Commit b4953e9d authored by Kenton Varda's avatar Kenton Varda

Retrofit blob readers/builders on top of kj::ArrayPtr and kj::StringPtr.

parent 1b468272
......@@ -58,8 +58,8 @@ public:
static const char URL_PREFIX[] = "http://example.com/";
auto url = result.initUrl(urlSize + sizeof(URL_PREFIX));
strcpy(url.data(), URL_PREFIX);
char* pos = url.data() + strlen(URL_PREFIX);
strcpy(url.begin(), URL_PREFIX);
char* pos = url.begin() + strlen(URL_PREFIX);
for (int j = 0; j < urlSize; j++) {
*pos++ = 'a' + fastRand(26);
}
......@@ -85,7 +85,7 @@ public:
snippet.append(WORDS[fastRand(WORDS_COUNT)]);
}
result.setSnippet(snippet);
result.setSnippet(Text::Reader(snippet.c_str(), snippet.size()));
}
return goodCount;
......@@ -96,10 +96,10 @@ public:
for (auto result: request.getResults()) {
double score = result.getScore();
if (strstr(result.getSnippet().c_str(), " cat ") != nullptr) {
if (strstr(result.getSnippet().cStr(), " cat ") != nullptr) {
score *= 10000;
}
if (strstr(result.getSnippet().c_str(), " dog ") != nullptr) {
if (strstr(result.getSnippet().cStr(), " dog ") != nullptr) {
score /= 10000;
}
scoredResults.emplace_back(score, result);
......
......@@ -27,21 +27,21 @@
#include <string>
#include "test-util.h"
// TODO(test): This test is outdated -- it predates the retrofit of Text and Data on top of
// kj::ArrayPtr/kj::StringPtr. Clean it up.
namespace capnproto {
namespace {
TEST(Blob, Text) {
std::string str = "foo";
Text::Reader text = str;
Text::Reader text = str.c_str();
EXPECT_EQ("foo", text);
EXPECT_STREQ("foo", text.c_str());
EXPECT_STREQ("foo", text.data());
EXPECT_STREQ("foo", text.cStr());
EXPECT_STREQ("foo", text.begin());
EXPECT_EQ(3u, text.size());
std::string str2 = text.as<std::string>();
EXPECT_EQ("foo", str2);
Text::Reader text2 = "bar";
EXPECT_EQ("bar", text2);
......@@ -52,67 +52,67 @@ TEST(Blob, Text) {
Text::Builder builder(c, 3);
EXPECT_EQ("baz", builder);
EXPECT_EQ(Data::Reader("az"), builder.slice(1, 3));
EXPECT_EQ(kj::arrayPtr("az", 2), builder.slice(1, 3));
}
Data::Reader dataLit(const char* str) {
return Data::Reader(reinterpret_cast<const byte*>(str), strlen(str));
}
TEST(Blob, Data) {
std::string str = "foo";
Data::Reader data = str;
Data::Reader data = dataLit("foo");
EXPECT_EQ("foo", data);
EXPECT_EQ(dataLit("foo"), data);
EXPECT_EQ(3u, data.size());
std::string str2 = data.as<std::string>();
EXPECT_EQ("foo", str2);
Data::Reader data2 = "bar";
EXPECT_EQ("bar", data2.as<std::string>());
Data::Reader data2 = dataLit("bar");
EXPECT_EQ(dataLit("bar"), data2);
char c[4] = "baz";
Data::Reader data3(c);
EXPECT_EQ("baz", data3.as<std::string>());
byte c[4] = "baz";
Data::Reader data3(c, 3);
EXPECT_EQ(dataLit("baz"), data3);
Data::Builder builder(c, 3);
EXPECT_EQ("baz", builder.as<std::string>());
EXPECT_EQ(dataLit("baz"), builder);
EXPECT_EQ(Data::Reader("az"), builder.slice(1, 3));
EXPECT_EQ(dataLit("az"), builder.slice(1, 3));
}
TEST(Blob, Compare) {
EXPECT_TRUE (Data::Reader("foo") == Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") != Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foo") <= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foo") >= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") < Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") == Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") != Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("foo") <= Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") >= Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("foo") < Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") > Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("bar") == Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") != Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") <= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("bar") >= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") < Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("bar") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") == Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") != Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") <= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") >= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") < Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") == Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") != Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") <= Data::Reader("foobar"));
EXPECT_FALSE(Data::Reader("foo") >= Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") < Data::Reader("foobar"));
EXPECT_FALSE(Data::Reader("foo") > Data::Reader("foobar"));
EXPECT_TRUE (Text::Reader("foo") == Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foo") != Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("foo") <= Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("foo") >= Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foo") < Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foo") > Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foo") == Text::Reader("bar"));
EXPECT_TRUE (Text::Reader("foo") != Text::Reader("bar"));
EXPECT_FALSE(Text::Reader("foo") <= Text::Reader("bar"));
EXPECT_TRUE (Text::Reader("foo") >= Text::Reader("bar"));
EXPECT_FALSE(Text::Reader("foo") < Text::Reader("bar"));
EXPECT_TRUE (Text::Reader("foo") > Text::Reader("bar"));
EXPECT_FALSE(Text::Reader("bar") == Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("bar") != Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("bar") <= Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("bar") >= Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("bar") < Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("bar") > Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foobar") == Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("foobar") != Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foobar") <= Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("foobar") >= Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foobar") < Text::Reader("foo"));
EXPECT_TRUE (Text::Reader("foobar") > Text::Reader("foo"));
EXPECT_FALSE(Text::Reader("foo") == Text::Reader("foobar"));
EXPECT_TRUE (Text::Reader("foo") != Text::Reader("foobar"));
EXPECT_TRUE (Text::Reader("foo") <= Text::Reader("foobar"));
EXPECT_FALSE(Text::Reader("foo") >= Text::Reader("foobar"));
EXPECT_TRUE (Text::Reader("foo") < Text::Reader("foobar"));
EXPECT_FALSE(Text::Reader("foo") > Text::Reader("foobar"));
}
} // namespace
......
......@@ -41,204 +41,139 @@ struct Text {
class Builder;
};
template <size_t size>
struct InlineData: public Data {};
// Alias for Data used specifically for InlineData fields. This primarily exists so that
// List<InlineData<n>> can be specialized.
class Data::Reader {
class Data::Reader: public kj::ArrayPtr<const byte> {
// Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple
// pointer which does not own its target, can be passed by value, etc.
//
// Data::Reader can be implicitly converted to any type which has a constructor that takes a
// (const char*, size) pair, and can be implicitly constructed from any type that has data()
// and size() methods. Many types follow this pattern, such as std::string. Data::Reader can
// also be implicitly constructed from a NUL-terminated char*.
public:
typedef Data Reads;
inline Reader(): bytes(nullptr), size_(0) {}
inline Reader(const char* bytes): bytes(bytes), size_(strlen(bytes)) {}
inline Reader(char* bytes): bytes(bytes), size_(strlen(bytes)) {}
inline Reader(const char* bytes, uint size): bytes(bytes), size_(size) {}
template <typename T>
inline Reader(const T& other): bytes(other.data()), size_(other.size()) {}
// Primarily intended for converting from std::string.
template <typename T>
inline T as() const { return T(bytes, size_); }
// Explicitly converts to the desired type, which must have a (const char*, size) constructor.
inline const char* data() const { return bytes; }
inline uint size() const { return size_; }
inline const char operator[](uint index) const { return bytes[index]; }
inline Reader slice(uint start, uint end) const {
KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds slice.");
return Reader(bytes + start, end - start);
}
inline bool operator==(const Reader& other) const {
return size_ == other.size_ && memcmp(bytes, other.bytes, size_) == 0;
}
inline bool operator<=(const Reader& other) const {
bool shorter = size_ <= other.size_;
int cmp = memcmp(bytes, other.bytes, shorter ? size_ : other.size_);
return cmp < 0 ? true : cmp > 0 ? false : size_ <= other.size_;
}
inline bool operator!=(const Reader& other) const { return !(*this == other); }
inline bool operator>=(const Reader& other) const { return other <= *this; }
inline bool operator< (const Reader& other) const { return !(other <= *this); }
inline bool operator> (const Reader& other) const { return !(*this <= other); }
inline const char* begin() const { return bytes; }
inline const char* end() const { return bytes + size_; }
private:
const char* bytes;
uint size_;
Reader() = default;
inline Reader(decltype(nullptr)): ArrayPtr<const byte>(nullptr) {}
inline Reader(const byte* value, size_t size): ArrayPtr<const byte>(value, size) {}
inline Reader(const kj::Array<const byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const ArrayPtr<const byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const kj::Array<byte>& value): ArrayPtr<const byte>(value) {}
inline Reader(const ArrayPtr<byte>& value): ArrayPtr<const byte>(value) {}
};
class Text::Reader: public Data::Reader {
class Text::Reader: public kj::StringPtr {
// Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted
// in the size but must be present immediately after the last byte.
//
// Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of
// the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD
// also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares.
//
// Text::Reader can be implicitly converted to and from const char*. Additionally, it can be
// implicitly converted to any type that can be constructed from a (const char*, size) pair, as
// well as from any type which has c_str() and size() methods. Many types follow this pattern,
// such as std::string.
public:
typedef Text Reads;
inline Reader(): Data::Reader("", 0) {}
inline Reader(const char* text): Data::Reader(text, strlen(text)) {}
inline Reader(char* text): Data::Reader(text, strlen(text)) {}
inline Reader(const char* text, uint size): Data::Reader(text, size) {
KJ_IREQUIRE(text[size] == '\0', "Text must be NUL-terminated.");
}
template <typename T>
inline Reader(const T& other): Data::Reader(other.c_str(), other.size()) {
// Primarily intended for converting from std::string.
KJ_IREQUIRE(data()[size()] == '\0', "Text must be NUL-terminated.");
}
inline const char* c_str() const { return data(); }
inline operator const char*() const { return data(); }
Reader() = default;
inline Reader(decltype(nullptr)): StringPtr(nullptr) {}
inline Reader(const char* value): StringPtr(value) {}
inline Reader(const char* value, size_t size): StringPtr(value, size) {}
inline Reader(const kj::String& value): StringPtr(value) {}
inline Reader(const StringPtr& value): StringPtr(value) {}
};
inline kj::StringPtr KJ_STRINGIFY(Text::Reader reader) {
// TODO(soon): Use size().
return reader.c_str();
}
class Data::Builder {
// Like Data::Reader except the pointers aren't const, and it can't be implicitly constructed from
// other types.
class Data::Builder: public kj::ArrayPtr<byte> {
// Like Data::Reader except the pointers aren't const.
public:
typedef Data Builds;
inline Builder(): bytes(nullptr), size_(0) {}
inline Builder(char* bytes, uint size): bytes(bytes), size_(size) {}
template <typename T>
inline operator T() const { return T(bytes, size_); }
// Primarily intended for converting to std::string.
Builder() = default;
inline Builder(decltype(nullptr)): ArrayPtr<byte>(nullptr) {}
inline Builder(byte* value, size_t size): ArrayPtr<byte>(value, size) {}
inline Builder(kj::Array<byte>& value): ArrayPtr<byte>(value) {}
inline Builder(const ArrayPtr<byte>& value): ArrayPtr<byte>(value) {}
inline operator Data::Reader() const { return Data::Reader(bytes, size_); }
template <typename T>
inline T as() const { return T(bytes, size_); }
// Explicitly converts to the desired type, which must have a (char*, size) constructor.
inline Data::Reader asReader() const { return Data::Reader(*this); }
};
inline char* data() const { return bytes; }
inline uint size() const { return size_; }
inline char& operator[](uint index) const { return bytes[index]; }
class Text::Builder {
// Basically identical to kj::StringPtr, except that the contents are non-const.
inline Builder slice(uint start, uint end) const {
KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds slice.");
return Builder(bytes + start, end - start);
public:
inline Builder(): content(nulstr, 1) {}
inline Builder(decltype(nullptr)): content(nulstr, 1) {}
inline Builder(char* value): content(value, strlen(value) + 1) {}
inline Builder(char* value, size_t size): content(value, size + 1) {
KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated.");
}
inline bool operator==(const Builder& other) const {
return size_ == other.size_ && memcmp(bytes, other.bytes, size_) == 0;
}
inline bool operator<=(const Builder& other) const {
bool shorter = size_ <= other.size_;
int cmp = memcmp(bytes, other.bytes, shorter ? size_ : other.size_);
return cmp < 0 ? true : cmp > 0 ? false : size_ <= other.size_;
}
inline bool operator!=(const Builder& other) const { return !(*this == other); }
inline bool operator>=(const Builder& other) const { return other <= *this; }
inline bool operator< (const Builder& other) const { return !(other <= *this); }
inline bool operator> (const Builder& other) const { return !(*this <= other); }
template <typename T>
inline void copyFrom(const T& other) const {
KJ_IREQUIRE(size() == other.size(), "Sizes must match to copy.");
memcpy(bytes, other.data(), other.size());
}
inline void copyFrom(const void* other) const {
memcpy(bytes, other, size_);
}
inline Reader asReader() const { return Reader(content.begin(), content.size()); }
inline char* begin() const { return bytes; }
inline char* end() const { return bytes + size_; }
inline operator kj::ArrayPtr<char>() const;
inline kj::ArrayPtr<char> asArray() const;
// Result does not include NUL terminator.
inline Data::Reader asReader() { return Data::Reader(bytes, size_); }
inline operator kj::StringPtr() const;
inline kj::StringPtr asString() const;
private:
char* bytes;
uint size_;
};
inline const char* cStr() const { return content.begin(); }
// Returns NUL-terminated string.
class Text::Builder: public Data::Builder {
// Like Text::Reader except the pointers aren't const, and it can't be implicitly constructed from
// other types. The Text::Builder automatically initializes the NUL terminator at construction,
// so it is never necessary for the caller to do so.
inline size_t size() const { return content.size() - 1; }
// Result does not include NUL terminator.
public:
typedef Text Builds;
inline char operator[](size_t index) const { return content[index]; }
inline char* begin() const { return content.begin(); }
inline char* end() const { return content.end() - 1; }
inline Builder(): Data::Builder(nulstr, 0) {}
inline Builder(char* text, uint size): Data::Builder(text, size) { text[size] = '\0'; }
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
inline char* c_str() const { return data(); }
inline operator char*() const { return data(); }
inline operator const char*() const { return data(); }
inline bool operator==(Builder other) const { return asString() == other.asString(); }
inline bool operator!=(Builder other) const { return asString() == other.asString(); }
inline bool operator< (Builder other) const { return asString() < other.asString(); }
inline bool operator> (Builder other) const { return asString() > other.asString(); }
inline bool operator<=(Builder other) const { return asString() <= other.asString(); }
inline bool operator>=(Builder other) const { return asString() >= other.asString(); }
inline Text::Reader asReader() { return Text::Reader(begin(), size()); }
inline Builder slice(size_t start) const;
inline kj::ArrayPtr<char> slice(size_t start, size_t end) const;
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
// version that assumes end = size().
private:
inline explicit Builder(kj::ArrayPtr<char> content): content(content) {}
kj::ArrayPtr<char> content;
static char nulstr[1];
};
inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) {
// TODO(soon): Use size().
return builder.c_str();
return builder.asString();
}
inline bool operator==(const char* a, Data::Reader b) { return Data::Reader(a) == b; }
inline bool operator==(const char* a, Data::Builder b) { return Data::Reader(a) == (Data::Reader)b; }
inline bool operator==(Data::Reader a, Data::Builder b) { return a == (Data::Reader)b; }
inline bool operator==(Data::Builder a, Data::Reader b) { return (Data::Reader)a == b; }
template <typename T>
T& operator<<(T& os, Data::Reader value) { return os.write(value.data(), value.size()); }
template <typename T>
T& operator<<(T& os, Data::Builder value) { return os.write(value.data(), value.size()); }
template <typename T>
T& operator<<(T& os, Text::Reader value) { return os.write(value.data(), value.size()); }
template <typename T>
T& operator<<(T& os, Text::Builder value) { return os.write(value.data(), value.size()); }
inline bool operator==(const char* a, const Text::Builder& b) { return a == b.asString(); }
inline bool operator!=(const char* a, const Text::Builder& b) { return a != b.asString(); }
inline Text::Builder::operator kj::StringPtr() const {
return kj::StringPtr(content.begin(), content.size() - 1);
}
inline kj::StringPtr Text::Builder::asString() const {
return kj::StringPtr(content.begin(), content.size() - 1);
}
inline Text::Builder::operator kj::ArrayPtr<char>() const {
return content.slice(0, content.size() - 1);
}
inline kj::ArrayPtr<char> Text::Builder::asArray() const {
return content.slice(0, content.size() - 1);
}
inline Text::Builder Text::Builder::slice(size_t start) const {
return Text::Builder(content.slice(start, content.size()));
}
inline kj::ArrayPtr<char> Text::Builder::slice(size_t start, size_t end) const {
return content.slice(start, end);
}
} // namespace capnproto
......
......@@ -490,7 +490,7 @@ Text::Builder DynamicStruct::Builder::getObjectAsText(StructSchema::Member membe
auto field = member.getProto().getBody().getFieldMember();
KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return getObjectAsDataImpl(builder, member);
return getObjectAsTextImpl(builder, member);
}
}
......@@ -565,7 +565,7 @@ Text::Builder DynamicStruct::Builder::initObjectAsText(StructSchema::Member memb
auto field = member.getProto().getBody().getFieldMember();
KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return initFieldAsDataImpl(builder, member, size);
return initFieldAsTextImpl(builder, member, size);
}
}
......@@ -627,7 +627,7 @@ Text::Builder DynamicStruct::Builder::getObjectAsText(Text::Reader name) {
return getObjectAsText(schema.getMemberByName(name));
}
Data::Builder DynamicStruct::Builder::getObjectAsData(Text::Reader name) {
return getObjectAsText(schema.getMemberByName(name));
return getObjectAsData(schema.getMemberByName(name));
}
DynamicStruct::Builder DynamicStruct::Builder::initObject(
Text::Reader name, StructSchema type) {
......@@ -641,7 +641,7 @@ Text::Builder DynamicStruct::Builder::initObjectAsText(Text::Reader name, uint s
return initObjectAsText(schema.getMemberByName(name), size);
}
Data::Builder DynamicStruct::Builder::initObjectAsData(Text::Reader name, uint size) {
return initObjectAsText(schema.getMemberByName(name), size);
return initObjectAsData(schema.getMemberByName(name), size);
}
DynamicValue::Reader DynamicStruct::Reader::getImpl(
......@@ -691,14 +691,14 @@ DynamicValue::Reader DynamicStruct::Reader::getImpl(
Text::Reader typedDval = dval.getTextValue();
return DynamicValue::Reader(
reader.getBlobField<Text>(field.getOffset() * POINTERS,
typedDval.data(), typedDval.size() * BYTES));
typedDval.begin(), typedDval.size() * BYTES));
}
case schema::Type::Body::DATA_TYPE: {
Data::Reader typedDval = dval.getDataValue();
return DynamicValue::Reader(
reader.getBlobField<Data>(field.getOffset() * POINTERS,
typedDval.data(), typedDval.size() * BYTES));
typedDval.begin(), typedDval.size() * BYTES));
}
case schema::Type::Body::LIST_TYPE: {
......@@ -783,14 +783,14 @@ DynamicValue::Builder DynamicStruct::Builder::getImpl(
Text::Reader typedDval = dval.getTextValue();
return DynamicValue::Builder(
builder.getBlobField<Text>(field.getOffset() * POINTERS,
typedDval.data(), typedDval.size() * BYTES));
typedDval.begin(), typedDval.size() * BYTES));
}
case schema::Type::Body::DATA_TYPE: {
Data::Reader typedDval = dval.getDataValue();
return DynamicValue::Builder(
builder.getBlobField<Data>(field.getOffset() * POINTERS,
typedDval.data(), typedDval.size() * BYTES));
typedDval.begin(), typedDval.size() * BYTES));
}
case schema::Type::Body::LIST_TYPE: {
......@@ -1457,6 +1457,7 @@ BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder buil
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(data, DATA, Data)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
......@@ -1465,27 +1466,6 @@ HANDLE_TYPE(union, UNION, DynamicUnion)
#undef HANDLE_TYPE
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(Reader reader) {
if (reader.type == TEXT) {
// Implicitly convert from text.
return reader.textValue;
}
KJ_REQUIRE(reader.type == DATA, "Type mismatch when using DynamicValue::Reader::as().") {
return Data::Reader();
}
return reader.dataValue;
}
Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder builder) {
if (builder.type == TEXT) {
// Implicitly convert from text.
return builder.textValue;
}
KJ_REQUIRE(builder.type == DATA, "Type mismatch when using DynamicValue::Builder::as().") {
return Data::Builder();
}
return builder.dataValue;
}
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
Void DynamicValue::Reader::AsImpl<Void>::apply(Reader reader) {
KJ_REQUIRE(reader.type == VOID, "Type mismatch when using DynamicValue::Reader::as().") {
......
......@@ -556,7 +556,6 @@ public:
// - Integers can be converted to floating points. This may lose information, but won't throw.
// - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose
// information, but won't throw.
// - Text can be converted to Data (but not vice-versa).
// - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
// vice-versa).
//
......
......@@ -148,9 +148,9 @@ TEST(Encoding, GenericObjects) {
EXPECT_EQ("foo", root.getObjectField<Text>());
EXPECT_EQ("foo", root.asReader().getObjectField<Text>());
root.setObjectField<Data>("foo");
EXPECT_EQ("foo", root.getObjectField<Data>());
EXPECT_EQ("foo", root.asReader().getObjectField<Data>());
root.setObjectField<Data>(data("foo"));
EXPECT_EQ(data("foo"), root.getObjectField<Data>());
EXPECT_EQ(data("foo"), root.asReader().getObjectField<Data>());
{
root.setObjectField<List<uint32_t>>({123, 456, 789});
......
......@@ -1226,7 +1226,8 @@ struct WireHelpers {
static KJ_ALWAYS_INLINE(void setTextPointer(
WirePointer* ref, SegmentBuilder* segment, Text::Reader value)) {
initTextPointer(ref, segment, value.size() * BYTES).copyFrom(value);
memcpy(initTextPointer(ref, segment, value.size() * BYTES).begin(),
value.begin(), value.size());
}
static KJ_ALWAYS_INLINE(Text::Builder getWritableTextPointer(
......@@ -1234,7 +1235,7 @@ struct WireHelpers {
const void* defaultValue, ByteCount defaultSize)) {
if (ref->isNull()) {
Text::Builder builder = initTextPointer(ref, segment, defaultSize);
builder.copyFrom(defaultValue);
memcpy(builder.begin(), defaultValue, defaultSize / BYTES);
return builder;
} else {
word* ptr = followFars(ref, segment);
......@@ -1258,12 +1259,13 @@ struct WireHelpers {
ref->listRef.set(FieldSize::BYTE, size * (1 * ELEMENTS / BYTES));
// Build the Data::Builder.
return Data::Builder(reinterpret_cast<char*>(ptr), size / BYTES);
return Data::Builder(reinterpret_cast<byte*>(ptr), size / BYTES);
}
static KJ_ALWAYS_INLINE(void setDataPointer(
WirePointer* ref, SegmentBuilder* segment, Data::Reader value)) {
initDataPointer(ref, segment, value.size() * BYTES).copyFrom(value);
memcpy(initDataPointer(ref, segment, value.size() * BYTES).begin(),
value.begin(), value.size());
}
static KJ_ALWAYS_INLINE(Data::Builder getWritableDataPointer(
......@@ -1271,7 +1273,7 @@ struct WireHelpers {
const void* defaultValue, ByteCount defaultSize)) {
if (ref->isNull()) {
Data::Builder builder = initDataPointer(ref, segment, defaultSize);
builder.copyFrom(defaultValue);
memcpy(builder.begin(), defaultValue, defaultSize / BYTES);
return builder;
} else {
word* ptr = followFars(ref, segment);
......@@ -1281,7 +1283,7 @@ struct WireHelpers {
KJ_REQUIRE(ref->listRef.elementSize() == FieldSize::BYTE,
"Called getData{Field,Element}() but existing list pointer is not byte-sized.");
return Data::Builder(reinterpret_cast<char*>(ptr), ref->listRef.elementCount() / ELEMENTS);
return Data::Builder(reinterpret_cast<byte*>(ptr), ref->listRef.elementCount() / ELEMENTS);
}
}
......@@ -1668,7 +1670,7 @@ struct WireHelpers {
const void* defaultValue, ByteCount defaultSize)) {
if (ref == nullptr || ref->isNull()) {
useDefault:
return Data::Reader(reinterpret_cast<const char*>(defaultValue), defaultSize / BYTES);
return Data::Reader(reinterpret_cast<const byte*>(defaultValue), defaultSize / BYTES);
} else {
const word* ptr = followFars(ref, segment);
......@@ -1695,7 +1697,7 @@ struct WireHelpers {
goto useDefault;
}
return Data::Reader(reinterpret_cast<const char*>(ptr), size);
return Data::Reader(reinterpret_cast<const byte*>(ptr), size);
}
}
......@@ -2022,7 +2024,7 @@ Data::Builder ListBuilder::asData() {
return Data::Builder();
}
return Data::Builder(reinterpret_cast<char*>(ptr), elementCount / ELEMENTS);
return Data::Builder(reinterpret_cast<byte*>(ptr), elementCount / ELEMENTS);
}
StructBuilder ListBuilder::getStructElement(ElementCount index) const {
......@@ -2143,7 +2145,7 @@ Data::Reader ListReader::asData() {
return Data::Reader();
}
return Data::Reader(reinterpret_cast<const char*>(ptr), elementCount / ELEMENTS);
return Data::Reader(reinterpret_cast<const byte*>(ptr), elementCount / ELEMENTS);
}
StructReader ListReader::getStructElement(ElementCount index) const {
......
......@@ -712,7 +712,7 @@ struct ObjectReader {
// Internal implementation details...
inline Data::Builder StructBuilder::getDataSectionAsBlob() {
return Data::Builder(reinterpret_cast<char*>(data), dataSize / BITS_PER_BYTE / BYTES);
return Data::Builder(reinterpret_cast<byte*>(data), dataSize / BITS_PER_BYTE / BYTES);
}
template <typename T>
......@@ -768,7 +768,7 @@ inline void StructBuilder::setDataField(
// -------------------------------------------------------------------
inline Data::Reader StructReader::getDataSectionAsBlob() {
return Data::Reader(reinterpret_cast<const char*>(data), dataSize / BITS_PER_BYTE / BYTES);
return Data::Reader(reinterpret_cast<const byte*>(data), dataSize / BITS_PER_BYTE / BYTES);
}
template <typename T>
......
......@@ -170,8 +170,8 @@ TEST(SchemaLoader, Upgrade) {
loadUnderAlternateTypeId<test::TestNewVersion>(loader, typeId<test::TestOldVersion>());
// The new version replaced the old.
EXPECT_STREQ(Schema::from<test::TestNewVersion>().getProto().getDisplayName(),
schema.getProto().getDisplayName());
EXPECT_EQ(Schema::from<test::TestNewVersion>().getProto().getDisplayName(),
schema.getProto().getDisplayName());
// But it is still usable as the old version.
schema.requireUsableAs<test::TestOldVersion>();
......@@ -189,8 +189,8 @@ TEST(SchemaLoader, Downgrade) {
loadUnderAlternateTypeId<test::TestOldVersion>(loader, typeId<test::TestNewVersion>());
// We kept the new version, because the replacement was older.
EXPECT_STREQ(Schema::from<test::TestNewVersion>().getProto().getDisplayName(),
schema.getProto().getDisplayName());
EXPECT_EQ(Schema::from<test::TestNewVersion>().getProto().getDisplayName(),
schema.getProto().getDisplayName());
schema.requireUsableAs<test::TestNewVersion>();
}
......
......@@ -466,81 +466,102 @@ TEST(Packed, RoundTripAllZeroEvenSegmentCountLazy) {
// =======================================================================================
TEST(Packed, RoundTripHugeString) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(1);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe;
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringScratchSpace) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(1);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe;
writePackedMessage(pipe, builder);
word scratch[1024];
PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringLazy) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(1);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe(1);
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringOddSegmentCount) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(3);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe;
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringOddSegmentCountLazy) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(3);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe(1);
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringEvenSegmentCount) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(2);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe;
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
TEST(Packed, RoundTripHugeStringEvenSegmentCountLazy) {
kj::String huge = kj::heapString(5023);
memset(huge.begin(), 'x', 5023);
TestMessageBuilder builder(2);
builder.initRoot<TestAllTypes>().setTextField(std::string(5023, 'x'));
builder.initRoot<TestAllTypes>().setTextField(huge);
TestPipe pipe(1);
writePackedMessage(pipe, builder);
PackedMessageReader reader(pipe);
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == std::string(5023, 'x'));
EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge);
}
// TODO(test): Test error cases.
......
......@@ -69,7 +69,15 @@ static void print(std::ostream& os, DynamicValue::Reader value,
case DynamicValue::TEXT:
case DynamicValue::DATA: {
os << '\"';
for (char c: value.as<Data>()) {
// TODO(someday): Data probably shouldn't be printed as a string.
kj::ArrayPtr<const char> chars;
if (value.getType() == DynamicValue::DATA) {
auto reader = value.as<Data>();
chars = kj::arrayPtr(reinterpret_cast<const char*>(reader.begin()), reader.size());
} else {
chars = value.as<Text>();
}
for (char c: chars) {
switch (c) {
case '\a': os << "\\a"; break;
case '\b': os << "\\b"; break;
......@@ -112,7 +120,7 @@ static void print(std::ostream& os, DynamicValue::Reader value,
case DynamicValue::ENUM: {
auto enumValue = value.as<DynamicEnum>();
KJ_IF_MAYBE(enumerant, enumValue.getEnumerant()) {
os << enumerant->getProto().getName().c_str();
os << enumerant->getProto().getName().cStr();
} else {
// Unknown enum value; output raw number.
os << enumValue.getRaw();
......@@ -130,7 +138,7 @@ static void print(std::ostream& os, DynamicValue::Reader value,
} else {
os << ", ";
}
os << member.getProto().getName().c_str() << " = ";
os << member.getProto().getName().cStr() << " = ";
auto memberBody = member.getProto().getBody();
switch (memberBody.which()) {
......@@ -150,7 +158,7 @@ static void print(std::ostream& os, DynamicValue::Reader value,
case DynamicValue::UNION: {
auto unionValue = value.as<DynamicUnion>();
KJ_IF_MAYBE(tag, unionValue.which()) {
os << tag->getProto().getName() << "(";
os << tag->getProto().getName().cStr() << "(";
print(os, unionValue.get(),
tag->getProto().getBody().getFieldMember().getType().getBody().which());
os << ")";
......
......@@ -44,7 +44,7 @@ void genericInitTestMessage(Builder builder) {
builder.setFloat32Field(1234.5);
builder.setFloat64Field(-123e45);
builder.setTextField("foo");
builder.setDataField("bar");
builder.setDataField(data("bar"));
{
auto subBuilder = builder.initStructField();
subBuilder.setVoidField(Void::VOID);
......@@ -60,7 +60,7 @@ void genericInitTestMessage(Builder builder) {
subBuilder.setFloat32Field(-1.25e-10);
subBuilder.setFloat64Field(345);
subBuilder.setTextField("baz");
subBuilder.setDataField("qux");
subBuilder.setDataField(data("qux"));
{
auto subSubBuilder = subBuilder.initStructField();
subSubBuilder.setTextField("nested");
......@@ -82,7 +82,7 @@ void genericInitTestMessage(Builder builder) {
subBuilder.setFloat32List({0, 1234567, 1e37, -1e37, 1e-37, -1e-37});
subBuilder.setFloat64List({0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306});
subBuilder.setTextList({"quux", "corge", "grault"});
subBuilder.setDataList({"garply", "waldo", "fred"});
subBuilder.setDataList({data("garply"), data("waldo"), data("fred")});
{
auto listBuilder = subBuilder.initStructList(3);
listBuilder[0].setTextField("x structlist 1");
......@@ -112,7 +112,7 @@ void genericInitTestMessage(Builder builder) {
-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN()});
builder.setTextList({"plugh", "xyzzy", "thud"});
builder.setDataList({"oops", "exhausted", "rfc3092"});
builder.setDataList({data("oops"), data("exhausted"), data("rfc3092")});
{
auto listBuilder = builder.initStructList(3);
listBuilder[0].setTextField("structlist 1");
......@@ -136,7 +136,7 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
builder.set("float32Field", 1234.5);
builder.set("float64Field", -123e45);
builder.set("textField", "foo");
builder.set("dataField", "bar");
builder.set("dataField", data("bar"));
{
auto subBuilder = builder.init("structField").as<DynamicStruct>();
subBuilder.set("voidField", Void::VOID);
......@@ -152,7 +152,7 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
subBuilder.set("float32Field", -1.25e-10);
subBuilder.set("float64Field", 345);
subBuilder.set("textField", "baz");
subBuilder.set("dataField", "qux");
subBuilder.set("dataField", data("qux"));
{
auto subSubBuilder = subBuilder.init("structField").as<DynamicStruct>();
subSubBuilder.set("textField", "nested");
......@@ -174,7 +174,7 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
subBuilder.set("float32List", {0, 1234567, 1e37, -1e37, 1e-37, -1e-37});
subBuilder.set("float64List", {0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306});
subBuilder.set("textList", {"quux", "corge", "grault"});
subBuilder.set("dataList", {"garply", "waldo", "fred"});
subBuilder.set("dataList", {data("garply"), data("waldo"), data("fred")});
{
auto listBuilder = subBuilder.init("structList", 3).as<DynamicList>();
listBuilder[0].as<DynamicStruct>().set("textField", "x structlist 1");
......@@ -204,7 +204,7 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN()});
builder.set("textList", {"plugh", "xyzzy", "thud"});
builder.set("dataList", {"oops", "exhausted", "rfc3092"});
builder.set("dataList", {data("oops"), data("exhausted"), data("rfc3092")});
{
auto listBuilder = builder.init("structList", 3).as<DynamicList>();
listBuilder[0].as<DynamicStruct>().set("textField", "structlist 1");
......@@ -256,7 +256,7 @@ void genericCheckTestMessage(Reader reader) {
EXPECT_FLOAT_EQ(1234.5f, reader.getFloat32Field());
EXPECT_DOUBLE_EQ(-123e45, reader.getFloat64Field());
EXPECT_EQ("foo", reader.getTextField());
EXPECT_EQ("bar", reader.getDataField());
EXPECT_EQ(data("bar"), reader.getDataField());
{
auto subReader = reader.getStructField();
EXPECT_EQ(Void::VOID, subReader.getVoidField());
......@@ -272,7 +272,7 @@ void genericCheckTestMessage(Reader reader) {
EXPECT_FLOAT_EQ(-1.25e-10f, subReader.getFloat32Field());
EXPECT_DOUBLE_EQ(345, subReader.getFloat64Field());
EXPECT_EQ("baz", subReader.getTextField());
EXPECT_EQ("qux", subReader.getDataField());
EXPECT_EQ(data("qux"), subReader.getDataField());
{
auto subSubReader = subReader.getStructField();
EXPECT_EQ("nested", subSubReader.getTextField());
......@@ -294,7 +294,7 @@ void genericCheckTestMessage(Reader reader) {
checkList(subReader.getFloat32List(), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f});
checkList(subReader.getFloat64List(), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306});
checkList(subReader.getTextList(), {"quux", "corge", "grault"});
checkList(subReader.getDataList(), {"garply", "waldo", "fred"});
checkList(subReader.getDataList(), {data("garply"), data("waldo"), data("fred")});
{
auto listReader = subReader.getStructList();
ASSERT_EQ(3u, listReader.size());
......@@ -333,7 +333,7 @@ void genericCheckTestMessage(Reader reader) {
EXPECT_TRUE(isNaN(listReader[3]));
}
checkList(reader.getTextList(), {"plugh", "xyzzy", "thud"});
checkList(reader.getDataList(), {"oops", "exhausted", "rfc3092"});
checkList(reader.getDataList(), {data("oops"), data("exhausted"), data("rfc3092")});
{
auto listReader = reader.getStructList();
ASSERT_EQ(3u, listReader.size());
......@@ -400,7 +400,7 @@ void dynamicCheckTestMessage(Reader reader) {
EXPECT_FLOAT_EQ(1234.5f, reader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(-123e45, reader.get("float64Field").as<double>());
EXPECT_EQ("foo", reader.get("textField").as<Text>());
EXPECT_EQ("bar", reader.get("dataField").as<Data>());
EXPECT_EQ(data("bar"), reader.get("dataField").as<Data>());
{
auto subReader = reader.get("structField").as<DynamicStruct>();
EXPECT_EQ(Void::VOID, subReader.get("voidField").as<Void>());
......@@ -416,7 +416,7 @@ void dynamicCheckTestMessage(Reader reader) {
EXPECT_FLOAT_EQ(-1.25e-10f, subReader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(345, subReader.get("float64Field").as<double>());
EXPECT_EQ("baz", subReader.get("textField").as<Text>());
EXPECT_EQ("qux", subReader.get("dataField").as<Data>());
EXPECT_EQ(data("qux"), subReader.get("dataField").as<Data>());
{
auto subSubReader = subReader.get("structField").as<DynamicStruct>();
EXPECT_EQ("nested", subSubReader.get("textField").as<Text>());
......@@ -439,7 +439,7 @@ void dynamicCheckTestMessage(Reader reader) {
checkList<float>(subReader.get("float32List"), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f});
checkList<double>(subReader.get("float64List"), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306});
checkList<Text>(subReader.get("textList"), {"quux", "corge", "grault"});
checkList<Data>(subReader.get("dataList"), {"garply", "waldo", "fred"});
checkList<Data>(subReader.get("dataList"), {data("garply"), data("waldo"), data("fred")});
{
auto listReader = subReader.get("structList").as<DynamicList>();
ASSERT_EQ(3u, listReader.size());
......@@ -478,7 +478,7 @@ void dynamicCheckTestMessage(Reader reader) {
EXPECT_TRUE(isNaN(listReader[3].as<double>()));
}
checkList<Text>(reader.get("textList"), {"plugh", "xyzzy", "thud"});
checkList<Data>(reader.get("dataList"), {"oops", "exhausted", "rfc3092"});
checkList<Data>(reader.get("dataList"), {data("oops"), data("exhausted"), data("rfc3092")});
{
auto listReader = reader.get("structList").as<DynamicList>();
ASSERT_EQ(3u, listReader.size());
......@@ -506,7 +506,7 @@ void genericCheckTestMessageAllZero(Reader reader) {
EXPECT_FLOAT_EQ(0, reader.getFloat32Field());
EXPECT_DOUBLE_EQ(0, reader.getFloat64Field());
EXPECT_EQ("", reader.getTextField());
EXPECT_EQ("", reader.getDataField());
EXPECT_EQ(data(""), reader.getDataField());
{
auto subReader = reader.getStructField();
EXPECT_EQ(Void::VOID, subReader.getVoidField());
......@@ -522,7 +522,7 @@ void genericCheckTestMessageAllZero(Reader reader) {
EXPECT_FLOAT_EQ(0, subReader.getFloat32Field());
EXPECT_DOUBLE_EQ(0, subReader.getFloat64Field());
EXPECT_EQ("", subReader.getTextField());
EXPECT_EQ("", subReader.getDataField());
EXPECT_EQ(data(""), subReader.getDataField());
{
auto subSubReader = subReader.getStructField();
EXPECT_EQ("", subSubReader.getTextField());
......@@ -581,7 +581,7 @@ void dynamicCheckTestMessageAllZero(Reader reader) {
EXPECT_FLOAT_EQ(0, reader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(0, reader.get("float64Field").as<double>());
EXPECT_EQ("", reader.get("textField").as<Text>());
EXPECT_EQ("", reader.get("dataField").as<Data>());
EXPECT_EQ(data(""), reader.get("dataField").as<Data>());
{
auto subReader = reader.get("structField").as<DynamicStruct>();
EXPECT_EQ(Void::VOID, subReader.get("voidField").as<Void>());
......@@ -597,7 +597,7 @@ void dynamicCheckTestMessageAllZero(Reader reader) {
EXPECT_FLOAT_EQ(0, subReader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(0, subReader.get("float64Field").as<double>());
EXPECT_EQ("", subReader.get("textField").as<Text>());
EXPECT_EQ("", subReader.get("dataField").as<Data>());
EXPECT_EQ(data(""), subReader.get("dataField").as<Data>());
{
auto subSubReader = subReader.get("structField").as<DynamicStruct>();
EXPECT_EQ("", subSubReader.get("textField").as<Text>());
......
......@@ -32,16 +32,16 @@
namespace capnproto {
inline std::ostream& operator<<(std::ostream& os, const Data::Reader& value) {
return os.write(value.data(), value.size());
return os.write(reinterpret_cast<const char*>(value.begin()), value.size());
}
inline std::ostream& operator<<(std::ostream& os, const Data::Builder& value) {
return os.write(value.data(), value.size());
return os.write(reinterpret_cast<char*>(value.begin()), value.size());
}
inline std::ostream& operator<<(std::ostream& os, const Text::Reader& value) {
return os.write(value.data(), value.size());
return os.write(value.begin(), value.size());
}
inline std::ostream& operator<<(std::ostream& os, const Text::Builder& value) {
return os.write(value.data(), value.size());
return os.write(value.begin(), value.size());
}
inline std::ostream& operator<<(std::ostream& os, Void) {
return os << "void";
......@@ -49,6 +49,10 @@ inline std::ostream& operator<<(std::ostream& os, Void) {
namespace internal {
inline Data::Reader data(const char* str) {
return Data::Reader(reinterpret_cast<const byte*>(str), strlen(str));
}
namespace test = capnproto_test::capnproto::test;
// We don't use "using namespace" to pull these in because then things would still compile
......
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