| @ -0,0 +1,186 @@ | |||||
| // Copyright (C) 2011 Google Inc. | |||||
| // | |||||
| // 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. | |||||
| // Author: Philippe Liard | |||||
| #include <cassert> | |||||
| #include <cstring> | |||||
| #include <sstream> | |||||
| #include "stringutil.h" | |||||
| namespace i18n { | |||||
| namespace phonenumbers { | |||||
| using std::stringstream; | |||||
| string operator+(const string& s, int n) { | |||||
| stringstream ss; | |||||
| ss << s << n; | |||||
| string result; | |||||
| ss >> result; | |||||
| return result; | |||||
| } | |||||
| string SimpleItoa(int n) { | |||||
| stringstream ss; | |||||
| ss << n; | |||||
| string result; | |||||
| ss >> result; | |||||
| return result; | |||||
| } | |||||
| bool TryStripPrefixString(const string& in, const string& prefix, string* out) { | |||||
| assert(out); | |||||
| const bool has_prefix = in.compare(0, prefix.length(), prefix) == 0; | |||||
| out->assign(has_prefix ? in.substr(prefix.length()) : in); | |||||
| return has_prefix; | |||||
| } | |||||
| bool HasSuffixString(const string& s, const string& suffix) { | |||||
| if (s.length() < suffix.length()) { | |||||
| return false; | |||||
| } | |||||
| return s.compare(s.length() - suffix.length(), suffix.length(), suffix) == 0; | |||||
| } | |||||
| // StringHolder class | |||||
| StringHolder::StringHolder(const string& s) : | |||||
| string_(&s), | |||||
| cstring_(NULL), | |||||
| len_(s.size()) | |||||
| {} | |||||
| StringHolder::StringHolder(const char* s) : | |||||
| string_(NULL), | |||||
| cstring_(s), | |||||
| len_(std::strlen(s)) | |||||
| {} | |||||
| StringHolder::~StringHolder() {} | |||||
| // StrCat | |||||
| // Implement s += sh; (s: string, sh: StringHolder) | |||||
| string& operator+=(string& lhs, const StringHolder& rhs) { | |||||
| const string* const s = rhs.GetString(); | |||||
| if (s) { | |||||
| lhs += *s; | |||||
| } else { | |||||
| const char* const cs = rhs.GetCString(); | |||||
| if (cs) | |||||
| lhs.append(cs, rhs.Length()); | |||||
| } | |||||
| return lhs; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + 1); | |||||
| result += s1; | |||||
| result += s2; | |||||
| return result; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + s3.Length() + 1); | |||||
| result += s1; | |||||
| result += s2; | |||||
| result += s3; | |||||
| return result; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() + 1); | |||||
| result += s1; | |||||
| result += s2; | |||||
| result += s3; | |||||
| result += s4; | |||||
| return result; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() + | |||||
| s5.Length() + 1); | |||||
| result += s1; | |||||
| result += s2; | |||||
| result += s3; | |||||
| result += s4; | |||||
| result += s5; | |||||
| return result; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5, const StringHolder& s6) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() + | |||||
| s5.Length() + s6.Length() + 1); | |||||
| result += s1; | |||||
| result += s2; | |||||
| result += s3; | |||||
| result += s4; | |||||
| result += s5; | |||||
| result += s6; | |||||
| return result; | |||||
| } | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5, const StringHolder& s6, | |||||
| const StringHolder& s7, const StringHolder& s8, | |||||
| const StringHolder& s9, const StringHolder& s10, | |||||
| const StringHolder& s11) { | |||||
| string result; | |||||
| result.reserve(s1.Length() + s2.Length() + s3.Length() + s4.Length() + | |||||
| s5.Length() + s6.Length() + s7.Length() + s8.Length() + | |||||
| s9.Length() + s10.Length() + s11.Length()); | |||||
| result += s1; | |||||
| result += s2; | |||||
| result += s3; | |||||
| result += s4; | |||||
| result += s5; | |||||
| result += s6; | |||||
| result += s7; | |||||
| result += s8; | |||||
| result += s9; | |||||
| result += s10; | |||||
| result += s11; | |||||
| return result; | |||||
| } | |||||
| } // namespace phonenumbers | |||||
| } // namespace i18n | |||||
| @ -0,0 +1,100 @@ | |||||
| // Copyright (C) 2011 Google Inc. | |||||
| // | |||||
| // 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. | |||||
| // Author: Philippe Liard | |||||
| #ifndef I18N_PHONENUMBERS_STRINGUTIL_H_ | |||||
| #define I18N_PHONENUMBERS_STRINGUTIL_H_ | |||||
| #include <cstddef> | |||||
| #include <string> | |||||
| namespace i18n { | |||||
| namespace phonenumbers { | |||||
| using std::string; | |||||
| // Support string("hello") + 10 | |||||
| string operator+(const string& s, int n); | |||||
| // Convert integer into string | |||||
| string SimpleItoa(int n); | |||||
| // Return true if 'in' starts with 'prefix' and write into 'out' | |||||
| // 'in' minus 'prefix' | |||||
| bool TryStripPrefixString(const string& in, const string& prefix, string* out); | |||||
| // Return true if 's' ends with 'suffix' | |||||
| bool HasSuffixString(const string& s, const string& suffix); | |||||
| // Hold a reference to a std::string or C string. | |||||
| class StringHolder { | |||||
| public: | |||||
| // Don't make the constructors explicit to make the StrCat usage convenient. | |||||
| StringHolder(const string& s); | |||||
| StringHolder(const char* s); | |||||
| ~StringHolder(); | |||||
| const string* GetString() const { | |||||
| return string_; | |||||
| } | |||||
| const char* GetCString() const { | |||||
| return cstring_; | |||||
| } | |||||
| size_t Length() const { | |||||
| return len_; | |||||
| } | |||||
| private: | |||||
| const string* const string_; | |||||
| const char* const cstring_; | |||||
| const size_t len_; | |||||
| }; | |||||
| string& operator+=(string& lhs, const StringHolder& rhs); | |||||
| // Efficient string concatenation | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2); | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3); | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4); | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5); | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5, const StringHolder& s6); | |||||
| string StrCat(const StringHolder& s1, const StringHolder& s2, | |||||
| const StringHolder& s3, const StringHolder& s4, | |||||
| const StringHolder& s5, const StringHolder& s6, | |||||
| const StringHolder& s7, const StringHolder& s8, | |||||
| const StringHolder& s9, const StringHolder& s10, | |||||
| const StringHolder& s11); | |||||
| } // namespace phonenumbers | |||||
| } // namespace i18n | |||||
| #endif // I18N_PHONENUMBERS_STRINGUTIL_H_ | |||||
| @ -0,0 +1,130 @@ | |||||
| // Copyright (C) 2011 Google Inc. | |||||
| // | |||||
| // 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. | |||||
| // Author: Philippe Liard | |||||
| #include <gtest/gtest.h> | |||||
| #include "stringutil.h" | |||||
| namespace i18n { | |||||
| namespace phonenumbers { | |||||
| // Test operator+(const string&, int) | |||||
| TEST(StringUtilTest, OperatorPlus) { | |||||
| EXPECT_EQ("hello10", string("hello") + 10); | |||||
| } | |||||
| // Test SimpleItoa implementation | |||||
| TEST(StringUtilTest, SimpleItoa) { | |||||
| EXPECT_EQ("10", SimpleItoa(10)); | |||||
| } | |||||
| // Test TryStripPrefixString | |||||
| TEST(StringUtilTest, TryStripPrefixString) { | |||||
| string s; | |||||
| EXPECT_TRUE(TryStripPrefixString("hello world", "hello", &s)); | |||||
| EXPECT_EQ(" world", s); | |||||
| s.clear(); | |||||
| EXPECT_FALSE(TryStripPrefixString("hello world", "helloa", &s)); | |||||
| s.clear(); | |||||
| EXPECT_TRUE(TryStripPrefixString("hello world", "", &s)); | |||||
| EXPECT_EQ("hello world", s); | |||||
| s.clear(); | |||||
| EXPECT_FALSE(TryStripPrefixString("", "hello", &s)); | |||||
| s.clear(); | |||||
| } | |||||
| // Test HasSuffixString | |||||
| TEST(StringUtilTest, HasSuffixString) { | |||||
| EXPECT_TRUE(HasSuffixString("hello world", "hello world")); | |||||
| EXPECT_TRUE(HasSuffixString("hello world", "world")); | |||||
| EXPECT_FALSE(HasSuffixString("hello world", "world!")); | |||||
| EXPECT_TRUE(HasSuffixString("hello world", "")); | |||||
| EXPECT_FALSE(HasSuffixString("", "hello")); | |||||
| } | |||||
| // Test the StringHolder class | |||||
| TEST(StringUtilTest, StringHolder) { | |||||
| // Test with C string | |||||
| static const char cstring[] = "aaa"; | |||||
| StringHolder sh1(cstring); | |||||
| EXPECT_EQ(cstring, sh1.GetCString()); | |||||
| EXPECT_EQ(NULL, sh1.GetString()); | |||||
| // Test with std::string | |||||
| string s = "bbb"; | |||||
| StringHolder sh2(s); | |||||
| EXPECT_EQ(NULL, sh2.GetCString()); | |||||
| EXPECT_EQ(&s, sh2.GetString()); | |||||
| // Test GetLength() | |||||
| string s2 = "hello"; | |||||
| StringHolder sh3(s2); | |||||
| EXPECT_EQ(5, sh3.Length()); | |||||
| } | |||||
| // Test the operator+=(string& lhs, const StringHolder& rhs) implementation | |||||
| TEST(StringUtilTest, OperatorPlusEquals) { | |||||
| // Test with a const char* string to append | |||||
| string s = "h"; | |||||
| static const char append1[] = "ello"; | |||||
| s += StringHolder(append1); // force StringHolder usage | |||||
| EXPECT_EQ("hello", s); | |||||
| // Test with a std::string to append | |||||
| s = "h"; | |||||
| string append2 = "ello"; | |||||
| s += StringHolder(append2); // force StringHolder usage | |||||
| EXPECT_EQ("hello", s); | |||||
| } | |||||
| // Test the StrCat implementations | |||||
| TEST(StringUtilTest, StrCat) { | |||||
| string s; | |||||
| // Test with 2 arguments | |||||
| s = StrCat("a", "b"); | |||||
| EXPECT_EQ("ab", s); | |||||
| // Test with 3 arguments | |||||
| s = StrCat("a", "b", "c"); | |||||
| EXPECT_EQ("abc", s); | |||||
| // Test with 4 arguments | |||||
| s = StrCat("a", "b", "c", "d"); | |||||
| EXPECT_EQ("abcd", s); | |||||
| // Test with 5 arguments | |||||
| s = StrCat("a", "b", "c", "d", "e"); | |||||
| EXPECT_EQ("abcde", s); | |||||
| // Test with 6 arguments | |||||
| s = StrCat("a", "b", "c", "d", "e", "f"); | |||||
| EXPECT_EQ("abcdef", s); | |||||
| // Test with 11 arguments | |||||
| s = StrCat("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"); | |||||
| EXPECT_EQ("abcdefghijk", s); | |||||
| } | |||||
| } // namespace phonenumbers | |||||
| } // namespace i18n | |||||