Skip to content

Commit

Permalink
Add copy function to string and string_view
Browse files Browse the repository at this point in the history
  • Loading branch information
rick-de-water committed Jan 24, 2020
1 parent 276e399 commit bcc444d
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 17 deletions.
23 changes: 17 additions & 6 deletions src/lib/lingo/encoding/point_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,34 @@ namespace lingo
LINGO_CONSTEXPR14 point_iterator() noexcept:
_current(nullptr),
_end(nullptr),
_last(nullptr),
_code_point(0)
{
}

template <typename Page, typename Allocator>
point_iterator(const basic_string<encoding_type, Page, Allocator>& string):
_current(string.data()),
_end(string.data() + string.size()),
point_iterator(const basic_string<encoding_type, Page, Allocator>& str):
_current(str.data()),
_end(str.data() + str.size()),
_last(str.data()),
_code_point(parse())
{
}

template <typename Page>
LINGO_CONSTEXPR14 point_iterator(basic_string_view<encoding_type, Page> string):
_current(string.data()),
_end(string.data() + string.size()),
LINGO_CONSTEXPR14 point_iterator(basic_string_view<encoding_type, Page> str):
_current(str.data()),
_end(str.data() + str.size()),
_last(str.data()),
_code_point(parse())
{
}

LINGO_CONSTEXPR14 const unit_type* read_ptr() const noexcept
{
return _last;
}

LINGO_CONSTEXPR14 const_reference operator * () const noexcept
{
return _code_point;
Expand Down Expand Up @@ -99,6 +107,7 @@ namespace lingo
{
_current = nullptr;
_end = nullptr;
_last = nullptr;
return {};
}

Expand All @@ -111,6 +120,7 @@ namespace lingo
}

// Move the current pointer
_last = _current;
_current += result.size;
assert(_current <= _end); // _current should never go beyond _end

Expand All @@ -120,6 +130,7 @@ namespace lingo

const unit_type* _current;
const unit_type* _end;
const unit_type* _last;
point_type _code_point;
};

Expand Down
36 changes: 29 additions & 7 deletions src/lib/lingo/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <lingo/platform/endian.hpp>

#include <lingo/utility/object_builder.hpp>
#include <lingo/utility/pointer_iterator.hpp>
#include <lingo/utility/type_traits.hpp>

Expand Down Expand Up @@ -70,8 +71,6 @@ namespace lingo
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;

using object_builder = utility::object_builder<value_type>;

static LINGO_CONSTEXPR11 size_type npos = static_cast<size_type>(-1);
static LINGO_CONSTEXPR11 unit_type null_terminator = unit_type{};
static LINGO_CONSTEXPR11 bool is_execution_set = lingo::utility::is_execution_set<encoding_type, page_type>::value;
Expand All @@ -80,6 +79,7 @@ namespace lingo
static_assert(std::is_same<typename page_type::point_type, typename encoding_type::point_type>::value, "page_type::point_type must be the same type as encoding_type::point_type");
static_assert(std::is_same<typename allocator_type::value_type, typename encoding_type::unit_type>::value, "allocator_type::value_type must be the same type as encoding_type::unit_type");

using object_builder = utility::object_builder<value_type>;
using storage_type = basic_string_storage<value_type, allocator_type>;
using string_view = basic_string_view<encoding_type, page_type>;

Expand All @@ -106,12 +106,24 @@ namespace lingo
{
}

template <typename _ = int, typename std::enable_if<is_execution_set, _>::type = 0>
basic_string(const_pointer cstring, size_type count, const allocator_type& allocator = allocator_type()):
basic_string(string_view(cstring, count), allocator)
{
}

template <typename _ = int, typename std::enable_if<!is_execution_set, _>::type = 0>
explicit basic_string(const_pointer cstring, const allocator_type& allocator = allocator_type()):
basic_string(string_view(cstring), allocator)
{
}

template <typename _ = int, typename std::enable_if<!is_execution_set, _>::type = 0>
explicit basic_string(const_pointer cstring, size_type count, const allocator_type& allocator = allocator_type()):
basic_string(string_view(cstring, count), allocator)
{
}

basic_string(string_view string_view, const allocator_type& allocator = allocator_type()):
basic_string(allocator)
{
Expand Down Expand Up @@ -657,11 +669,16 @@ namespace lingo
_storage.set_size(new_size);
}

