summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hash-util.cc38
-rw-r--r--src/hash-util.h47
-rw-r--r--src/string-view.cc196
-rw-r--r--src/string-view.h288
-rw-r--r--src/test-string-view.cc412
5 files changed, 981 insertions, 0 deletions
diff --git a/src/hash-util.cc b/src/hash-util.cc
new file mode 100644
index 00000000..c0c55a21
--- /dev/null
+++ b/src/hash-util.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hash-util.h"
+
+#include "config.h"
+
+namespace wabt {
+
+// Hash combiner from:
+// http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
+
+hash_code hash_combine(hash_code seed, hash_code y) {
+#if SIZEOF_SIZE_T == 4
+ constexpr hash_code magic = 0x9e3779b9;
+#elif SIZEOF_SIZE_T == 8
+ constexpr hash_code magic = 0x9e3779b97f4a7c16;
+#else
+#error "weird sizeof size_t"
+#endif
+ seed ^= y + magic + (seed << 6) + (seed >> 2);
+ return seed;
+}
+
+} // namespace wabt
diff --git a/src/hash-util.h b/src/hash-util.h
new file mode 100644
index 00000000..0cf68758
--- /dev/null
+++ b/src/hash-util.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WABT_HASH_UTIL_H_
+#define WABT_HASH_UTIL_H_
+
+#include <cstdlib>
+#include <functional>
+
+namespace wabt {
+
+typedef std::size_t hash_code;
+
+inline hash_code hash_combine() { return 0; }
+inline hash_code hash_combine(hash_code seed) { return seed; }
+hash_code hash_combine(hash_code x, hash_code y);
+
+template <typename T, typename... U>
+inline hash_code hash_combine(const T& first, const U&... rest) {
+ return hash_combine(hash_combine(rest...), std::hash<T>()(first));
+}
+
+template <typename It>
+inline hash_code hash_range(It first, It last) {
+ hash_code result = 0;
+ for (auto iter = first; iter != last; ++iter) {
+ result = hash_combine(result, *iter);
+ }
+ return result;
+}
+
+} // namespace wabt
+
+#endif // WABT_HASH_UTIL_H_
diff --git a/src/string-view.cc b/src/string-view.cc
new file mode 100644
index 00000000..dc72f7dd
--- /dev/null
+++ b/src/string-view.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "string-view.h"
+
+#include <algorithm>
+#include <limits>
+
+namespace wabt {
+
+void string_view::remove_prefix(size_type n) {
+ assert(n <= size_);
+ data_ += n;
+ size_ -= n;
+}
+
+void string_view::remove_suffix(size_type n) {
+ assert(n <= size_);
+ size_ -= n;
+}
+
+void string_view::swap(string_view& s) noexcept {
+ std::swap(data_, s.data_);
+ std::swap(size_, s.size_);
+}
+
+string_view::operator std::string() const {
+ return std::string(data_, size_);
+}
+
+std::string string_view::to_string() const {
+ return std::string(data_, size_);
+}
+
+constexpr string_view::size_type string_view::max_size() const noexcept {
+ return std::numeric_limits<size_type>::max();
+}
+
+string_view::size_type string_view::copy(char* s,
+ size_type n,
+ size_type pos) const {
+ assert(pos <= size_);
+ size_t count = std::min(n, size_ - pos);
+ traits_type::copy(s, data_ + pos, count);
+ return count;
+}
+
+string_view string_view::substr(size_type pos, size_type n) const {
+ assert(pos <= size_);
+ size_t count = std::min(n, size_ - pos);
+ return string_view(data_ + pos, count);
+}
+
+int string_view::compare(string_view s) const noexcept {
+ size_type rlen = std::min(size_, s.size_);
+ int result = traits_type::compare(data_, s.data_, rlen);
+ if (result != 0 || size_ == s.size_) {
+ return result;
+ }
+ return size_ < s.size_ ? -1 : 1;
+}
+
+int string_view::compare(size_type pos1, size_type n1, string_view s) const {
+ return substr(pos1, n1).compare(s);
+}
+
+int string_view::compare(size_type pos1,
+ size_type n1,
+ string_view s,
+ size_type pos2,
+ size_type n2) const {
+ return substr(pos1, n1).compare(s.substr(pos2, n2));
+}
+
+int string_view::compare(const char* s) const {
+ return compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1, size_type n1, const char* s) const {
+ return substr(pos1, n1).compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1,
+ size_type n1,
+ const char* s,
+ size_type n2) const {
+ return substr(pos1, n1).compare(string_view(s, n2));
+}
+
+string_view::size_type string_view::find(string_view s, size_type pos) const
+ noexcept {
+ pos = std::min(pos, size_);
+ const_iterator iter = std::search(begin() + pos, end(), s.begin(), s.end());
+ return iter == end() ? npos : iter - begin();
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept {
+ return find(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find(const char* s,
+ size_type pos,
+ size_type n) const {
+ return find(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find(const char* s, size_type pos) const {
+ return find(string_view(s), pos);
+}
+
+string_view::size_type string_view::rfind(string_view s, size_type pos) const
+ noexcept {
+ pos = std::min(pos, size_ - s.size_);
+ reverse_iterator iter = std::search(reverse_iterator(begin() + pos + s.size_),
+ rend(), s.rbegin(), s.rend());
+ return iter == rend() ? npos : (rend() - iter - s.size_);
+}
+
+string_view::size_type string_view::rfind(char c, size_type pos) const
+ noexcept {
+ return rfind(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s,
+ size_type pos,
+ size_type n) const {
+ return rfind(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s, size_type pos) const {
+ return rfind(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_first_of(string_view s,
+ size_type pos) const
+ noexcept {
+ pos = std::min(pos, size_);
+ const_iterator iter =
+ std::find_first_of(begin() + pos, end(), s.begin(), s.end());
+ return iter == end() ? npos : iter - begin();
+}
+
+string_view::size_type string_view::find_first_of(char c, size_type pos) const
+ noexcept {
+ return find_first_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s,
+ size_type pos,
+ size_type n) const {
+ return find_first_of(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s,
+ size_type pos) const {
+ return find_first_of(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_last_of(string_view s,
+ size_type pos) const noexcept {
+ pos = std::min(pos, size_ - 1);
+ reverse_iterator iter = std::find_first_of(
+ reverse_iterator(begin() + pos + 1), rend(), s.begin(), s.end());
+ return iter == rend() ? npos : (rend() - iter - 1);
+}
+
+string_view::size_type string_view::find_last_of(char c, size_type pos) const
+ noexcept {
+ return find_last_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s,
+ size_type pos,
+ size_type n) const {
+ return find_last_of(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s,
+ size_type pos) const {
+ return find_last_of(string_view(s), pos);
+}
+
+} // namespace wabt
diff --git a/src/string-view.h b/src/string-view.h
new file mode 100644
index 00000000..bc90130f
--- /dev/null
+++ b/src/string-view.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WABT_STRING_VIEW_H_
+#define WABT_STRING_VIEW_H_
+
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <string>
+
+#include "hash-util.h"
+
+namespace wabt {
+
+// This is a simplified implemention of C++17's basic_string_view template.
+//
+// Missing features:
+// * Not a template
+// * No allocator support
+// * Some functions are not implemented
+// * Asserts instead of exceptions
+// * Some functions are not constexpr because we don't compile in C++17 mode
+
+class string_view {
+ public:
+ typedef std::char_traits<char> traits_type;
+ typedef char value_type;
+ typedef char* pointer;
+ typedef const char* const_pointer;
+ typedef char& reference;
+ typedef const char& const_reference;
+ typedef const char* const_iterator;
+ typedef const_iterator iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef const_reverse_iterator reverse_iterator;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ static const size_type npos = size_type(-1);
+
+ // construction and assignment
+ constexpr string_view() noexcept;
+ constexpr string_view(const string_view&) noexcept = default;
+ string_view& operator=(const string_view&) noexcept = default;
+ string_view(const std::string& str) noexcept;
+ /*constexpr*/ string_view(const char* str);
+ constexpr string_view(const char* str, size_type len);
+
+ // iterator support
+ constexpr const_iterator begin() const noexcept;
+ constexpr const_iterator end() const noexcept;
+ constexpr const_iterator cbegin() const noexcept;
+ constexpr const_iterator cend() const noexcept;
+ const_reverse_iterator rbegin() const noexcept;
+ const_reverse_iterator rend() const noexcept;
+ const_reverse_iterator crbegin() const noexcept;
+ const_reverse_iterator crend() const noexcept;
+
+ // capacity
+ constexpr size_type size() const noexcept;
+ constexpr size_type length() const noexcept;
+ constexpr size_type max_size() const noexcept;
+ constexpr bool empty() const noexcept;
+
+ // element access
+ constexpr const_reference operator[](size_type pos) const;
+ /*constexpr*/ const_reference at(size_type pos) const;
+ /*constexpr*/ const_reference front() const;
+ /*constexpr*/ const_reference back() const;
+ constexpr const_pointer data() const noexcept;
+
+ // modifiers
+ /*constexpr*/ void remove_prefix(size_type n);
+ /*constexpr*/ void remove_suffix(size_type n);
+ /*constexpr*/ void swap(string_view& s) noexcept;
+
+ // string operations
+ explicit operator std::string() const;
+ std::string to_string() const;
+ size_type copy(char* s, size_type n, size_type pos = 0) const;
+ /*constexpr*/ string_view substr(size_type pos = 0, size_type n = npos) const;
+ /*constexpr*/ int compare(string_view s) const noexcept;
+ /*constexpr*/ int compare(size_type pos1, size_type n1, string_view s) const;
+ /*constexpr*/ int compare(size_type pos1,
+ size_type n1,
+ string_view s,
+ size_type pos2,
+ size_type n2) const;
+ /*constexpr*/ int compare(const char* s) const;
+ /*constexpr*/ int compare(size_type pos1, size_type n1, const char* s) const;
+ /*constexpr*/ int compare(size_type pos1,
+ size_type n1,
+ const char* s,
+ size_type n2) const;
+ /*constexpr*/ size_type find(string_view s, size_type pos = 0) const noexcept;
+ /*constexpr*/ size_type find(char c, size_type pos = 0) const noexcept;
+ /*constexpr*/ size_type find(const char* s, size_type pos, size_type n) const;
+ /*constexpr*/ size_type find(const char* s, size_type pos = 0) const;
+ /*constexpr*/ size_type rfind(string_view s, size_type pos = npos) const
+ noexcept;
+ /*constexpr*/ size_type rfind(char c, size_type pos = npos) const noexcept;
+ /*constexpr*/ size_type rfind(const char* s,
+ size_type pos,
+ size_type n) const;
+ /*constexpr*/ size_type rfind(const char* s, size_type pos = npos) const;
+ /*constexpr*/ size_type find_first_of(string_view s, size_type pos = 0) const
+ noexcept;
+ /*constexpr*/ size_type find_first_of(char c, size_type pos = 0) const
+ noexcept;
+ /*constexpr*/ size_type find_first_of(const char* s,
+ size_type pos,
+ size_type n) const;
+ /*constexpr*/ size_type find_first_of(const char* s, size_type pos = 0) const;
+ /*constexpr*/ size_type find_last_of(string_view s,
+ size_type pos = npos) const noexcept;
+ /*constexpr*/ size_type find_last_of(char c, size_type pos = npos) const
+ noexcept;
+ /*constexpr*/ size_type find_last_of(const char* s,
+ size_type pos,
+ size_type n) const;
+ /*constexpr*/ size_type find_last_of(const char* s,
+ size_type pos = npos) const;
+
+ // TODO(binji): These are defined by C++17 basic_string_view but not
+ // implemented here.
+#if 0
+ constexpr size_type find_first_not_of(string_view s, size_type pos = 0) const
+ noexcept;
+ constexpr size_type find_first_not_of(char c, size_type pos = 0) const
+ noexcept;
+ constexpr size_type find_first_not_of(const char* s,
+ size_type pos,
+ size_type n) const;
+ constexpr size_type find_first_not_of(const char* s, size_type pos = 0) const;
+ constexpr size_type find_last_not_of(string_view s,
+ size_type pos = npos) const noexcept;
+ constexpr size_type find_last_not_of(char c, size_type pos = npos) const
+ noexcept;
+ constexpr size_type find_last_not_of(const char* s,
+ size_type pos,
+ size_type n) const;
+ constexpr size_type find_last_not_of(const char* s,
+ size_type pos = npos) const;
+#endif
+
+ private:
+ const char* data_;
+ size_type size_;
+};
+
+// non-member comparison functions
+inline bool operator==(string_view x, string_view y) noexcept {
+ return x.compare(y) == 0;
+}
+
+inline bool operator!=(string_view x, string_view y) noexcept {
+ return x.compare(y) != 0;
+}
+
+inline bool operator<(string_view x, string_view y) noexcept {
+ return x.compare(y) < 0;
+}
+
+inline bool operator>(string_view x, string_view y) noexcept {
+ return x.compare(y) > 0;
+}
+
+inline bool operator<=(string_view x, string_view y) noexcept {
+ return x.compare(y) <= 0;
+}
+
+inline bool operator>=(string_view x, string_view y) noexcept {
+ return x.compare(y) >= 0;
+}
+
+inline constexpr string_view::string_view() noexcept
+ : data_(nullptr), size_(0) {}
+
+inline string_view::string_view(const std::string& str) noexcept
+ : data_(str.data()), size_(str.size()) {}
+
+inline string_view::string_view(const char* str)
+ : data_(str), size_(traits_type::length(str)) {}
+
+inline constexpr string_view::string_view(const char* str, size_type len)
+ : data_(str), size_(len) {}
+
+inline constexpr string_view::const_iterator string_view::begin() const
+ noexcept {
+ return data_;
+}
+
+inline constexpr string_view::const_iterator string_view::end() const noexcept {
+ return data_ + size_;
+}
+
+inline constexpr string_view::const_iterator string_view::cbegin() const
+ noexcept {
+ return data_;
+}
+
+inline constexpr string_view::const_iterator string_view::cend() const
+ noexcept {
+ return data_ + size_;
+}
+
+inline string_view::const_reverse_iterator string_view::rbegin() const
+ noexcept {
+ return const_reverse_iterator(end());
+}
+
+inline string_view::const_reverse_iterator string_view::rend() const noexcept {
+ return const_reverse_iterator(begin());
+}
+
+inline string_view::const_reverse_iterator string_view::crbegin() const
+ noexcept {
+ return const_reverse_iterator(cend());
+}
+
+inline string_view::const_reverse_iterator string_view::crend() const noexcept {
+ return const_reverse_iterator(cbegin());
+}
+
+constexpr inline string_view::size_type string_view::size() const noexcept {
+ return size_;
+}
+
+constexpr inline string_view::size_type string_view::length() const noexcept {
+ return size_;
+}
+
+constexpr inline bool string_view::empty() const noexcept {
+ return size_ == 0;
+}
+
+constexpr inline string_view::const_reference string_view::operator[](
+ size_type pos) const {
+ return data_[pos];
+}
+
+inline string_view::const_reference string_view::at(size_type pos) const {
+ assert(pos < size_);
+ return data_[pos];
+}
+
+inline string_view::const_reference string_view::front() const {
+ assert(!empty());
+ return *data_;
+}
+
+inline string_view::const_reference string_view::back() const {
+ assert(!empty());
+ return data_[size_ - 1];
+}
+
+constexpr inline string_view::const_pointer string_view::data() const noexcept {
+ return data_;
+}
+
+} // namespace wabt
+
+namespace std {
+
+// hash support
+template <>
+struct hash<::wabt::string_view> {
+ ::wabt::hash_code operator()(const ::wabt::string_view& sv) {
+ return ::wabt::hash_range(sv.begin(), sv.end());
+ }
+};
+
+}
+
+#endif // WABT_STRING_VIEW_H_
diff --git a/src/test-string-view.cc b/src/test-string-view.cc
new file mode 100644
index 00000000..9a7636f7
--- /dev/null
+++ b/src/test-string-view.cc
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "string-view.h"
+
+#include <cstring>
+#include <functional>
+
+using namespace wabt;
+
+namespace {
+
+void assert_string_view_eq(const char* s, const string_view& sv) {
+ size_t len = std::strlen(s);
+ ASSERT_EQ(len, sv.size());
+ for (size_t i = 0; i < len; ++i) {
+ ASSERT_EQ(s[i], sv[i]);
+ }
+}
+
+constexpr string_view::size_type npos = string_view::npos;
+
+} // namespace
+
+TEST(string_view, default_constructor) {
+ assert_string_view_eq("", string_view());
+}
+
+TEST(string_view, copy_constructor) {
+ string_view sv1("copy");
+ assert_string_view_eq("copy", string_view(sv1));
+
+ string_view sv2;
+ assert_string_view_eq("", string_view(sv2));
+}
+
+TEST(string_view, assignment_operator) {
+ string_view sv1;
+ sv1 = string_view("assign");
+ assert_string_view_eq("assign", sv1);
+
+ string_view sv2;
+ sv2 = string_view();
+ assert_string_view_eq("", sv2);
+}
+
+TEST(string_view, string_constructor) {
+ assert_string_view_eq("", string_view(std::string()));
+ assert_string_view_eq("string", string_view(std::string("string")));
+}
+
+TEST(string_view, cstr_constructor) {
+ assert_string_view_eq("", string_view(""));
+ assert_string_view_eq("cstr", string_view("cstr"));
+}
+
+TEST(string_view, cstr_len_constructor) {
+ assert_string_view_eq("", string_view("foo-bar-baz", 0));
+ assert_string_view_eq("foo", string_view("foo-bar-baz", 3));
+ assert_string_view_eq("foo-bar", string_view("foo-bar-baz", 7));
+}
+
+TEST(string_view, begin_end) {
+ string_view sv("012345");
+
+ char count = 0;
+ for (auto iter = sv.begin(), end = sv.end(); iter != end; ++iter) {
+ ASSERT_EQ('0' + count, *iter);
+ ++count;
+ }
+ ASSERT_EQ(6, count);
+}
+
+TEST(string_view, cbegin_cend) {
+ const string_view sv("012345");
+
+ char count = 0;
+ for (auto iter = sv.cbegin(), end = sv.cend(); iter != end; ++iter) {
+ ASSERT_EQ('0' + count, *iter);
+ ++count;
+ }
+ ASSERT_EQ(6, count);
+}
+
+TEST(string_view, rbegin_rend) {
+ string_view sv("012345");
+
+ char count = 0;
+ for (auto iter = sv.rbegin(), end = sv.rend(); iter != end; ++iter) {
+ ASSERT_EQ('5' - count, *iter);
+ ++count;
+ }
+ ASSERT_EQ(6, count);
+}
+
+TEST(string_view, crbegin_crend) {
+ const string_view sv("012345");
+
+ char count = 0;
+ for (auto iter = sv.crbegin(), end = sv.crend(); iter != end; ++iter) {
+ ASSERT_EQ('5' - count, *iter);
+ ++count;
+ }
+ ASSERT_EQ(6, count);
+}
+
+TEST(string_view, size) {
+ string_view sv1;
+ ASSERT_EQ(0U, sv1.size());
+
+ string_view sv2("");
+ ASSERT_EQ(0U, sv2.size());
+
+ string_view sv3("hello");
+ ASSERT_EQ(5U, sv3.size());
+}
+
+TEST(string_view, length) {
+ string_view sv1;
+ ASSERT_EQ(0U, sv1.length());
+
+ string_view sv2("hello");
+ ASSERT_EQ(5U, sv2.length());
+}
+
+TEST(string_view, empty) {
+ string_view sv1;
+ ASSERT_TRUE(sv1.empty());
+
+ string_view sv2("bye");
+ ASSERT_FALSE(sv2.empty());
+}
+
+TEST(string_view, operator_bracket) {
+ string_view sv("words");
+ ASSERT_EQ('w', sv[0]);
+ ASSERT_EQ('o', sv[1]);
+ ASSERT_EQ('r', sv[2]);
+ ASSERT_EQ('d', sv[3]);
+ ASSERT_EQ('s', sv[4]);
+}
+
+TEST(string_view, at) {
+ string_view sv("words");
+ ASSERT_EQ('w', sv.at(0));
+ ASSERT_EQ('o', sv.at(1));
+ ASSERT_EQ('r', sv.at(2));
+ ASSERT_EQ('d', sv.at(3));
+ ASSERT_EQ('s', sv.at(4));
+}
+
+TEST(string_view, front) {
+ string_view sv("words");
+ ASSERT_EQ('w', sv.front());
+}
+
+TEST(string_view, back) {
+ string_view sv("words");
+ ASSERT_EQ('s', sv.back());
+}
+
+TEST(string_view, data) {
+ const char* cstr = "words";
+ string_view sv(cstr);
+ ASSERT_EQ(cstr, sv.data());
+}
+
+TEST(string_view, remove_prefix) {
+ string_view sv("words");
+ sv.remove_prefix(2);
+ assert_string_view_eq("rds", sv);
+}
+
+TEST(string_view, remove_suffix) {
+ string_view sv("words");
+ sv.remove_suffix(2);
+ assert_string_view_eq("wor", sv);
+}
+
+TEST(string_view, swap) {
+ string_view sv1("hello");
+ string_view sv2("bye");
+
+ sv1.swap(sv2);
+
+ assert_string_view_eq("bye", sv1);
+ assert_string_view_eq("hello", sv2);
+}
+
+TEST(string_view, operator_std_string) {
+ string_view sv1("hi");
+ std::string s(sv1);
+
+ ASSERT_EQ(2U, s.size());
+ ASSERT_EQ('h', s[0]);
+ ASSERT_EQ('i', s[1]);
+}
+
+TEST(string_view, copy) {
+ string_view sv("words");
+ char buffer[10] = {0};
+
+ sv.copy(buffer, 10, 2);
+ ASSERT_EQ('r', buffer[0]);
+ ASSERT_EQ('d', buffer[1]);
+ ASSERT_EQ('s', buffer[2]);
+ for (int i = 3; i < 10; ++i) {
+ ASSERT_EQ(0, buffer[i]);
+ }
+}
+
+TEST(string_view, substr) {
+ string_view sv1("abcdefghij");
+ string_view sv2 = sv1.substr(2, 3);
+ assert_string_view_eq("cde", sv2);
+}
+
+TEST(string_view, compare0) {
+ ASSERT_TRUE(string_view("meat").compare(string_view("meet")) < 0);
+ ASSERT_TRUE(string_view("rest").compare(string_view("rate")) > 0);
+ ASSERT_TRUE(string_view("equal").compare(string_view("equal")) == 0);
+ ASSERT_TRUE(string_view("star").compare(string_view("start")) < 0);
+ ASSERT_TRUE(string_view("finished").compare(string_view("fin")) > 0);
+}
+
+TEST(string_view, compare1) {
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("ca")) > 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cd")) == 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cz")) < 0);
+}
+
+TEST(string_view, compare2) {
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_ca__"), 1, 2) >
+ 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cd__"), 1, 2) ==
+ 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cz__"), 1, 2) <
+ 0);
+}
+
+TEST(string_view, compare3) {
+ ASSERT_TRUE(string_view("abcdef").compare("aaaa") > 0);
+ ASSERT_TRUE(string_view("abcdef").compare("abcdef") == 0);
+ ASSERT_TRUE(string_view("abcdef").compare("zzzz") < 0);
+}
+
+TEST(string_view, compare4) {
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca") > 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd") == 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz") < 0);
+}
+
+TEST(string_view, compare5) {
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca____", 2) > 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd___", 2) == 0);
+ ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz__", 2) < 0);
+}
+
+TEST(string_view, find0) {
+ ASSERT_EQ(0U, string_view("find fins").find(string_view("fin")));
+ ASSERT_EQ(5U, string_view("find fins").find(string_view("fin"), 1));
+ ASSERT_EQ(npos, string_view("find fins").find(string_view("fin"), 6));
+}
+
+TEST(string_view, find1) {
+ ASSERT_EQ(0U, string_view("012340123").find('0'));
+ ASSERT_EQ(5U, string_view("012340123").find('0', 2));
+ ASSERT_EQ(npos, string_view("012340123").find('0', 6));
+}
+
+TEST(string_view, find2) {
+ ASSERT_EQ(1U, string_view("012340123").find("12345", 0, 2));
+ ASSERT_EQ(6U, string_view("012340123").find("12345", 3, 2));
+ ASSERT_EQ(npos, string_view("012340123").find("12345", 10, 2));
+}
+
+TEST(string_view, find3) {
+ ASSERT_EQ(1U, string_view("012340123").find("12"));
+ ASSERT_EQ(6U, string_view("012340123").find("12", 2));
+ ASSERT_EQ(npos, string_view("012340123").find("12", 10));
+}
+
+TEST(string_view, rfind0) {
+ ASSERT_EQ(5U, string_view("find fins").rfind(string_view("fin")));
+ ASSERT_EQ(0U, string_view("find fins").rfind(string_view("fin"), 4));
+ ASSERT_EQ(npos, string_view("find fins").rfind(string_view("no")));
+}
+
+TEST(string_view, rfind1) {
+ ASSERT_EQ(5U, string_view("012340123").rfind('0'));
+ ASSERT_EQ(0U, string_view("012340123").rfind('0', 2));
+ ASSERT_EQ(npos, string_view("012340123").rfind('9'));
+}
+
+TEST(string_view, rfind2) {
+ ASSERT_EQ(6U, string_view("012340123").rfind("12345", npos, 2));
+ ASSERT_EQ(1U, string_view("012340123").rfind("12345", 4, 2));
+ ASSERT_EQ(npos, string_view("012340123").rfind("12345", npos, 5));
+}
+
+TEST(string_view, rfind3) {
+ ASSERT_EQ(6U, string_view("012340123").rfind("12"));
+ ASSERT_EQ(1U, string_view("012340123").rfind("12", 2));
+ ASSERT_EQ(npos, string_view("012340123").rfind("12", 0));
+}
+
+TEST(string_view, find_first_of0) {
+ ASSERT_EQ(0U, string_view("0123abc").find_first_of(string_view("0a")));
+ ASSERT_EQ(4U, string_view("0123abc").find_first_of(string_view("0a"), 1));
+ ASSERT_EQ(npos, string_view("0123abc").find_first_of(string_view("xyz")));
+}
+
+TEST(string_view, find_first_of1) {
+ ASSERT_EQ(1U, string_view("ahellohi").find_first_of('h'));
+ ASSERT_EQ(6U, string_view("ahellohi").find_first_of('h', 2));
+ ASSERT_EQ(npos, string_view("ahellohi").find_first_of('z', 2));
+}
+
+TEST(string_view, find_first_of2) {
+ ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a1b", 0, 2));
+ ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a1b", 1, 2));
+ ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a1b", 5, 2));
+}
+
+TEST(string_view, find_first_of3) {
+ ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a"));
+ ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a", 0));
+ ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a", 1));
+ ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a", 5));
+}
+
+TEST(string_view, find_last_of0) {
+ ASSERT_EQ(4U, string_view("0123abc").find_last_of(string_view("0a")));
+ ASSERT_EQ(0U, string_view("0123abc").find_last_of(string_view("0a"), 1));
+ ASSERT_EQ(npos, string_view("0123abc").find_last_of(string_view("xyz")));
+}
+
+TEST(string_view, find_last_of1) {
+ ASSERT_EQ(6U, string_view("ahellohi").find_last_of('h'));
+ ASSERT_EQ(1U, string_view("ahellohi").find_last_of('h', 2));
+ ASSERT_EQ(npos, string_view("ahellohi").find_last_of('z', 2));
+}
+
+TEST(string_view, find_last_of2) {
+ ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a1b", npos, 2));
+ ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a1b", 1, 2));
+ ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1b", 0, 2));
+ ASSERT_EQ(npos, string_view("0123abc").find_last_of("xyz", npos, 0));
+}
+
+TEST(string_view, find_last_of3) {
+ ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a"));
+ ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a", npos));
+ ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a", 1));
+ ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1", 0));
+}
+
+TEST(string_view, operator_equal) {
+ ASSERT_TRUE(string_view("this") == string_view("this"));
+ ASSERT_FALSE(string_view("this") == string_view("that"));
+}
+
+TEST(string_view, operator_not_equal) {
+ ASSERT_FALSE(string_view("here") != string_view("here"));
+ ASSERT_TRUE(string_view("here") != string_view("there"));
+}
+
+TEST(string_view, operator_less_than) {
+ ASSERT_TRUE(string_view("abc") < string_view("xyz"));
+ ASSERT_FALSE(string_view("later") < string_view("earlier"));
+ ASSERT_FALSE(string_view("one") < string_view("one"));
+}
+
+TEST(string_view, operator_greater_than) {
+ ASSERT_TRUE(string_view("much") > string_view("little"));
+ ASSERT_FALSE(string_view("future") > string_view("past"));
+ ASSERT_FALSE(string_view("now") > string_view("now"));
+}
+
+TEST(string_view, operator_less_than_or_equal) {
+ ASSERT_TRUE(string_view("abc") <= string_view("xyz"));
+ ASSERT_FALSE(string_view("later") <= string_view("earlier"));
+ ASSERT_TRUE(string_view("one") <= string_view("one"));
+}
+
+TEST(string_view, operator_greater_than_or_equal) {
+ ASSERT_TRUE(string_view("much") >= string_view("little"));
+ ASSERT_FALSE(string_view("future") >= string_view("past"));
+ ASSERT_TRUE(string_view("now") >= string_view("now"));
+}
+
+TEST(string_view, hash) {
+ std::hash<string_view> hasher;
+
+ ASSERT_NE(hasher(string_view("hello")), hasher(string_view("goodbye")));
+ ASSERT_EQ(hasher(string_view("same")), hasher(string_view("same")));
+}