summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2017-01-19 23:40:02 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2017-01-19 23:40:06 +0000
commit1f9f11007db09bbbc156965e77b10de82a32a544 (patch)
treee715a9edb691da38726c2c5487625bd35b05ec94 /libs
parent12375e9e0d14868cf63c0d6584c7a7d9440c30c4 (diff)
parentd5083f6f6b9bc76bbe64052bcec639eee752a321 (diff)
Merge "Move StringPiece to libandroidfw"
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/include/androidfw/StringPiece.h279
-rw-r--r--libs/androidfw/tests/Android.mk1
-rw-r--r--libs/androidfw/tests/StringPiece_test.cpp95
3 files changed, 375 insertions, 0 deletions
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
new file mode 100644
index 000000000000..c9effd1a5112
--- /dev/null
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 ANDROIDFW_STRING_PIECE_H
+#define ANDROIDFW_STRING_PIECE_H
+
+#include <ostream>
+#include <string>
+
+#include "utils/JenkinsHash.h"
+#include "utils/Unicode.h"
+
+namespace android {
+
+// Read only wrapper around basic C strings. Prevents excessive copying.
+// StringPiece does not own the data it is wrapping. The lifetime of the underlying
+// data must outlive this StringPiece.
+//
+// WARNING: When creating from std::basic_string<>, moving the original
+// std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
+// BasicStringPiece<> should only be used transitively.
+template <typename TChar>
+class BasicStringPiece {
+ public:
+ using const_iterator = const TChar*;
+ using difference_type = size_t;
+
+ // End of string marker.
+ constexpr static const size_t npos = static_cast<size_t>(-1);
+
+ BasicStringPiece();
+ BasicStringPiece(const BasicStringPiece<TChar>& str);
+ BasicStringPiece(const std::basic_string<TChar>& str); // NOLINT(implicit)
+ BasicStringPiece(const TChar* str); // NOLINT(implicit)
+ BasicStringPiece(const TChar* str, size_t len);
+
+ BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
+ BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
+
+ BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
+ BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
+ BasicStringPiece<TChar>::const_iterator end) const;
+
+ const TChar* data() const;
+ size_t length() const;
+ size_t size() const;
+ bool empty() const;
+ std::basic_string<TChar> to_string() const;
+
+ bool contains(const BasicStringPiece<TChar>& rhs) const;
+ int compare(const BasicStringPiece<TChar>& rhs) const;
+ bool operator<(const BasicStringPiece<TChar>& rhs) const;
+ bool operator>(const BasicStringPiece<TChar>& rhs) const;
+ bool operator==(const BasicStringPiece<TChar>& rhs) const;
+ bool operator!=(const BasicStringPiece<TChar>& rhs) const;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ private:
+ const TChar* data_;
+ size_t length_;
+};
+
+using StringPiece = BasicStringPiece<char>;
+using StringPiece16 = BasicStringPiece<char16_t>;
+
+//
+// BasicStringPiece implementation.
+//
+
+template <typename TChar>
+constexpr const size_t BasicStringPiece<TChar>::npos;
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str)
+ : data_(str.data_), length_(str.length_) {}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str)
+ : data_(str.data()), length_(str.length()) {}
+
+template <>
+inline BasicStringPiece<char>::BasicStringPiece(const char* str)
+ : data_(str), length_(str != nullptr ? strlen(str) : 0) {}
+
+template <>
+inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str)
+ : data_(str), length_(str != nullptr ? strlen16(str) : 0) {}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len)
+ : data_(str), length_(len) {}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
+ const BasicStringPiece<TChar>& rhs) {
+ data_ = rhs.data_;
+ length_ = rhs.length_;
+ return *this;
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
+ data_ = str;
+ length_ = len;
+ return *this;
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
+ if (len == npos) {
+ len = length_ - start;
+ }
+
+ if (start > length_ || start + len > length_) {
+ return BasicStringPiece<TChar>();
+ }
+ return BasicStringPiece<TChar>(data_ + start, len);
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
+ BasicStringPiece<TChar>::const_iterator begin,
+ BasicStringPiece<TChar>::const_iterator end) const {
+ return BasicStringPiece<TChar>(begin, end - begin);
+}
+
+template <typename TChar>
+inline const TChar* BasicStringPiece<TChar>::data() const {
+ return data_;
+}
+
+template <typename TChar>
+inline size_t BasicStringPiece<TChar>::length() const {
+ return length_;
+}
+
+template <typename TChar>
+inline size_t BasicStringPiece<TChar>::size() const {
+ return length_;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::empty() const {
+ return length_ == 0;
+}
+
+template <typename TChar>
+inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const {
+ return std::basic_string<TChar>(data_, length_);
+}
+
+template <>
+inline bool BasicStringPiece<char>::contains(const BasicStringPiece<char>& rhs) const {
+ if (!data_ || !rhs.data_) {
+ return false;
+ }
+ if (rhs.length_ > length_) {
+ return false;
+ }
+ return strstr(data_, rhs.data_) != nullptr;
+}
+
+template <>
+inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
+ const char nullStr = '\0';
+ const char* b1 = data_ != nullptr ? data_ : &nullStr;
+ const char* e1 = b1 + length_;
+ const char* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
+ const char* e2 = b2 + rhs.length_;
+
+ while (b1 < e1 && b2 < e2) {
+ const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
+ if (d) {
+ return d;
+ }
+ }
+ return static_cast<int>(length_ - rhs.length_);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
+ const ssize_t result_len = utf16_to_utf8_length(str.data(), str.size());
+ if (result_len < 0) {
+ // Empty string.
+ return out;
+ }
+
+ std::string result;
+ result.resize(static_cast<size_t>(result_len));
+ utf16_to_utf8(str.data(), str.length(), &*result.begin(), static_cast<size_t>(result_len) + 1);
+ return out << result;
+}
+
+template <>
+inline bool BasicStringPiece<char16_t>::contains(const BasicStringPiece<char16_t>& rhs) const {
+ if (!data_ || !rhs.data_) {
+ return false;
+ }
+ if (rhs.length_ > length_) {
+ return false;
+ }
+ return strstr16(data_, rhs.data_) != nullptr;
+}
+
+template <>
+inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
+ const char16_t nullStr = u'\0';
+ const char16_t* b1 = data_ != nullptr ? data_ : &nullStr;
+ const char16_t* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
+ return strzcmp16(b1, length_, b2, rhs.length_);
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
+ return compare(rhs) < 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
+ return compare(rhs) > 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
+ return compare(rhs) == 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
+ return compare(rhs) != 0;
+}
+
+template <typename TChar>
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
+ return data_;
+}
+
+template <typename TChar>
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
+ return data_ + length_;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
+ return out.write(str.data(), str.size());
+}
+
+} // namespace android
+
+namespace std {
+
+template <typename TChar>
+struct hash<android::BasicStringPiece<TChar>> {
+ size_t operator()(const android::BasicStringPiece<TChar>& str) const {
+ uint32_t hashCode = android::JenkinsHashMixBytes(
+ 0, reinterpret_cast<const uint8_t*>(str.data()), sizeof(TChar) * str.size());
+ return static_cast<size_t>(hashCode);
+ }
+};
+
+} // namespace std
+
+#endif // ANDROIDFW_STRING_PIECE_H
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6754cd89944a..650f8138366b 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -34,6 +34,7 @@ testFiles := \
LoadedArsc_test.cpp \
ResTable_test.cpp \
Split_test.cpp \
+ StringPiece_test.cpp \
TestHelpers.cpp \
TestMain.cpp \
Theme_test.cpp \
diff --git a/libs/androidfw/tests/StringPiece_test.cpp b/libs/androidfw/tests/StringPiece_test.cpp
new file mode 100644
index 000000000000..316a5c1bf40e
--- /dev/null
+++ b/libs/androidfw/tests/StringPiece_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 "androidfw/StringPiece.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "TestHelpers.h"
+
+namespace android {
+
+TEST(StringPieceTest, CompareNonNullTerminatedPiece) {
+ StringPiece a("hello world", 5);
+ StringPiece b("hello moon", 5);
+ EXPECT_EQ(a, b);
+
+ StringPiece16 a16(u"hello world", 5);
+ StringPiece16 b16(u"hello moon", 5);
+ EXPECT_EQ(a16, b16);
+}
+
+TEST(StringPieceTest, PiecesHaveCorrectSortOrder) {
+ std::string testing("testing");
+ std::string banana("banana");
+ std::string car("car");
+
+ EXPECT_TRUE(StringPiece(testing) > banana);
+ EXPECT_TRUE(StringPiece(testing) > car);
+ EXPECT_TRUE(StringPiece(banana) < testing);
+ EXPECT_TRUE(StringPiece(banana) < car);
+ EXPECT_TRUE(StringPiece(car) < testing);
+ EXPECT_TRUE(StringPiece(car) > banana);
+}
+
+TEST(StringPieceTest, PiecesHaveCorrectSortOrderUtf8) {
+ std::string testing("testing");
+ std::string banana("banana");
+ std::string car("car");
+
+ EXPECT_TRUE(StringPiece(testing) > banana);
+ EXPECT_TRUE(StringPiece(testing) > car);
+ EXPECT_TRUE(StringPiece(banana) < testing);
+ EXPECT_TRUE(StringPiece(banana) < car);
+ EXPECT_TRUE(StringPiece(car) < testing);
+ EXPECT_TRUE(StringPiece(car) > banana);
+}
+
+TEST(StringPieceTest, ContainsOtherStringPiece) {
+ StringPiece text("I am a leaf on the wind.");
+ StringPiece start_needle("I am");
+ StringPiece end_needle("wind.");
+ StringPiece middle_needle("leaf");
+ StringPiece empty_needle("");
+ StringPiece missing_needle("soar");
+ StringPiece long_needle("This string is longer than the text.");
+
+ EXPECT_TRUE(text.contains(start_needle));
+ EXPECT_TRUE(text.contains(end_needle));
+ EXPECT_TRUE(text.contains(middle_needle));
+ EXPECT_TRUE(text.contains(empty_needle));
+ EXPECT_FALSE(text.contains(missing_needle));
+ EXPECT_FALSE(text.contains(long_needle));
+
+ StringPiece16 text16(u"I am a leaf on the wind.");
+ StringPiece16 start_needle16(u"I am");
+ StringPiece16 end_needle16(u"wind.");
+ StringPiece16 middle_needle16(u"leaf");
+ StringPiece16 empty_needle16(u"");
+ StringPiece16 missing_needle16(u"soar");
+ StringPiece16 long_needle16(u"This string is longer than the text.");
+
+ EXPECT_TRUE(text16.contains(start_needle16));
+ EXPECT_TRUE(text16.contains(end_needle16));
+ EXPECT_TRUE(text16.contains(middle_needle16));
+ EXPECT_TRUE(text16.contains(empty_needle16));
+ EXPECT_FALSE(text16.contains(missing_needle16));
+ EXPECT_FALSE(text16.contains(long_needle16));
+}
+
+} // namespace android