Skip to content

Commit

Permalink
#40 Add basic_string + basic_string_view concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
rick-de-water committed Jan 6, 2020
1 parent ab81b81 commit 85f9406
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 29 deletions.
93 changes: 65 additions & 28 deletions src/lib/lingo/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,43 +341,35 @@ namespace lingo
}

// Allocate memory
const size_type current_size = size();
const size_type new_size = current_size + result.size;
_storage.grow(new_size);

// Destruct old null terminator
_storage.destruct(_storage.data() + current_size, 1);
_storage.grow(size() + result.size);

// Fill memory
_storage.copy_construct(_storage.data() + current_size, encoded_point, result.size);

// Construct new null terminator
_storage.copy_construct(_storage.data() + new_size, &null_terminator, 1);

// Update size
_storage.set_size(new_size);
// Append data
append(string_view(encoded_point, result.size));
}

template <typename OtherAllocator>
basic_string& operator += (const basic_string<Encoding, Page, OtherAllocator> & other)
basic_string& operator += (const basic_string<Encoding, Page, OtherAllocator>& other)
{
// We can't simply call the string_view version here
// If &other == this, the data pointer in the string view might become invalid when growing the capacity

// Allocate memory
const size_type current_size = size();
const size_type added_size = other.size();
const size_type new_size = current_size + added_size;
_storage.grow(new_size);
_storage.grow(size() + other.size());

// Destruct old null terminator
_storage.destruct(_storage.data() + current_size, 1);
// Append data
append(other);

// Fill memory
_storage.copy_construct(_storage.data() + current_size, other.data(), added_size);
// Return this
return *this;
}

// Construct new null terminator
_storage.copy_construct(_storage.data() + new_size, &null_terminator, 1);
basic_string& operator += (string_view other)
{
// Allocate memory
_storage.grow(size() + other.size());

// Update size
_storage.set_size(new_size);
// Append data
append(other);

// Return this
return *this;
Expand Down Expand Up @@ -423,6 +415,27 @@ namespace lingo
}

private:
void append(string_view other)
{
const size_type current_size = size();
const size_type added_size = other.size();
const size_type new_size = current_size + added_size;

assert(new_size <= capacity());

// Destruct old null terminator
_storage.destruct(_storage.data() + current_size, 1);

// Fill memory
_storage.copy_construct(_storage.data() + current_size, other.data(), added_size);

// Construct new null terminator
_storage.copy_construct(_storage.data() + new_size, &null_terminator, 1);

// Update size
_storage.set_size(new_size);
}

storage_type _storage;
};

Expand All @@ -434,7 +447,31 @@ namespace lingo
template <typename Encoding, typename Page, typename LeftAllocator, typename RightAllocator, typename ResultAllocator = LeftAllocator>
basic_string<Encoding, Page, ResultAllocator> operator + (basic_string<Encoding, Page, LeftAllocator> left, basic_string<Encoding, Page, RightAllocator> right)
{
basic_string<Encoding, Page, ResultAllocator> result;
return operator+<Encoding, Page, ResultAllocator>(
left.operator lingo::basic_string_view<Encoding, Page>(),
right.operator lingo::basic_string_view<Encoding, Page>());
}

template <typename Encoding, typename Page, typename LeftAllocator, typename ResultAllocator = LeftAllocator>
basic_string<Encoding, Page, ResultAllocator> operator + (basic_string<Encoding, Page, LeftAllocator> left, basic_string_view<Encoding, Page> right)
{
return operator+<Encoding, Page, ResultAllocator>(
left.operator lingo::basic_string_view<Encoding, Page>(),
right);
}

template <typename Encoding, typename Page, typename RightAllocator, typename ResultAllocator = RightAllocator>
basic_string<Encoding, Page, ResultAllocator> operator + (basic_string_view<Encoding, Page> left, basic_string<Encoding, Page, RightAllocator> right)
{
return operator+<Encoding, Page, ResultAllocator>(
left,
right.operator lingo::basic_string_view<Encoding, Page>());
}

template <typename Encoding, typename Page, typename Allocator = internal::default_allocator<Encoding>>
basic_string<Encoding, Page, Allocator> operator + (basic_string_view<Encoding, Page> left, basic_string_view<Encoding, Page> right)
{
basic_string<Encoding, Page, Allocator> result;
result.reserve(left.size() + right.size());
result += left;
result += right;
Expand Down
43 changes: 42 additions & 1 deletion tests/lingo/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ LINGO_UNIT_TEST_CASE("A string can be concatenated to another string")

REQUIRE_FALSE(std::is_same<string_type, different_allocator_string_type>::value);

string_view_type source_string = lingo::test::test_string<unit_type>::value;
const string_view_type source_string = lingo::test::test_string<unit_type>::value;
string_type test_string = source_string;
different_allocator_string_type different_allocator_test_string = lingo::test::test_string<unit_type>::value;

Expand Down Expand Up @@ -610,4 +610,45 @@ LINGO_UNIT_TEST_CASE("A string can be concatenated to another string")
REQUIRE(string_view_type(different_allocator_test_string.data(), source_string.size()) == source_string);
REQUIRE(string_view_type(different_allocator_test_string.data() + source_string.size(), source_string.size()) == source_string);
}
}

LINGO_UNIT_TEST_CASE("A string_view can be concatenated to a string")
{
LINGO_UNIT_TEST_TYPEDEFS;

const string_view_type source_string = lingo::test::test_string<unit_type>::value;
string_type test_string;

test_string = test_string + source_string;
REQUIRE(test_string == source_string);

for (size_type i = 0; i < 10; ++i)
{
test_string += source_string;
REQUIRE(test_string.size() == source_string.size() * (i + 2));

for (size_type j = 0; j < i + 2; ++j)
{
REQUIRE(string_view_type(test_string.data() + source_string.size() * j, source_string.size()) == source_string);
}
}
}

LINGO_UNIT_TEST_CASE("A string_view can be concatenated to a string_view")
{
LINGO_UNIT_TEST_TYPEDEFS;

const string_view_type source_string = lingo::test::test_string<unit_type>::value;
string_type test_string;

test_string = source_string + source_string;
REQUIRE(test_string.size() == source_string.size() * 2);
REQUIRE(string_view_type(test_string.data(), source_string.size()) == source_string);
REQUIRE(string_view_type(test_string.data() + source_string.size(), source_string.size()) == source_string);

for (size_type i = 0; i < 10; ++i)
{
test_string += source_string;
REQUIRE(test_string.size() == source_string.size() * (i + 3));
}
}

0 comments on commit 85f9406

Please sign in to comment.