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:
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 {
KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access.");
return ptr[index];
......@@ -1294,8 +1294,8 @@ public:
inline T* end() { return ptr + size_; }
inline T& front() { return *ptr; }
inline T& back() { return *(ptr + size_ - 1); }
inline const T* begin() const { return ptr; }
inline const T* end() const { return ptr + size_; }
inline constexpr const T* begin() const { return ptr; }
inline constexpr const T* end() const { return ptr + size_; }
inline const T& front() const { return *ptr; }
inline const T& back() const { return *(ptr + size_ - 1); }
......
......@@ -173,6 +173,18 @@ TEST(String, ToString) {
}
#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 _ (private)
} // namespace kj
......@@ -31,11 +31,29 @@
#include <string.h>
namespace kj {
class StringPtr;
class String;
class StringPtr;
class String;
class StringTree; // string-tree.h
}
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
// we'll just preprocess it out if not supported.
......@@ -75,8 +93,8 @@ public:
// those who don't want it.
#endif
inline operator ArrayPtr<const char>() const;
inline ArrayPtr<const char> asArray() const;
inline constexpr operator ArrayPtr<const char>() const;
inline constexpr ArrayPtr<const char> asArray() const;
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
// Result does not include NUL terminator.
......@@ -121,9 +139,11 @@ public:
// Overflowed floating numbers return inf.
private:
inline StringPtr(ArrayPtr<const char> content): content(content) {}
inline constexpr StringPtr(ArrayPtr<const char> content): content(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; }
......@@ -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::operator ArrayPtr<const char>() const {
return content.slice(0, content.size() - 1);
inline constexpr StringPtr::operator ArrayPtr<const char>() const {
return ArrayPtr<const char>(content.begin(), content.size() - 1);
}
inline ArrayPtr<const char> StringPtr::asArray() const {
return content.slice(0, content.size() - 1);
inline constexpr ArrayPtr<const char> StringPtr::asArray() const {
return ArrayPtr<const char>(content.begin(), content.size() - 1);
}
inline bool StringPtr::operator==(const StringPtr& other) const {
......@@ -531,4 +551,8 @@ inline String heapString(ArrayPtr<const char> value) {
} // 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_
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