Commit 8777008e authored by Kenton Varda's avatar Kenton Varda

Implement _kj suffix for string literals.

E.g.:

    "foo"_kj

This literal will have type StringPtr. Although any string literal can implicitly cast to StringPtr, using the _kj suffix has the advantage that it can be constexpr.
parent 2e066e16
...@@ -1280,7 +1280,7 @@ public: ...@@ -1280,7 +1280,7 @@ public:
return ArrayPtr<const T>(ptr, size_); return ArrayPtr<const T>(ptr, size_);
} }
inline size_t size() const { return size_; } inline constexpr size_t size() const { return size_; }
inline const T& operator[](size_t index) const { inline const T& operator[](size_t index) const {
KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access.");
return ptr[index]; return ptr[index];
...@@ -1294,8 +1294,8 @@ public: ...@@ -1294,8 +1294,8 @@ public:
inline T* end() { return ptr + size_; } inline T* end() { return ptr + size_; }
inline T& front() { return *ptr; } inline T& front() { return *ptr; }
inline T& back() { return *(ptr + size_ - 1); } inline T& back() { return *(ptr + size_ - 1); }
inline const T* begin() const { return ptr; } inline constexpr const T* begin() const { return ptr; }
inline const T* end() const { return ptr + size_; } inline constexpr const T* end() const { return ptr + size_; }
inline const T& front() const { return *ptr; } inline const T& front() const { return *ptr; }
inline const T& back() const { return *(ptr + size_ - 1); } inline const T& back() const { return *(ptr + size_ - 1); }
......
...@@ -173,6 +173,18 @@ TEST(String, ToString) { ...@@ -173,6 +173,18 @@ TEST(String, ToString) {
} }
#endif #endif
KJ_TEST("string literals with _kj suffix") {
static constexpr StringPtr FOO = "foo"_kj;
KJ_EXPECT(FOO == "foo", FOO);
KJ_EXPECT(FOO[3] == 0);
KJ_EXPECT("foo\0bar"_kj == StringPtr("foo\0bar", 7));
static constexpr ArrayPtr<const char> ARR = "foo"_kj;
KJ_EXPECT(ARR.size() == 3);
KJ_EXPECT(kj::str(ARR) == "foo");
}
} // namespace } // namespace
} // namespace _ (private) } // namespace _ (private)
} // namespace kj } // namespace kj
...@@ -31,11 +31,29 @@ ...@@ -31,11 +31,29 @@
#include <string.h> #include <string.h>
namespace kj { namespace kj {
class StringPtr;
class String;
class StringPtr; class StringTree; // string-tree.h
class String; }
class StringTree; // string-tree.h constexpr kj::StringPtr operator "" _kj(const char* str, size_t n);
// You can append _kj to a string literal to make its type be StringPtr. There are a few cases
// where you must do this for correctness:
// - When you want to declare a constexpr StringPtr. Without _kj, this is a compile error.
// - When you want to initialize a static/global StringPtr from a string literal without forcing
// global constructor code to run at dynamic initialization time.
// - When you have a string literal that contains NUL characters. Without _kj, the string will
// be considered to end at the first NUL.
// - When you want to initialize an ArrayPtr<const char> from a string literal, without including
// the NUL terminator in the data. (Initializing an ArrayPtr from a regular string literal is
// a compile error specifically due to this ambiguity.)
//
// In other cases, there should be no difference between initializing a StringPtr from a regular
// string literal vs. one with _kj (assuming the compiler is able to optimize away strlen() on a
// string literal).
namespace kj {
// Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so // Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so
// we'll just preprocess it out if not supported. // we'll just preprocess it out if not supported.
...@@ -75,8 +93,8 @@ public: ...@@ -75,8 +93,8 @@ public:
// those who don't want it. // those who don't want it.
#endif #endif
inline operator ArrayPtr<const char>() const; inline constexpr operator ArrayPtr<const char>() const;
inline ArrayPtr<const char> asArray() const; inline constexpr ArrayPtr<const char> asArray() const;
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); } inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
// Result does not include NUL terminator. // Result does not include NUL terminator.
...@@ -121,9 +139,11 @@ public: ...@@ -121,9 +139,11 @@ public:
// Overflowed floating numbers return inf. // Overflowed floating numbers return inf.
private: private:
inline StringPtr(ArrayPtr<const char> content): content(content) {} inline constexpr StringPtr(ArrayPtr<const char> content): content(content) {}
ArrayPtr<const char> content; ArrayPtr<const char> content;
friend constexpr kj::StringPtr (::operator "" _kj)(const char* str, size_t n);
}; };
inline bool operator==(const char* a, const StringPtr& b) { return b == a; } inline bool operator==(const char* a, const StringPtr& b) { return b == a; }
...@@ -427,12 +447,12 @@ inline String Stringifier::operator*(const Array<T>& arr) const { ...@@ -427,12 +447,12 @@ inline String Stringifier::operator*(const Array<T>& arr) const {
inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {} inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {}
inline StringPtr::operator ArrayPtr<const char>() const { inline constexpr StringPtr::operator ArrayPtr<const char>() const {
return content.slice(0, content.size() - 1); return ArrayPtr<const char>(content.begin(), content.size() - 1);
} }
inline ArrayPtr<const char> StringPtr::asArray() const { inline constexpr ArrayPtr<const char> StringPtr::asArray() const {
return content.slice(0, content.size() - 1); return ArrayPtr<const char>(content.begin(), content.size() - 1);
} }
inline bool StringPtr::operator==(const StringPtr& other) const { inline bool StringPtr::operator==(const StringPtr& other) const {
...@@ -531,4 +551,8 @@ inline String heapString(ArrayPtr<const char> value) { ...@@ -531,4 +551,8 @@ inline String heapString(ArrayPtr<const char> value) {
} // namespace kj } // namespace kj
constexpr kj::StringPtr operator "" _kj(const char* str, size_t n) {
return kj::StringPtr(kj::ArrayPtr<const char>(str, n + 1));
};
#endif // KJ_STRING_H_ #endif // KJ_STRING_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment