Add more constexpr to StringRef

This commit is contained in:
Martin Hořeňovský 2020-02-13 15:01:03 +01:00
parent 63b7d6f98e
commit 2945b80f61
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
10 changed files with 154 additions and 41 deletions

View File

@ -22,17 +22,7 @@ namespace Catch {
CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance"); CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance");
return m_start; return m_start;
} }
auto StringRef::data() const noexcept -> char const* {
return m_start;
}
auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
if (start < m_size) {
return StringRef(m_start + start, (std::min)(m_size - start, size));
} else {
return StringRef();
}
}
auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
return m_size == other.m_size return m_size == other.m_size
&& (std::memcmp( m_start, other.m_start, m_size ) == 0); && (std::memcmp( m_start, other.m_start, m_size ) == 0);

View File

@ -74,12 +74,21 @@ namespace Catch {
public: // substrings and searches public: // substrings and searches
// Returns a substring of [start, start + length). // Returns a substring of [start, start + length).
// If start + length > size(), then the substring is [start, size()). // If start + length > size(), then the substring is [start, start + size()).
// If start > size(), then the substring is empty. // If start > size(), then the substring is empty.
auto substr( size_type start, size_type length ) const noexcept -> StringRef; constexpr StringRef substr(size_type start, size_type length) const noexcept {
if (start < m_size) {
const auto shortened_size = m_size - start;
return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
} else {
return StringRef();
}
}
// Returns the current start pointer. May not be null-terminated. // Returns the current start pointer. May not be null-terminated.
auto data() const noexcept -> char const*; constexpr char const* data() const noexcept {
return m_start;
}
constexpr auto isNullTerminated() const noexcept -> bool { constexpr auto isNullTerminated() const noexcept -> bool {
return m_start[m_size] == '\0'; return m_start[m_size] == '\0';

View File

@ -1193,6 +1193,7 @@ String.tests.cpp:<line number>: passed: s.data() == s2.data() for: "hello world!
String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!" String.tests.cpp:<line number>: passed: s.data() == ss.data() for: "hello world!" == "hello world!"
String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true String.tests.cpp:<line number>: passed: s.substr(s.size() + 1, 123).empty() for: true
String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0 String.tests.cpp:<line number>: passed: std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
String.tests.cpp:<line number>: passed: s.substr(1'000'000, 1).empty() for: true
String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello" String.tests.cpp:<line number>: passed: (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
String.tests.cpp:<line number>: passed: left == right for: Hello == Hello String.tests.cpp:<line number>: passed: left == right for: Hello == Hello
String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel String.tests.cpp:<line number>: passed: left != left.substr(0, 3) for: Hello != Hel
@ -1206,11 +1207,20 @@ String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringre
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11 String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref" String.tests.cpp:<line number>: passed: stdStr == "a stringref" for: "a stringref" == "a stringref"
String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11 String.tests.cpp:<line number>: passed: stdStr.size() == sr.size() for: 11 == 11
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{}.size() == 0' String.tests.cpp:<line number>: passed: with 1 message: 'empty.size() == 0'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.size() == 3' String.tests.cpp:<line number>: passed: with 1 message: 'empty.begin() == empty.end()'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.size() == 3'
String.tests.cpp:<line number>: passed: with 1 message: 'StringRef{ "abc", 2 }.size() == 2' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.isNullTerminated()'
String.tests.cpp:<line number>: passed: with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())' String.tests.cpp:<line number>: passed: with 1 message: 'stringref.data() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.begin() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.begin() != stringref.end()'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.substr(10, 0).empty()'
String.tests.cpp:<line number>: passed: with 1 message: 'stringref.substr(2, 1).data() == abc + 2'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.size() == 2'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.data() == abc'
String.tests.cpp:<line number>: passed: with 1 message: 'shortened.begin() != shortened.end()'
String.tests.cpp:<line number>: passed: with 1 message: '!(shortened.isNullTerminated())'
String.tests.cpp:<line number>: passed: with 1 message: '!(shortened.substr(1, 3).isNullTerminated())'
String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())' String.tests.cpp:<line number>: passed: with 1 message: '!(sr1.empty())'
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3' String.tests.cpp:<line number>: passed: with 1 message: 'sr1.size() == 3'
String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()' String.tests.cpp:<line number>: passed: with 1 message: 'sr1.isNullTerminated()'

View File

@ -1381,5 +1381,5 @@ due to unexpected exception with message:
=============================================================================== ===============================================================================
test cases: 320 | 246 passed | 70 failed | 4 failed as expected test cases: 320 | 246 passed | 70 failed | 4 failed as expected
assertions: 1782 | 1630 passed | 131 failed | 21 failed as expected assertions: 1792 | 1640 passed | 131 failed | 21 failed as expected

View File

@ -8715,6 +8715,19 @@ String.tests.cpp:<line number>: PASSED:
with expansion: with expansion:
0 == 0 0 == 0
-------------------------------------------------------------------------------
StringRef
Substrings
substring start after the end is empty
-------------------------------------------------------------------------------
String.tests.cpp:<line number>
...............................................................................
String.tests.cpp:<line number>: PASSED:
REQUIRE( s.substr(1'000'000, 1).empty() )
with expansion:
true
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
StringRef StringRef
Comparisons are deep Comparisons are deep
@ -8836,23 +8849,59 @@ String.tests.cpp:<line number>
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{}.size() == 0 empty.size() == 0
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 3 }.size() == 3 empty.begin() == empty.end()
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 3 }.isNullTerminated() stringref.size() == 3
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
StringRef{ "abc", 2 }.size() == 2 stringref.isNullTerminated()
String.tests.cpp:<line number>: PASSED: String.tests.cpp:<line number>: PASSED:
with message: with message:
!(StringRef{ "abc", 2 }.isNullTerminated()) stringref.data() == abc
String.tests.cpp:<line number>: PASSED:
with message:
stringref.begin() == abc
String.tests.cpp:<line number>: PASSED:
with message:
stringref.begin() != stringref.end()
String.tests.cpp:<line number>: PASSED:
with message:
stringref.substr(10, 0).empty()
String.tests.cpp:<line number>: PASSED:
with message:
stringref.substr(2, 1).data() == abc + 2
String.tests.cpp:<line number>: PASSED:
with message:
shortened.size() == 2
String.tests.cpp:<line number>: PASSED:
with message:
shortened.data() == abc
String.tests.cpp:<line number>: PASSED:
with message:
shortened.begin() != shortened.end()
String.tests.cpp:<line number>: PASSED:
with message:
!(shortened.isNullTerminated())
String.tests.cpp:<line number>: PASSED:
with message:
!(shortened.substr(1, 3).isNullTerminated())
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
StringRef at compilation time StringRef at compilation time
@ -14005,5 +14054,5 @@ Misc.tests.cpp:<line number>: PASSED:
=============================================================================== ===============================================================================
test cases: 320 | 230 passed | 86 failed | 4 failed as expected test cases: 320 | 230 passed | 86 failed | 4 failed as expected
assertions: 1799 | 1630 passed | 148 failed | 21 failed as expected assertions: 1809 | 1640 passed | 148 failed | 21 failed as expected

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact <testsuitesloose text artifact
> >
<testsuite name="<exe-name>" errors="17" failures="132" tests="1800" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}"> <testsuite name="<exe-name>" errors="17" failures="132" tests="1810" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties> <properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/> <property name="filters" value="~[!nonportable]~[!benchmark]~[approvals] *"/>
<property name="random-seed" value="1"/> <property name="random-seed" value="1"/>
@ -1114,6 +1114,7 @@ Matchers.tests.cpp:<line number>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Pointer values of substring refs should also match" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Past the end substring" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Substrings/Substring off the end are trimmed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Substrings/substring start after the end is empty" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/Comparisons are deep" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/from std::string/implicitly constructed" time="{duration}"/>
<testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/> <testcase classname="<exe-name>.global" name="StringRef/from std::string/explicitly constructed" time="{duration}"/>