basic_string substr(size_type pos = 0, size_type count = npos)
basic_string substr(size_type pos = 0, size_type count = npos) const
{
return basic_string(*this, pos, count);
}

size_type copy(value_type* dest, size_type count, size_type pos = 0) const
{
return view().copy(dest, count, pos);
}

template <typename OtherAllocator>
basic_string& operator += (const basic_string<Encoding, Page, OtherAllocator>& other)
{
Expand Down Expand Up @@ -715,7 +732,7 @@ namespace lingo

operator string_view() const noexcept
{
return string_view(data(), size(), true);
return view();
}

const_pointer c_str() const noexcept
Expand All @@ -729,15 +746,20 @@ namespace lingo
return std::basic_string<value_type, Traits, StdAllocator>(data(), size());
}

string_view view() const noexcept
{
return string_view(data(), size(), true);
}

template <typename RightAllocator>
LINGO_CONSTEXPR14 int compare(const basic_string<encoding_type, page_type, RightAllocator>& other) const noexcept(noexcept(std::declval<const basic_string&>().compare(other.operator lingo::basic_string_view<Encoding, Page>())))
LINGO_CONSTEXPR14 int compare(const basic_string<encoding_type, page_type, RightAllocator>& other) const noexcept(noexcept(std::declval<const basic_string&>().compare(other.view())))
{
return compare(other.operator lingo::basic_string_view<encoding_type, page_type>());
return compare(other.view());
}

LINGO_CONSTEXPR14 int compare(basic_string_view<encoding_type, page_type> other) const
{
return operator lingo::basic_string_view<Encoding, page_type>().compare(other);
return view().compare(other);
}

template <typename _ = int,
Expand Down
3 changes: 1 addition & 2 deletions src/lib/lingo/string_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,11 @@ namespace lingo
using size_type = typename allocator_type::size_type;
using difference_type = typename allocator_type::difference_type;

using object_builder = utility::object_builder<value_type>;

static_assert(std::is_same<unit_type, typename allocator_type::value_type>::value, "allocator_type::value_type must be the same type as basic_string_storage::unit_type");

private:
using compressed_pair = utility::compressed_pair<internal::basic_string_storage_data<unit_type>, allocator_type>;
using object_builder = utility::object_builder<value_type>;

struct allocation
{
Expand Down
16 changes: 15 additions & 1 deletion src/lib/lingo/string_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <lingo/encoding/utf16.hpp>
#include <lingo/encoding/utf32.hpp>

#include <lingo/utility/object_builder.hpp>
#include <lingo/utility/pointer_iterator.hpp>
#include <lingo/utility/type_traits.hpp>

Expand Down Expand Up @@ -62,6 +63,7 @@ namespace lingo
private:
static_assert(std::is_same<typename page_type::point_type, typename encoding_type::point_type>::value, "page_type::point_type must be the same type as encoding_type::point_type");

using object_builder = utility::object_builder<value_type>;
using point_iterator = encoding::point_iterator<encoding_type>;
using storage_type = basic_string_view_storage<value_type>;

Expand Down Expand Up @@ -211,8 +213,13 @@ namespace lingo
}
#endif

basic_string_view substr(size_type pos = 0, size_type count = npos)
basic_string_view substr(size_type pos = 0, size_type count = npos) const
{
if (pos > size())
{
throw std::out_of_range("pos > size()");
}

const const_pointer d = data() + pos;
const size_type s = std::min(count, size() - pos);
const bool nt = null_terminated() && (s == size() - pos);
Expand Down Expand Up @@ -250,6 +257,13 @@ namespace lingo
}
}

LINGO_CONSTEXPR14 size_type copy(value_type* dest, size_type count, size_type pos = 0) const
{
const basic_string_view str = substr(pos, count);
object_builder::copy_construct(dest, str.data(), str.size());
return str.size();
}

