diff --git a/paddle/strings/stringpiece.cc b/paddle/strings/stringpiece.cc index cc6d6a23f655622a94a5f474d22fe53f20ad5c5c..4f788c6ecd56166aa0520db139a6cb1a29fae7cd 100644 --- a/paddle/strings/stringpiece.cc +++ b/paddle/strings/stringpiece.cc @@ -16,7 +16,9 @@ #include "paddle/strings/stringpiece.h" -#include +// #include +#include + #include #include @@ -72,12 +74,14 @@ bool HasSuffix(StringPiece s, StringPiece x) { } StringPiece SkipPrefix(StringPiece s, size_t n) { - assert(n <= s.len()); + if (n > s.len()) + throw std::invalid_argument("Skip distance larger than StringPiece length"); return StringPiece(s.data() + n, s.len() - n); } StringPiece SkipSuffix(StringPiece s, size_t n) { - assert(size_ >= n); + if (n > s.len()) + throw std::invalid_argument("Skip distance larger than StringPiece length"); return StringPiece(s.data(), s.len() - n); } @@ -124,4 +128,8 @@ StringPiece SubStr(StringPiece s, size_t pos, size_t n) { return StringPiece(s.data() + pos, n); } +std::ostream& operator<<(std::ostream& o, StringPiece piece) { + return o << piece.ToString(); +} + } // namespace paddle diff --git a/paddle/strings/stringpiece.h b/paddle/strings/stringpiece.h index f10b5eecf4316b42244e1f7ed3f7eb30e03a2191..413b65d38412126deef10436770cdd888de6c60c 100644 --- a/paddle/strings/stringpiece.h +++ b/paddle/strings/stringpiece.h @@ -17,7 +17,6 @@ #pragma once #include -#include #include #include @@ -26,7 +25,11 @@ namespace paddle { // StringPiece points into a std::string object but doesn't own the // string. It is for efficient access to strings. Like Go's string -// type. StringPiece is not thread-safe. +// type. Not that StringPiece doesn't mutate the underlying string, +// so it is thread-safe given that the underlying string doesn't +// change. Because StringPiece contains a little data members, and +// its syntax is simple as it doesn't own/manage the string, it is +// cheap to construct StringPieces and pass them around. class StringPiece { public: static const size_t npos = static_cast(-1); @@ -37,7 +40,7 @@ public: // size_ is 0. StringPiece(); StringPiece(const char* d, size_t n); - StringPiece(const char* s); + StringPiece(const char* d); StringPiece(const std::string& s); const char* data() const { return data_; } @@ -55,10 +58,6 @@ public: iterator begin() const { return data_; } iterator end() const { return data_ + size_; } - struct Hasher { - size_t operator()(StringPiece arg) const; - }; - // Return a string that contains the copy of the referenced data. std::string ToString() const { return std::string(data_, size_); } @@ -69,12 +68,6 @@ private: // Intentionally copyable }; -// Because StringPiece contains a little data members, and without the -// ownership, it is so cheap to pass StringPieces around, we don't -// need to define parrameters of the following operations to be -// references. Also, it is cheap to construct new StringPieces, so we -// don't define mutative operations as member functions. - int Compare(StringPiece a, StringPiece b); bool operator==(StringPiece x, StringPiece y); @@ -94,9 +87,13 @@ StringPiece SkipSuffix(StringPiece s, size_t n); StringPiece TrimPrefix(StringPiece s, StringPiece prefix); StringPiece TrimSuffix(StringPiece s, StringPiece suffix); +// Returns if s contains sub. Any s except for empty s contains an +// empty sub. bool Contains(StringPiece s, StringPiece sub); -// Return the first occurrence of sub in s, or npos. +// Return the first occurrence of sub in s, or npos. If both s and +// sub is empty, it returns npos; otherwise, if only sub is empty, it +// returns 0. size_t Index(StringPiece s, StringPiece sub); // Return the first occurrence of c in s[pos:end], or npos. @@ -108,6 +105,6 @@ size_t RFind(StringPiece s, char c, size_t pos); StringPiece SubStr(StringPiece s, size_t pos, size_t n); // allow StringPiece to be logged -extern std::ostream& operator<<(std::ostream& o, StringPiece piece); +std::ostream& operator<<(std::ostream& o, StringPiece piece); } // namespace paddle diff --git a/paddle/strings/stringpiece_test.cc b/paddle/strings/stringpiece_test.cc index 84ebc0ee032043829e956c5c0fac9f34a94f50a6..2ba66a04f641c3457efa713383484491a213668f 100644 --- a/paddle/strings/stringpiece_test.cc +++ b/paddle/strings/stringpiece_test.cc @@ -15,6 +15,9 @@ */ #include "paddle/strings/stringpiece.h" + +#include + #include "gtest/gtest.h" TEST(StringPiece, Construct) { @@ -23,10 +26,7 @@ TEST(StringPiece, Construct) { EXPECT_EQ(NULL, s.data()); EXPECT_EQ(0U, s.len()); } - { - EXPECT_THROW([] { paddle::StringPiece s(NULL, 10000U); }(), - std::invalid_argument); - } + { EXPECT_THROW(paddle::StringPiece s(NULL, 10000U), std::invalid_argument); } { paddle::StringPiece s(NULL); EXPECT_EQ(0U, s.len()); @@ -54,7 +54,7 @@ TEST(StringPiece, CopyAndAssign) { EXPECT_NE(a.data(), c.data()); } -TEST(StringPiece, Comparison) { +TEST(StringPiece, Compare) { { paddle::StringPiece a("hello"); paddle::StringPiece b("world"); @@ -64,6 +64,8 @@ TEST(StringPiece, Comparison) { EXPECT_TRUE(a <= b); EXPECT_FALSE(a > b); EXPECT_FALSE(a >= b); + EXPECT_LT(Compare(a, b), 0); + EXPECT_GT(Compare(b, a), 0); } { paddle::StringPiece a, b; @@ -73,5 +75,219 @@ TEST(StringPiece, Comparison) { EXPECT_FALSE(a > b); EXPECT_TRUE(a <= b); EXPECT_TRUE(a >= b); + EXPECT_EQ(0, Compare(a, b)); + EXPECT_EQ(0, Compare(b, a)); + } +} + +TEST(StringPiece, ToString) { + { + paddle::StringPiece s; + EXPECT_EQ(std::string(""), s.ToString()); + } + { + paddle::StringPiece s(NULL); + EXPECT_EQ(std::string(""), s.ToString()); + } + { + paddle::StringPiece s("hello"); + EXPECT_EQ(std::string("hello"), s.ToString()); + } +} + +TEST(StringPiece, HasPrefixSuffix) { + using paddle::HasPrefix; + using paddle::HasSuffix; + { + paddle::StringPiece s; + EXPECT_FALSE(HasPrefix(s, "something")); + EXPECT_TRUE(HasPrefix(s, "")); + EXPECT_FALSE(HasSuffix(s, "something")); + EXPECT_TRUE(HasSuffix(s, "")); + } + { + paddle::StringPiece s("app"); + EXPECT_TRUE(HasPrefix(s, "")); + EXPECT_TRUE(HasPrefix(s, "a")); + EXPECT_TRUE(HasPrefix(s, "ap")); + EXPECT_TRUE(HasPrefix(s, "app")); + + EXPECT_TRUE(HasSuffix(s, "")); + EXPECT_TRUE(HasSuffix(s, "p")); + EXPECT_TRUE(HasSuffix(s, "pp")); + EXPECT_TRUE(HasSuffix(s, "app")); } } + +TEST(StringPiece, SkipPrefixSuffix) { + using paddle::SkipPrefix; + using paddle::SkipSuffix; + { + paddle::StringPiece s; + EXPECT_EQ("", SkipPrefix(s, 0)); + EXPECT_THROW(SkipPrefix(s, 1), std::invalid_argument); + + EXPECT_EQ("", SkipSuffix(s, 0)); + EXPECT_THROW(SkipSuffix(s, 1), std::invalid_argument); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ("app", SkipPrefix(s, 0)); + EXPECT_EQ("pp", SkipPrefix(s, 1)); + EXPECT_EQ("p", SkipPrefix(s, 2)); + EXPECT_EQ("", SkipPrefix(s, 3)); + EXPECT_THROW(SkipPrefix(s, 4), std::invalid_argument); + + EXPECT_EQ("app", SkipSuffix(s, 0)); + EXPECT_EQ("ap", SkipSuffix(s, 1)); + EXPECT_EQ("a", SkipSuffix(s, 2)); + EXPECT_EQ("", SkipSuffix(s, 3)); + EXPECT_THROW(SkipSuffix(s, 4), std::invalid_argument); + } +} + +TEST(StringPiece, TrimPrefixSuffix) { + using paddle::TrimPrefix; + using paddle::TrimSuffix; + { + paddle::StringPiece s; + EXPECT_EQ("", TrimPrefix(s, "")); + EXPECT_EQ("", TrimPrefix(s, "something")); + + EXPECT_EQ("", TrimSuffix(s, "")); + EXPECT_EQ("", TrimSuffix(s, "something")); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ("app", TrimPrefix(s, "")); + EXPECT_EQ("pp", TrimPrefix(s, "a")); + EXPECT_EQ("p", TrimPrefix(s, "ap")); + EXPECT_EQ("", TrimPrefix(s, "app")); + EXPECT_EQ("app", TrimPrefix(s, "something")); + + EXPECT_EQ("app", TrimSuffix(s, "")); + EXPECT_EQ("ap", TrimSuffix(s, "p")); + EXPECT_EQ("a", TrimSuffix(s, "pp")); + EXPECT_EQ("", TrimSuffix(s, "app")); + EXPECT_EQ("app", TrimSuffix(s, "something")); + } +} + +TEST(StringPiece, Contains) { + using paddle::Contains; + { + paddle::StringPiece s; + EXPECT_FALSE(Contains(s, "")); + EXPECT_FALSE(Contains(s, "something")); + } + { + paddle::StringPiece s("app"); + EXPECT_TRUE(Contains(s, "")); + EXPECT_TRUE(Contains(s, "a")); + EXPECT_TRUE(Contains(s, "p")); + EXPECT_TRUE(Contains(s, "ap")); + EXPECT_TRUE(Contains(s, "pp")); + EXPECT_TRUE(Contains(s, "app")); + EXPECT_FALSE(Contains(s, "something")); + } +} + +TEST(StringPiece, Index) { + using paddle::Index; + auto npos = paddle::StringPiece::npos; + { + paddle::StringPiece s; + EXPECT_EQ(npos, Index(s, "")); + EXPECT_EQ(npos, Index(s, "something")); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ(0U, Index(s, "")); + EXPECT_EQ(0U, Index(s, "a")); + EXPECT_EQ(1U, Index(s, "p")); + EXPECT_EQ(0U, Index(s, "ap")); + EXPECT_EQ(1U, Index(s, "pp")); + EXPECT_EQ(0U, Index(s, "app")); + EXPECT_EQ(npos, Index(s, "something")); + } +} + +TEST(StringPiece, Find) { + using paddle::Find; + auto npos = paddle::StringPiece::npos; + { + paddle::StringPiece s; + EXPECT_EQ(npos, Find(s, 'a', 0U)); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ(0U, Find(s, 'a', 0U)); + EXPECT_EQ(1U, Find(s, 'p', 0U)); + EXPECT_EQ(1U, Find(s, 'p', 1U)); + EXPECT_EQ(2U, Find(s, 'p', 2U)); + EXPECT_EQ(npos, Find(s, 'z', 2U)); + } +} + +TEST(StringPiece, RFind) { + using paddle::RFind; + auto npos = paddle::StringPiece::npos; + { + paddle::StringPiece s; + EXPECT_EQ(npos, RFind(s, 'a', 0U)); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ(2U, RFind(s, 'p', 2U)); + EXPECT_EQ(0U, RFind(s, 'a', 2U)); + EXPECT_EQ(1U, RFind(s, 'p', 1U)); + EXPECT_EQ(0U, RFind(s, 'a', 0)); + EXPECT_EQ(npos, RFind(s, 'z', 2U)); + } +} + +TEST(StringPiece, SubStr) { + using paddle::SubStr; + { + paddle::StringPiece s; + EXPECT_EQ("", SubStr(s, 0, 0)); + EXPECT_EQ("", SubStr(s, 0, 1)); + EXPECT_EQ("", SubStr(s, 1, 0)); + } + { + paddle::StringPiece s("app"); + EXPECT_EQ("", SubStr(s, 0, 0)); + EXPECT_EQ("", SubStr(s, 1, 0)); + EXPECT_EQ("", SubStr(s, 2, 0)); + EXPECT_EQ("", SubStr(s, 3, 0)); + + EXPECT_EQ("a", SubStr(s, 0, 1)); + EXPECT_EQ("p", SubStr(s, 1, 1)); + EXPECT_EQ("p", SubStr(s, 2, 1)); + EXPECT_EQ("", SubStr(s, 3, 1)); + + EXPECT_EQ("ap", SubStr(s, 0, 2)); + EXPECT_EQ("pp", SubStr(s, 1, 2)); + EXPECT_EQ("p", SubStr(s, 2, 2)); + EXPECT_EQ("", SubStr(s, 3, 2)); + + EXPECT_EQ("app", SubStr(s, 0, 3)); + EXPECT_EQ("pp", SubStr(s, 1, 3)); + EXPECT_EQ("p", SubStr(s, 2, 3)); + EXPECT_EQ("", SubStr(s, 3, 3)); + } +} + +TEST(StringPiece, StreamOutput) { + using paddle::StringPiece; + + std::stringstream o; + o << StringPiece(); + EXPECT_EQ("", o.str()); + + o << StringPiece("hello"); + EXPECT_EQ("hello", o.str()); + + o << StringPiece(); + EXPECT_EQ("hello", o.str()); +}