diff options
-rw-r--r-- | include/llvm/ADT/StringRef.h | 127 | ||||
-rw-r--r-- | unittests/ADT/StringRefTest.cpp | 59 |
2 files changed, 186 insertions, 0 deletions
diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h new file mode 100644 index 0000000..988701b --- /dev/null +++ b/include/llvm/ADT/StringRef.h @@ -0,0 +1,127 @@ +//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGREF_H +#define LLVM_ADT_STRINGREF_H + +#include <cstring> +#include <string> + +namespace llvm { + /// StringRef - Represent a constant reference to a string, i.e. a character + /// array and a length, which need not be null terminated. + /// + /// This class does not own the string data, it is expected to be used in + /// situations where the character data resides in some other buffer, whose + /// lifetime extends past that of the StringRef. For this reason, it is not in + /// general safe to store a StringRef. + class StringRef { + public: + typedef const char *iterator; + + private: + /// The start of the string, in an external buffer. + const char *Data; + + /// The length of the string. + unsigned Length; + + public: + /// @name Constructors + /// @{ + + /// Construct an empty string ref. + /*implicit*/ StringRef() : Data(0), Length(0) {} + + /// Construct a string ref from a cstring. + /*implicit*/ StringRef(const char *Str) + : Data(Str), Length(::strlen(Str)) {} + + /// Construct a string ref from a pointer and length. + /*implicit*/ StringRef(const char *_Data, unsigned _Length) + : Data(_Data), Length(_Length) {} + + /// Construct a string ref from an std::string. + /*implicit*/ StringRef(const std::string &Str) + : Data(Str.c_str()), Length(Str.length()) {} + + /// @} + /// @name Iterators + /// @{ + + iterator begin() const { return Data; } + + iterator end() const { return Data + Length; } + + /// @} + /// @name String Operations + /// @{ + + /// data - Get a pointer to the start of the string (which may not be null + /// terminated). + const char *data() const { return Data; } + + /// empty - Check if the string is empty. + bool empty() const { return Length == 0; } + + /// size - Get the string size. + unsigned size() const { return Length; } + + /// compare - Compare two strings; the result is -1, 0, or 1 if this string + /// is lexicographically less than, equal to, or greater than the \arg RHS. + int compare(const StringRef &RHS) const { + // Check the prefix for a mismatch. + if (int Res = memcmp(Data, RHS.Data, std::min(Length, RHS.Length))) + return Res < 0 ? -1 : 1; + + // Otherwise the prefixes match, so we only need to check the lengths. + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; + } + + /// str - Get the contents as an std::string. + std::string str() const { return std::string(Data, Length); } + + /// @} + /// @name Operator Overloads + /// @{ + + bool operator==(const StringRef &RHS) const { + return Length == RHS.Length && memcmp(Data, RHS.Data, Length) == 0; + } + + bool operator!=(const StringRef &RHS) const { return !(*this == RHS); } + + bool operator<(const StringRef &RHS) const { return compare(RHS) == -1; } + + bool operator<=(const StringRef &RHS) const { return compare(RHS) != 1; } + + bool operator>(const StringRef &RHS) const { return compare(RHS) == 1; } + + bool operator>=(const StringRef &RHS) const { return compare(RHS) != -1; } + + char operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// @} + /// @name Type Conversions + /// @{ + + operator std::string() const { + return str(); + } + + /// @} + }; +} + +#endif diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp new file mode 100644 index 0000000..8a2c743 --- /dev/null +++ b/unittests/ADT/StringRefTest.cpp @@ -0,0 +1,59 @@ +//===- llvm/unittest/ADT/StringRefTest.cpp - StringRef unit tests ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/StringRef.h" +using namespace llvm; + +namespace { + +TEST(StringRefTest, Construction) { + EXPECT_TRUE(StringRef() == ""); + EXPECT_TRUE(StringRef("hello") == "hello"); + EXPECT_TRUE(StringRef("hello world", 5) == "hello"); + EXPECT_TRUE(StringRef(std::string("hello")) == "hello"); +} + +TEST(StringRefTest, Iteration) { + StringRef S("hello"); + const char *p = "hello"; + for (const char *it = S.begin(), *ie = S.end(); it != ie; ++it, ++p) + EXPECT_TRUE(*p == *it); +} + +TEST(StringRefTest, StringOps) { + const char *p = "hello"; + EXPECT_EQ(p, StringRef(p, 0).data()); + EXPECT_TRUE(StringRef().empty()); + EXPECT_EQ((size_t) 5, StringRef("hello").size()); + EXPECT_EQ(-1, StringRef("aab").compare("aad")); + EXPECT_EQ( 0, StringRef("aab").compare("aab")); + EXPECT_EQ( 1, StringRef("aab").compare("aaa")); + EXPECT_EQ(-1, StringRef("aab").compare("aabb")); + EXPECT_EQ( 1, StringRef("aab").compare("aa")); +} + +TEST(StringRefTest, Operators) { + EXPECT_TRUE(StringRef() == ""); + EXPECT_TRUE(StringRef("aab") < StringRef("aad")); + EXPECT_FALSE(StringRef("aab") < StringRef("aab")); + EXPECT_TRUE(StringRef("aab") <= StringRef("aab")); + EXPECT_FALSE(StringRef("aab") <= StringRef("aaa")); + EXPECT_TRUE(StringRef("aad") > StringRef("aab")); + EXPECT_FALSE(StringRef("aab") > StringRef("aab")); + EXPECT_TRUE(StringRef("aab") >= StringRef("aab")); + EXPECT_FALSE(StringRef("aaa") >= StringRef("aab")); + EXPECT_TRUE(StringRef("aab") == StringRef("aab")); + EXPECT_FALSE(StringRef("aab") == StringRef("aac")); + EXPECT_FALSE(StringRef("aab") != StringRef("aab")); + EXPECT_TRUE(StringRef("aab") != StringRef("aac")); + EXPECT_EQ('a', StringRef("aab")[1]); +} + +} // end anonymous namespace |