LINGO_CONSTEXPR14 void swap(basic_string_view& other) noexcept
{
_storage.swap(other._storage);
Expand Down
10 changes: 9 additions & 1 deletion src/lib/lingo/utility/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace lingo

template <typename Iterator, typename Catagory>
struct is_catagory_iterator<Iterator, Catagory,
typename std::enable_if<std::is_same<typename std::iterator_traits<Iterator>::iterator_catagory, Catagory>::value>::type> : std::true_type
typename std::enable_if<std::is_base_of<Catagory, typename std::iterator_traits<Iterator>::iterator_catagory>::value>::type> : std::true_type
{
};

Expand All @@ -78,6 +78,10 @@ namespace lingo
using is_bidirectional_iterator = is_catagory_iterator<Iterator, std::bidirectional_iterator_tag>;
template <typename Iterator>
using is_random_access_iterator = is_catagory_iterator<Iterator, std::random_access_iterator_tag>;
#ifdef __cpp_lib_ranges
template <typename Iterator>
using is_contiguous_iterator = is_catagory_iterator<Iterator, std::contiguous_iterator_tag>;
#endif

#ifdef __cpp_variable_templates
template <typename Iterator>
Expand All @@ -90,6 +94,10 @@ namespace lingo
LINGO_CONSTEXPR14 bool is_bidirectional_iterator_v = is_bidirectional_iterator<Iterator>::value;
template <typename Iterator>
LINGO_CONSTEXPR14 bool is_random_access_iterator_v = is_random_access_iterator<Iterator>::value;
#ifdef __cpp_lib_ranges
template <typename Iterator>
LINGO_CONSTEXPR14 bool is_contiguous_iterator_v = is_contiguous_iterator<Iterator>::value;
#endif
#endif
}
}
Expand Down
27 changes: 27 additions & 0 deletions tests/lingo/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,4 +671,31 @@ LINGO_UNIT_TEST_CASE("A cstring can be concatenated to a string_view")

REQUIRE(string_view_type(suffix_test_string_result.data(), source_string.size()) == source_string);
REQUIRE(string_view_type(suffix_test_string_result.data() + source_string.size(), source_string.size()) == source_string);
}

LINGO_UNIT_TEST_CASE("string can be copied to an array")
{
LINGO_UNIT_TEST_TYPEDEFS;

const unit_type* data = lingo::test::test_string<unit_type>::value;
const size_type size = sizeof(lingo::test::test_string<unit_type>::value) / sizeof(lingo::test::test_string<unit_type>::value[0]) - 1;
const string_type source(data, size);

for (auto pos_it = point_iterator_type(source); pos_it != point_iterator_type(); ++pos_it)
{
const size_type pos = pos_it.read_ptr() - source.data();

for (auto size_it = pos_it; size_it != point_iterator_type(); ++size_it)
{
const size_type buffer_size = (size_it.read_ptr() - source.data()) - pos;
auto buffer = std::make_unique<unit_type[]>(buffer_size);

const size_type copied_count = source.copy(buffer.get(), buffer_size, pos);

REQUIRE(copied_count == buffer_size);
REQUIRE(string_view_type(buffer.get(), buffer_size, false) == source.substr(pos, buffer_size));
}
}

REQUIRE_THROWS_AS(source.copy(nullptr, 0, size + 1), std::out_of_range);
}
27 changes: 27 additions & 0 deletions tests/lingo/string_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,30 @@ LINGO_UNIT_TEST_CASE("string_view can be swapped")
REQUIRE(test_string_view1 == test_string_view4);
REQUIRE(test_string_view2 == test_string_view3);
}

LINGO_UNIT_TEST_CASE("string_view can be copied to an array")
{
LINGO_UNIT_TEST_TYPEDEFS;

const unit_type* data = lingo::test::test_string<unit_type>::value;
const size_type size = sizeof(lingo::test::test_string<unit_type>::value) / sizeof(lingo::test::test_string<unit_type>::value[0]) - 1;
const string_view_type source(data, size, true);

for (auto pos_it = point_iterator_type(source); pos_it != point_iterator_type(); ++pos_it)
{
const size_type pos = pos_it.read_ptr() - source.data();

for (auto size_it = pos_it; size_it != point_iterator_type(); ++size_it)
{
const size_type buffer_size = (size_it.read_ptr() - source.data()) - pos;
auto buffer = std::make_unique<unit_type[]>(buffer_size);

const size_type copied_count = source.copy(buffer.get(), buffer_size, pos);

REQUIRE(copied_count == buffer_size);
REQUIRE(string_view_type(buffer.get(), buffer_size, false) == source.substr(pos, buffer_size));
}
}

REQUIRE_THROWS_AS(source.copy(nullptr, 0, size + 1), std::out_of_range);
}

0 comments on commit bcc444d

Please sign in to comment.