Made simple_string_view take a char type

This allows (most usefully) a `ustring_view` for viewing unsigned char
strings.
This commit is contained in:
Jason Rhinelander 2020-04-02 21:09:13 -03:00
parent bc49b5e9a0
commit af42875e97
2 changed files with 134 additions and 56 deletions

View File

@ -75,6 +75,13 @@ inline std::string to_hex(string_view s) {
return hex;
}
inline std::string to_hex(ustring_view s) {
std::string hex;
hex.reserve(s.size() * 2);
to_hex(s.begin(), s.end(), std::back_inserter(hex));
return hex;
}
/// Returns true if all elements in the range are hex characters
template <typename It>
constexpr bool is_hex(It begin, It end) {
@ -87,6 +94,7 @@ constexpr bool is_hex(It begin, It end) {
/// Returns true if all elements in the string-like value are hex characters
constexpr bool is_hex(string_view s) { return is_hex(s.begin(), s.end()); }
constexpr bool is_hex(ustring_view s) { return is_hex(s.begin(), s.end()); }
/// Convert a hex digit into its numeric (0-15) value
constexpr char from_hex_digit(unsigned char x) noexcept {
@ -119,4 +127,11 @@ inline std::string from_hex(string_view s) {
return bytes;
}
inline std::string from_hex(ustring_view s) {
std::string bytes;
bytes.reserve(s.size() / 2);
from_hex(s.begin(), s.end(), std::back_inserter(bytes));
return bytes;
}
}

View File

@ -33,7 +33,10 @@
#ifdef __cpp_lib_string_view
#include <string_view>
namespace lokimq { using string_view = std::string_view; }
namespace lokimq {
using string_view = std::string_view;
using ustring_view = std::basic_string_view<unsigned char>;
}
#else
@ -43,16 +46,17 @@ namespace lokimq { using string_view = std::string_view; }
namespace lokimq {
/// Basic implementation of std::string_view (except for std::hash support).
template <typename CharT>
class simple_string_view {
const char *data_;
const CharT *data_;
size_t size_;
public:
using traits_type = std::char_traits<char>;
using value_type = char;
using pointer = char*;
using const_pointer = const char*;
using reference = char&;
using const_reference = const char&;
using traits_type = std::char_traits<CharT>;
using value_type = CharT;
using pointer = CharT*;
using const_pointer = const CharT*;
using reference = CharT&;
using const_reference = const CharT&;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
@ -64,27 +68,27 @@ public:
constexpr simple_string_view() noexcept : data_{nullptr}, size_{0} {}
constexpr simple_string_view(const simple_string_view&) noexcept = default;
simple_string_view(const std::string& str) : data_{str.data()}, size_{str.size()} {}
constexpr simple_string_view(const char* data, size_t size) noexcept : data_{data}, size_{size} {}
simple_string_view(const char* data) : data_{data}, size_{traits_type::length(data)} {}
simple_string_view(const std::basic_string<CharT>& str) : data_{str.data()}, size_{str.size()} {}
constexpr simple_string_view(const CharT* data, size_t size) noexcept : data_{data}, size_{size} {}
simple_string_view(const CharT* data) : data_{data}, size_{traits_type::length(data)} {}
simple_string_view& operator=(const simple_string_view&) = default;
constexpr const char* data() const noexcept { return data_; }
constexpr const CharT* data() const noexcept { return data_; }
constexpr size_t size() const noexcept { return size_; }
constexpr size_t length() const noexcept { return size_; }
constexpr size_t max_size() const noexcept { return std::numeric_limits<size_t>::max(); }
constexpr bool empty() const noexcept { return size_ == 0; }
explicit operator std::string() const { return {data_, size_}; }
constexpr const char* begin() const noexcept { return data_; }
constexpr const char* cbegin() const noexcept { return data_; }
constexpr const char* end() const noexcept { return data_ + size_; }
constexpr const char* cend() const noexcept { return data_ + size_; }
explicit operator std::basic_string<CharT>() const { return {data_, size_}; }
constexpr const CharT* begin() const noexcept { return data_; }
constexpr const CharT* cbegin() const noexcept { return data_; }
constexpr const CharT* end() const noexcept { return data_ + size_; }
constexpr const CharT* cend() const noexcept { return data_ + size_; }
reverse_iterator rbegin() const { return reverse_iterator{end()}; }
reverse_iterator crbegin() const { return reverse_iterator{end()}; }
reverse_iterator rend() const { return reverse_iterator{begin()}; }
reverse_iterator crend() const { return reverse_iterator{begin()}; }
constexpr const char& operator[](size_t pos) const { return data_[pos]; }
constexpr const char& front() const { return *data_; }
constexpr const char& back() const { return data_[size_ - 1]; }
constexpr const CharT& operator[](size_t pos) const { return data_[pos]; }
constexpr const CharT& front() const { return *data_; }
constexpr const CharT& back() const { return data_[size_ - 1]; }
int compare(simple_string_view s) const;
constexpr void remove_prefix(size_t n) { data_ += n; size_ -= n; }
constexpr void remove_suffix(size_t n) { size_ -= n; }
@ -93,13 +97,13 @@ public:
#if defined(__clang__) || !defined(__GNUG__) || __GNUC__ >= 6
constexpr // GCC 5.x is buggy wrt constexpr throwing
#endif
const char& at(size_t pos) const {
const CharT& at(size_t pos) const {
if (pos >= size())
throw std::out_of_range{"invalid string_view index"};
return data_[pos];
};
size_t copy(char* dest, size_t count, size_t pos = 0) const {
size_t copy(CharT* dest, size_t count, size_t pos = 0) const {
if (pos > size()) throw std::out_of_range{"invalid copy pos"};
size_t rcount = std::min(count, size_ - pos);
traits_type::copy(dest, data_ + pos, rcount);
@ -125,9 +129,9 @@ public:
}
return npos;
}
size_t find(char c, size_t pos = 0) const { return find({&c, 1}, pos); }
size_t find(const char* c, size_t pos, size_t count) const { return find({c, count}, pos); }
size_t find(const char* c, size_t pos = 0) const { return find(simple_string_view(c), pos); }
size_t find(CharT c, size_t pos = 0) const { return find({&c, 1}, pos); }
size_t find(const CharT* c, size_t pos, size_t count) const { return find({c, count}, pos); }
size_t find(const CharT* c, size_t pos = 0) const { return find(simple_string_view(c), pos); }
size_t rfind(simple_string_view v, size_t pos = npos) const {
if (v.size_ > size_) return npos;
@ -138,38 +142,38 @@ public:
}
return npos;
}
size_t rfind(char c, size_t pos = npos) const { return rfind({&c, 1}, pos); }
size_t rfind(const char* c, size_t pos, size_t count) const { return rfind({c, count}, pos); }
size_t rfind(const char* c, size_t pos = npos) const { return rfind(simple_string_view(c), pos); }
size_t rfind(CharT c, size_t pos = npos) const { return rfind({&c, 1}, pos); }
size_t rfind(const CharT* c, size_t pos, size_t count) const { return rfind({c, count}, pos); }
size_t rfind(const CharT* c, size_t pos = npos) const { return rfind(simple_string_view(c), pos); }
constexpr size_t find_first_of(simple_string_view v, size_t pos = 0) const noexcept {
for (; pos < size_; ++pos)
for (char c : v)
for (CharT c : v)
if (data_[pos] == c)
return pos;
return npos;
}
constexpr size_t find_first_of(char c, size_t pos = 0) const noexcept { return find_first_of({&c, 1}, pos); }
constexpr size_t find_first_of(const char* c, size_t pos, size_t count) const { return find_first_of({c, count}, pos); }
size_t find_first_of(const char* c, size_t pos = 0) const { return find_first_of(simple_string_view(c), pos); }
constexpr size_t find_first_of(CharT c, size_t pos = 0) const noexcept { return find_first_of({&c, 1}, pos); }
constexpr size_t find_first_of(const CharT* c, size_t pos, size_t count) const { return find_first_of({c, count}, pos); }
size_t find_first_of(const CharT* c, size_t pos = 0) const { return find_first_of(simple_string_view(c), pos); }
constexpr size_t find_last_of(simple_string_view v, const size_t pos = npos) const noexcept {
if (size_ == 0) return npos;
const size_t last_pos = std::min(pos, size_-1);
for (size_t i = last_pos; i <= last_pos; --i)
for (char c : v)
for (CharT c : v)
if (data_[i] == c)
return i;
return npos;
}
constexpr size_t find_last_of(char c, size_t pos = npos) const noexcept { return find_last_of({&c, 1}, pos); }
constexpr size_t find_last_of(const char* c, size_t pos, size_t count) const { return find_last_of({c, count}, pos); }
size_t find_last_of(const char* c, size_t pos = npos) const { return find_last_of(simple_string_view(c), pos); }
constexpr size_t find_last_of(CharT c, size_t pos = npos) const noexcept { return find_last_of({&c, 1}, pos); }
constexpr size_t find_last_of(const CharT* c, size_t pos, size_t count) const { return find_last_of({c, count}, pos); }
size_t find_last_of(const CharT* c, size_t pos = npos) const { return find_last_of(simple_string_view(c), pos); }
constexpr size_t find_first_not_of(simple_string_view v, size_t pos = 0) const noexcept {
for (; pos < size_; ++pos) {
bool none = true;
for (char c : v) {
for (CharT c : v) {
if (data_[pos] == c) {
none = false;
break;
@ -179,16 +183,16 @@ public:
}
return npos;
}
constexpr size_t find_first_not_of(char c, size_t pos = 0) const noexcept { return find_first_not_of({&c, 1}, pos); }
constexpr size_t find_first_not_of(const char* c, size_t pos, size_t count) const { return find_first_not_of({c, count}, pos); }
size_t find_first_not_of(const char* c, size_t pos = 0) const { return find_first_not_of(simple_string_view(c), pos); }
constexpr size_t find_first_not_of(CharT c, size_t pos = 0) const noexcept { return find_first_not_of({&c, 1}, pos); }
constexpr size_t find_first_not_of(const CharT* c, size_t pos, size_t count) const { return find_first_not_of({c, count}, pos); }
size_t find_first_not_of(const CharT* c, size_t pos = 0) const { return find_first_not_of(simple_string_view(c), pos); }
constexpr size_t find_last_not_of(simple_string_view v, const size_t pos = npos) const noexcept {
if (size_ == 0) return npos;
const size_t last_pos = std::min(pos, size_-1);
for (size_t i = last_pos; i <= last_pos; --i) {
bool none = true;
for (char c : v) {
for (CharT c : v) {
if (data_[i] == c) {
none = false;
break;
@ -198,47 +202,106 @@ public:
}
return npos;
}
constexpr size_t find_last_not_of(char c, size_t pos = npos) const noexcept { return find_last_not_of({&c, 1}, pos); }
constexpr size_t find_last_not_of(const char* c, size_t pos, size_t count) const { return find_last_not_of({c, count}, pos); }
size_t find_last_not_of(const char* c, size_t pos = npos) const { return find_last_not_of(simple_string_view(c), pos); }
constexpr size_t find_last_not_of(CharT c, size_t pos = npos) const noexcept { return find_last_not_of({&c, 1}, pos); }
constexpr size_t find_last_not_of(const CharT* c, size_t pos, size_t count) const { return find_last_not_of({c, count}, pos); }
size_t find_last_not_of(const CharT* c, size_t pos = npos) const { return find_last_not_of(simple_string_view(c), pos); }
};
inline bool operator==(simple_string_view lhs, simple_string_view rhs) {
return lhs.size() == rhs.size() && 0 == std::char_traits<char>::compare(lhs.data(), rhs.data(), lhs.size());
/// We have three of each of these: one with two string views, one with RHS argument deduction, and
/// one with LHS argument deduction, so that you can do (sv == sv), (sv == "foo"), and ("foo" == sv)
template <typename CharT>
inline bool operator==(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return lhs.size() == rhs.size() && 0 == std::char_traits<CharT>::compare(lhs.data(), rhs.data(), lhs.size());
};
inline bool operator!=(simple_string_view lhs, simple_string_view rhs) {
template <typename CharT>
inline bool operator==(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return lhs.size() == rhs.size() && 0 == std::char_traits<CharT>::compare(lhs.data(), rhs.data(), lhs.size());
};
template <typename CharT>
inline bool operator==(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return lhs.size() == rhs.size() && 0 == std::char_traits<CharT>::compare(lhs.data(), rhs.data(), lhs.size());
};
template <typename CharT>
inline bool operator!=(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return !(lhs == rhs);
}
inline int simple_string_view::compare(simple_string_view s) const {
int cmp = std::char_traits<char>::compare(data_, s.data(), std::min(size_, s.size()));
template <typename CharT>
inline bool operator!=(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return !(lhs == rhs);
}
template <typename CharT>
inline bool operator!=(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return !(lhs == rhs);
}
template <typename CharT>
inline int simple_string_view<CharT>::compare(simple_string_view s) const {
int cmp = std::char_traits<CharT>::compare(data_, s.data(), std::min(size_, s.size()));
if (cmp) return cmp;
if (size_ < s.size()) return -1;
else if (size_ > s.size()) return 1;
return 0;
}
inline bool operator<(simple_string_view lhs, simple_string_view rhs) {
template <typename CharT>
inline bool operator<(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) < 0;
};
inline bool operator<=(simple_string_view lhs, simple_string_view rhs) {
template <typename CharT>
inline bool operator<(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return lhs.compare(rhs) < 0;
};
template <typename CharT>
inline bool operator<(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) < 0;
};
template <typename CharT>
inline bool operator<=(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) <= 0;
};
inline bool operator>(simple_string_view lhs, simple_string_view rhs) {
template <typename CharT>
inline bool operator<=(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return lhs.compare(rhs) <= 0;
};
template <typename CharT>
inline bool operator<=(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) <= 0;
};
template <typename CharT>
inline bool operator>(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) > 0;
};
inline bool operator>=(simple_string_view lhs, simple_string_view rhs) {
template <typename CharT>
inline bool operator>(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return lhs.compare(rhs) > 0;
};
template <typename CharT>
inline bool operator>(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) > 0;
};
template <typename CharT>
inline bool operator>=(simple_string_view<CharT> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) >= 0;
};
inline std::ostream& operator<<(std::ostream& os, const simple_string_view& s) {
template <typename CharT>
inline bool operator>=(simple_string_view<CharT> lhs, std::common_type_t<simple_string_view<CharT>> rhs) {
return lhs.compare(rhs) >= 0;
};
template <typename CharT>
inline bool operator>=(std::common_type_t<simple_string_view<CharT>> lhs, simple_string_view<CharT> rhs) {
return lhs.compare(rhs) >= 0;
};
template <typename CharT>
inline std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const simple_string_view<CharT>& s) {
os.write(s.data(), s.size());
return os;
}
using string_view = simple_string_view;
using string_view = simple_string_view<char>;
using ustring_view = simple_string_view<unsigned char>;
}
#endif
// Add a "foo"_sv literal that works exactly like the C++17 "foo"sv literal, but works with out
// Add a "foo"_sv literal that works exactly like the C++17 "foo"sv literal, but works with our
// implementation in pre-C++17.
namespace lokimq {
inline namespace literals {