aboutsummaryrefslogtreecommitdiffstats
path: root/bindings/cpp/include/serd/detail/StringView.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'bindings/cpp/include/serd/detail/StringView.hpp')
-rw-r--r--bindings/cpp/include/serd/detail/StringView.hpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/bindings/cpp/include/serd/detail/StringView.hpp b/bindings/cpp/include/serd/detail/StringView.hpp
new file mode 100644
index 00000000..54d8fb84
--- /dev/null
+++ b/bindings/cpp/include/serd/detail/StringView.hpp
@@ -0,0 +1,236 @@
+/*
+ Copyright 2019-2020 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_STRINGVIEW_HPP
+#define SERD_DETAIL_STRINGVIEW_HPP
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+
+namespace serd {
+namespace detail {
+
+/**
+ Immutable slice of a string.
+
+ This is a minimal implementation that is compatible with std::string_view
+ and std::string for most basic use cases. This could be replaced with
+ std::string_view once C++17 support can be relied on.
+*/
+class StringView
+{
+public:
+ using char_type = char;
+ using size_type = size_t;
+ using traits_type = std::char_traits<char>;
+ using value_type = char;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = const char*;
+ using const_iterator = const char*;
+
+ static constexpr size_type npos = size_t(-1);
+
+ constexpr StringView() noexcept = default;
+
+ constexpr StringView(const char* const str, const size_t len) noexcept
+ : _str{str}
+ , _len{len}
+ {}
+
+ // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
+ StringView(const char* const str) noexcept
+ : _str{str}
+ , _len{str ? strlen(str) : 0}
+ {}
+
+ // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
+ StringView(const std::string& str) noexcept
+ : _str{str.c_str()}
+ , _len{str.length()}
+ {}
+
+ constexpr size_t size() const { return _len; }
+ constexpr size_t length() const { return _len; }
+ constexpr bool empty() const { return _len == 0; }
+ constexpr const char* c_str() const { return _str; }
+ constexpr const char* data() const { return _str; }
+ constexpr const char& front() const { return _str[0]; }
+ constexpr const char& back() const { return _str[_len - 1]; }
+
+ constexpr const_iterator begin() const { return _str; }
+ constexpr const_iterator end() const { return _str + _len; }
+ constexpr const_iterator cbegin() const { return begin(); }
+ constexpr const_iterator cend() const { return end(); }
+
+ constexpr const char& operator[](const size_t pos) const { return _str[pos]; }
+
+ const char& at(const size_t pos) const
+ {
+ if (pos >= size()) {
+ throw std::out_of_range("serd::StringView::at pos");
+ }
+
+ return _str[pos];
+ }
+
+ StringView substr(const size_t pos) const
+ {
+ if (pos > size()) {
+ throw std::out_of_range("serd::StringView::substr pos");
+ }
+
+ return StringView{data() + pos, size() - pos};
+ }
+
+ StringView substr(const size_t pos, const size_t n) const
+ {
+ if (pos > size()) {
+ throw std::out_of_range("serd::StringView::substr pos");
+ }
+
+ return StringView{data() + pos, std::min(size() - pos, n)};
+ }
+
+ int compare(StringView rhs) const noexcept
+ {
+ if (!data() && !rhs.data()) {
+ return 0;
+ }
+
+ if (!data()) {
+ return -1;
+ }
+
+ if (!rhs.data()) {
+ return 1;
+ }
+
+ const size_type len = std::min(size(), rhs.size());
+ const int cmp = strncmp(data(), rhs.data(), len);
+
+ if (cmp) {
+ return cmp;
+ }
+
+ if (size() == rhs.size()) {
+ return 0;
+ }
+
+ if (size() < rhs.size()) {
+ return -1;
+ }
+
+ return 1;
+ }
+
+ template<class Alloc = std::allocator<char>>
+ std::basic_string<char, traits_type, Alloc> str() const
+ {
+ return std::basic_string<char, traits_type, Alloc>(data(), size(), Alloc{});
+ }
+
+ template<class Alloc = std::allocator<char>>
+ std::basic_string<char, traits_type, Alloc> str(const Alloc& alloc) const
+ {
+ return std::basic_string<char, traits_type, Alloc>(data(), size(), alloc);
+ }
+
+ explicit operator std::string() const { return str(); }
+
+ explicit operator const char*() const { return _str; }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ operator const SerdStringView() const { return SerdStringView{_str, _len}; }
+
+private:
+ const char* const _str{};
+ const size_t _len{};
+};
+
+inline bool
+operator==(const detail::StringView& lhs, const detail::StringView& rhs)
+{
+ return !lhs.compare(rhs);
+}
+
+inline bool
+operator==(const detail::StringView& lhs, const std::string& rhs)
+{
+ return lhs.length() == rhs.length() &&
+ !strncmp(lhs.c_str(), rhs.c_str(), lhs.length());
+}
+
+inline bool
+operator==(const detail::StringView& lhs, const char* rhs)
+{
+ return !strncmp(lhs.c_str(), rhs, lhs.length());
+}
+
+inline bool
+operator!=(const detail::StringView& lhs, const detail::StringView& rhs)
+{
+ return lhs.compare(rhs);
+}
+
+inline bool
+operator!=(const detail::StringView& lhs, const std::string& rhs)
+{
+ return lhs.length() != rhs.length() ||
+ !!strncmp(lhs.c_str(), rhs.c_str(), lhs.length());
+}
+
+inline bool
+operator!=(const detail::StringView& lhs, const char* rhs)
+{
+ return !!strncmp(lhs.c_str(), rhs, lhs.length());
+}
+
+inline bool
+operator<(const detail::StringView& lhs, const detail::StringView& rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool
+operator<(const detail::StringView& lhs, const std::string& rhs)
+{
+ return lhs.c_str() < StringView(rhs);
+}
+
+inline bool
+operator<(const detail::StringView& lhs, const char* rhs)
+{
+ return strncmp(lhs.c_str(), rhs, lhs.length()) < 0;
+}
+
+inline std::ostream&
+operator<<(std::ostream& os, const StringView& str)
+{
+ os.write(str.data(), std::streamsize(str.size()));
+ return os;
+}
+
+} // namespace detail
+} // namespace serd
+
+#endif // SERD_DETAIL_STRINGVIEW_HPP