View File

@ -142,6 +142,7 @@
<testCase name="StringRef/Substrings/Pointer values of substring refs should also match" duration="{duration}"/> <testCase name="StringRef/Substrings/Pointer values of substring refs should also match" duration="{duration}"/>
<testCase name="StringRef/Substrings/Past the end substring" duration="{duration}"/> <testCase name="StringRef/Substrings/Past the end substring" duration="{duration}"/>
<testCase name="StringRef/Substrings/Substring off the end are trimmed" duration="{duration}"/> <testCase name="StringRef/Substrings/Substring off the end are trimmed" duration="{duration}"/>
<testCase name="StringRef/Substrings/substring start after the end is empty" duration="{duration}"/>
<testCase name="StringRef/Comparisons are deep" duration="{duration}"/> <testCase name="StringRef/Comparisons are deep" duration="{duration}"/>
<testCase name="StringRef/from std::string/implicitly constructed" duration="{duration}"/> <testCase name="StringRef/from std::string/implicitly constructed" duration="{duration}"/>
<testCase name="StringRef/from std::string/explicitly constructed" duration="{duration}"/> <testCase name="StringRef/from std::string/explicitly constructed" duration="{duration}"/>

View File

@ -2300,6 +2300,8 @@ ok {test-number} - s.substr(s.size() + 1, 123).empty() for: true
# StringRef # StringRef
ok {test-number} - std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0 ok {test-number} - std::strcmp(ss.c_str(), "world!") == 0 for: 0 == 0
# StringRef # StringRef
ok {test-number} - s.substr(1'000'000, 1).empty() for: true
# StringRef
ok {test-number} - (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello" ok {test-number} - (char*)buffer1 != (char*)buffer2 for: "Hello" != "Hello"
# StringRef # StringRef
ok {test-number} - left == right for: Hello == Hello ok {test-number} - left == right for: Hello == Hello
@ -2326,15 +2328,33 @@ ok {test-number} - stdStr == "a stringref" for: "a stringref" == "a stringref"
# StringRef # StringRef
ok {test-number} - stdStr.size() == sr.size() for: 11 == 11 ok {test-number} - stdStr.size() == sr.size() for: 11 == 11
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{}.size() == 0' ok {test-number} - with 1 message: 'empty.size() == 0'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 3 }.size() == 3' ok {test-number} - with 1 message: 'empty.begin() == empty.end()'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 3 }.isNullTerminated()' ok {test-number} - with 1 message: 'stringref.size() == 3'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: 'StringRef{ "abc", 2 }.size() == 2' ok {test-number} - with 1 message: 'stringref.isNullTerminated()'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: '!(StringRef{ "abc", 2 }.isNullTerminated())' ok {test-number} - with 1 message: 'stringref.data() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.begin() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.begin() != stringref.end()'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.substr(10, 0).empty()'
# StringRef at compilation time
ok {test-number} - with 1 message: 'stringref.substr(2, 1).data() == abc + 2'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.size() == 2'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.data() == abc'
# StringRef at compilation time
ok {test-number} - with 1 message: 'shortened.begin() != shortened.end()'
# StringRef at compilation time
ok {test-number} - with 1 message: '!(shortened.isNullTerminated())'
# StringRef at compilation time
ok {test-number} - with 1 message: '!(shortened.substr(1, 3).isNullTerminated())'
# StringRef at compilation time # StringRef at compilation time
ok {test-number} - with 1 message: '!(sr1.empty())' ok {test-number} - with 1 message: '!(sr1.empty())'
# StringRef at compilation time # StringRef at compilation time
@ -3590,5 +3610,5 @@ ok {test-number} - q3 == 23. for: 23.0 == 23.0
ok {test-number} - ok {test-number} -
# xmlentitycheck # xmlentitycheck
ok {test-number} - ok {test-number} -
1..1791 1..1801

View File

@ -10906,6 +10906,20 @@ Message from section two
</Section> </Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/> <OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section> </Section>
<Section name="Substrings" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="substring start after the end is empty" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original>
s.substr(1'000'000, 1).empty()
</Original>
<Expanded>
true
</Expanded>
</Expression>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<OverallResults successes="1" failures="0" expectedFailures="0"/>
</Section>
<Section name="Comparisons are deep" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="Comparisons are deep" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Original> <Original>
@ -11047,7 +11061,7 @@ Message from section two
</TestCase> </TestCase>
<TestCase name="StringRef at compilation time" tags="[constexpr][StringRef][Strings]" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <TestCase name="StringRef at compilation time" tags="[constexpr][StringRef][Strings]" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<Section name="Simple constructors" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="Simple constructors" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<OverallResults successes="5" failures="0" expectedFailures="0"/> <OverallResults successes="14" failures="0" expectedFailures="0"/>
</Section> </Section>
<Section name="UDL construction" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" > <Section name="UDL construction" filename="tests/<exe-name>/IntrospectiveTests/String.tests.cpp" >
<OverallResults successes="6" failures="0" expectedFailures="0"/> <OverallResults successes="6" failures="0" expectedFailures="0"/>
@ -16895,7 +16909,7 @@ loose text artifact
</Section> </Section>
<OverallResult success="true"/> <OverallResult success="true"/>
</TestCase> </TestCase>
<OverallResults successes="1630" failures="149" expectedFailures="21"/> <OverallResults successes="1640" failures="149" expectedFailures="21"/>
</Group> </Group>
<OverallResults successes="1630" failures="148" expectedFailures="21"/> <OverallResults successes="1640" failures="148" expectedFailures="21"/>
</Catch> </Catch>

View File

@ -72,7 +72,9 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
ss = s.substr(6, 123); ss = s.substr(6, 123);
REQUIRE(std::strcmp(ss.c_str(), "world!") == 0); REQUIRE(std::strcmp(ss.c_str(), "world!") == 0);
} }
// TODO: substring into string + size is longer than end SECTION("substring start after the end is empty") {
REQUIRE(s.substr(1'000'000, 1).empty());
}
} }
SECTION( "Comparisons are deep" ) { SECTION( "Comparisons are deep" ) {
@ -124,15 +126,32 @@ TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
} }
TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") { TEST_CASE("StringRef at compilation time", "[Strings][StringRef][constexpr]") {
//TODO:
// * substr
using Catch::StringRef; using Catch::StringRef;
SECTION("Simple constructors") { SECTION("Simple constructors") {
STATIC_REQUIRE(StringRef{}.size() == 0); constexpr StringRef empty;
STATIC_REQUIRE(empty.size() == 0);
STATIC_REQUIRE(empty.begin() == empty.end());
STATIC_REQUIRE(StringRef{ "abc", 3 }.size() == 3); constexpr char const* const abc = "abc";
STATIC_REQUIRE(StringRef{ "abc", 3 }.isNullTerminated());
STATIC_REQUIRE(StringRef{ "abc", 2 }.size() == 2); constexpr StringRef stringref(abc, 3);
STATIC_REQUIRE_FALSE(StringRef{ "abc", 2 }.isNullTerminated()); STATIC_REQUIRE(stringref.size() == 3);
STATIC_REQUIRE(stringref.isNullTerminated());
STATIC_REQUIRE(stringref.data() == abc);
STATIC_REQUIRE(stringref.begin() == abc);
STATIC_REQUIRE(stringref.begin() != stringref.end());
STATIC_REQUIRE(stringref.substr(10, 0).empty());
STATIC_REQUIRE(stringref.substr(2, 1).data() == abc + 2);
constexpr StringRef shortened(abc, 2);
STATIC_REQUIRE(shortened.size() == 2);
STATIC_REQUIRE(shortened.data() == abc);
STATIC_REQUIRE(shortened.begin() != shortened.end());
STATIC_REQUIRE_FALSE(shortened.isNullTerminated());
STATIC_REQUIRE_FALSE(shortened.substr(1, 3).isNullTerminated());
} }
SECTION("UDL construction") { SECTION("UDL construction") {
constexpr auto sr1 = "abc"_catch_sr; constexpr auto sr1 = "abc"_catch_sr;