Commit ebce4aa6 authored by Kenton Varda's avatar Kenton Varda

MSVC: All lite-mode tests pass.

The project file still only compiles a test binary, but it should be easy to separate out a library project from here.

Thanks again to Bryan Boreham <bjboreham@gmail.com> for much help getting this working.
parent ead1a3b3
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;CAPNP_LITE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;CAPNP_LITE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>.;..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
...@@ -75,14 +75,35 @@ ...@@ -75,14 +75,35 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\src\capnp\any.h" />
<ClInclude Include="..\src\capnp\arena.h" />
<ClInclude Include="..\src\capnp\blob.h" />
<ClInclude Include="..\src\capnp\common.h" />
<ClInclude Include="..\src\capnp\generated-header-support.h" />
<ClInclude Include="..\src\capnp\layout.h" />
<ClInclude Include="..\src\capnp\list.h" />
<ClInclude Include="..\src\capnp\message.h" />
<ClInclude Include="..\src\capnp\orphan.h" />
<ClInclude Include="..\src\capnp\pointer-helpers.h" />
<ClInclude Include="..\src\capnp\schema-lite.h" />
<ClInclude Include="..\src\capnp\serialize-packed.h" />
<ClInclude Include="..\src\capnp\serialize.h" />
<ClInclude Include="..\src\capnp\test-util.h" />
<ClInclude Include="..\src\kj\array.h" /> <ClInclude Include="..\src\kj\array.h" />
<ClInclude Include="..\src\kj\common.h" /> <ClInclude Include="..\src\kj\common.h" />
<ClInclude Include="..\src\kj\debug.h" /> <ClInclude Include="..\src\kj\debug.h" />
<ClInclude Include="..\src\kj\exception.h" /> <ClInclude Include="..\src\kj\exception.h" />
<ClInclude Include="..\src\kj\io.h" /> <ClInclude Include="..\src\kj\io.h" />
<ClInclude Include="..\src\kj\memory.h" /> <ClInclude Include="..\src\kj\memory.h" />
<ClInclude Include="..\src\kj\mutex.h" />
<ClInclude Include="..\src\kj\string.h" /> <ClInclude Include="..\src\kj\string.h" />
<ClInclude Include="..\src\kj\miniposix.h" /> <ClInclude Include="..\src\kj\miniposix.h" />
<ClInclude Include="..\src\kj\thread.h" />
<ClInclude Include="..\src\kj\threadlocal.h" />
<ClInclude Include="..\src\kj\units.h" />
<ClInclude Include="capnp\test-import.capnp.h" />
<ClInclude Include="capnp\test-import2.capnp.h" />
<ClInclude Include="capnp\test.capnp.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\src\kj\array-test.c++"> <ClCompile Include="..\src\kj\array-test.c++">
...@@ -136,6 +157,105 @@ ...@@ -136,6 +157,105 @@
<Project>{3af54c8a-10bf-4332-9147-f68ed9862032}</Project> <Project>{3af54c8a-10bf-4332-9147-f68ed9862032}</Project>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\capnp\any-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\any.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\arena.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\blob-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\blob.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\c++.capnp.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\common-test.c++">
<FileType>Document</FileType>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)-capnp</ObjectFileName>
<ProgramDataBaseFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)-capnpvc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)-capnp</ObjectFileName>
<ProgramDataBaseFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)-capnpvc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<ClCompile Include="..\src\capnp\encoding-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\endian-fallback-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\endian-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\layout-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\layout.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\list.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\message-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\message.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\orphan-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\schema.capnp.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\serialize-packed-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\serialize-packed.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\serialize-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\serialize.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\capnp\test-util.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="capnp\test-import.capnp.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="capnp\test-import2.capnp.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="capnp\test.capnp.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kj\mutex-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\mutex.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kj\thread.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\threadlocal-test.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
......
@echo off
rem You'll need to build capnp.exe and capnpc-c++.exe using MinGW.
capnp compile -oc++ -I../src --src-prefix=../src ../src/capnp/test.capnp ../src/capnp/test-import.capnp ../src/capnp/test-import2.capnp
...@@ -8,3 +8,12 @@ because Kenton doesn't understand cmake and wanted to get some work done. ...@@ -8,3 +8,12 @@ because Kenton doesn't understand cmake and wanted to get some work done.
The solution file refers to gtest, which must be downloaded to "c++/gtest". The solution file refers to gtest, which must be downloaded to "c++/gtest".
The "setup-autotools.sh" script accomplishes this, although it requires bash The "setup-autotools.sh" script accomplishes this, although it requires bash
to run. to run.
The solution also refers to generated code for test schemas which should be
under msvc/capnp (i.e. a directory called "capnp" within *this* directory).
To generate these files, do the following:
1. Build capnp.exe and capnpc-c++.exe with MinGW. (Or, download the
precompiled binaries if they are available.)
2. Copy those files to this directory, or somewhere in PATH.
3. Run gen-test-code.bat.
...@@ -124,9 +124,11 @@ TEST(Any, AnyStruct) { ...@@ -124,9 +124,11 @@ TEST(Any, AnyStruct) {
EXPECT_EQ(48, b.getDataSection().size()); EXPECT_EQ(48, b.getDataSection().size());
EXPECT_EQ(20, b.getPointerSection().size()); EXPECT_EQ(20, b.getPointerSection().size());
#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h.
b = root.getAnyPointerField().getAs<TestAllTypes>(); b = root.getAnyPointerField().getAs<TestAllTypes>();
EXPECT_EQ(48, b.getDataSection().size()); EXPECT_EQ(48, b.getDataSection().size());
EXPECT_EQ(20, b.getPointerSection().size()); EXPECT_EQ(20, b.getPointerSection().size());
#endif
auto r = toAny(root.getAnyPointerField().getAs<TestAllTypes>().asReader()); auto r = toAny(root.getAnyPointerField().getAs<TestAllTypes>().asReader());
EXPECT_EQ(48, r.getDataSection().size()); EXPECT_EQ(48, r.getDataSection().size());
...@@ -136,9 +138,11 @@ TEST(Any, AnyStruct) { ...@@ -136,9 +138,11 @@ TEST(Any, AnyStruct) {
EXPECT_EQ(48, r.getDataSection().size()); EXPECT_EQ(48, r.getDataSection().size());
EXPECT_EQ(20, r.getPointerSection().size()); EXPECT_EQ(20, r.getPointerSection().size());
#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h.
r = root.getAnyPointerField().getAs<TestAllTypes>().asReader(); r = root.getAnyPointerField().getAs<TestAllTypes>().asReader();
EXPECT_EQ(48, r.getDataSection().size()); EXPECT_EQ(48, r.getDataSection().size());
EXPECT_EQ(20, r.getPointerSection().size()); EXPECT_EQ(20, r.getPointerSection().size());
#endif
{ {
MallocMessageBuilder b2; MallocMessageBuilder b2;
...@@ -177,10 +181,12 @@ TEST(Any, AnyList) { ...@@ -177,10 +181,12 @@ TEST(Any, AnyList) {
EXPECT_EQ(48, alb.as<List<AnyStruct>>()[0].getDataSection().size()); EXPECT_EQ(48, alb.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alb.as<List<AnyStruct>>()[0].getPointerSection().size()); EXPECT_EQ(20, alb.as<List<AnyStruct>>()[0].getPointerSection().size());
#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h.
alb = root.getAnyPointerField().getAs<List<TestAllTypes>>(); alb = root.getAnyPointerField().getAs<List<TestAllTypes>>();
EXPECT_EQ(2, alb.size()); EXPECT_EQ(2, alb.size());
EXPECT_EQ(48, alb.as<List<AnyStruct>>()[0].getDataSection().size()); EXPECT_EQ(48, alb.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alb.as<List<AnyStruct>>()[0].getPointerSection().size()); EXPECT_EQ(20, alb.as<List<AnyStruct>>()[0].getPointerSection().size());
#endif
auto alr = toAny(root.getAnyPointerField().getAs<List<TestAllTypes>>().asReader()); auto alr = toAny(root.getAnyPointerField().getAs<List<TestAllTypes>>().asReader());
EXPECT_EQ(2, alr.size()); EXPECT_EQ(2, alr.size());
...@@ -192,10 +198,12 @@ TEST(Any, AnyList) { ...@@ -192,10 +198,12 @@ TEST(Any, AnyList) {
EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size()); EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size()); EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size());
#if !_MSC_VER // TODO(msvc): ICE on the necessary constructor; see any.h.
alr = root.getAnyPointerField().getAs<List<TestAllTypes>>().asReader(); alr = root.getAnyPointerField().getAs<List<TestAllTypes>>().asReader();
EXPECT_EQ(2, alr.size()); EXPECT_EQ(2, alr.size());
EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size()); EXPECT_EQ(48, alr.as<List<AnyStruct>>()[0].getDataSection().size());
EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size()); EXPECT_EQ(20, alr.as<List<AnyStruct>>()[0].getPointerSection().size());
#endif
} }
} // namespace } // namespace
......
...@@ -366,9 +366,9 @@ struct List<AnyPointer, Kind::OTHER> { ...@@ -366,9 +366,9 @@ struct List<AnyPointer, Kind::OTHER> {
inline explicit Reader(_::ListReader reader): reader(reader) {} inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; } inline uint size() const { return reader.size() / ELEMENTS; }
inline typename AnyPointer::Reader operator[](uint index) const { inline AnyPointer::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size()); KJ_IREQUIRE(index < size());
return typename AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS)); return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
} }
typedef _::IndexingIterator<const Reader, typename AnyPointer::Reader> Iterator; typedef _::IndexingIterator<const Reader, typename AnyPointer::Reader> Iterator;
...@@ -398,9 +398,9 @@ struct List<AnyPointer, Kind::OTHER> { ...@@ -398,9 +398,9 @@ struct List<AnyPointer, Kind::OTHER> {
inline Reader asReader() { return Reader(builder.asReader()); } inline Reader asReader() { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; } inline uint size() const { return builder.size() / ELEMENTS; }
inline typename AnyPointer::Builder operator[](uint index) { inline AnyPointer::Builder operator[](uint index) {
KJ_IREQUIRE(index < size()); KJ_IREQUIRE(index < size());
return typename AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS)); return AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS));
} }
typedef _::IndexingIterator<Builder, typename AnyPointer::Builder> Iterator; typedef _::IndexingIterator<Builder, typename AnyPointer::Builder> Iterator;
...@@ -422,9 +422,11 @@ public: ...@@ -422,9 +422,11 @@ public:
Reader() = default; Reader() = default;
inline Reader(_::StructReader reader): _reader(reader) {} inline Reader(_::StructReader reader): _reader(reader) {}
#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::STRUCT>> template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::STRUCT>>
inline Reader(T&& value) inline Reader(T&& value)
: _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {} : _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {}
#endif
Data::Reader getDataSection() { Data::Reader getDataSection() {
return _reader.getDataSectionAsBlob(); return _reader.getDataSectionAsBlob();
...@@ -448,9 +450,11 @@ public: ...@@ -448,9 +450,11 @@ public:
inline Builder(decltype(nullptr)) {} inline Builder(decltype(nullptr)) {}
inline Builder(_::StructBuilder builder): _builder(builder) {} inline Builder(_::StructBuilder builder): _builder(builder) {}
#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::STRUCT>> template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::STRUCT>>
inline Builder(T&& value) inline Builder(T&& value)
: _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {} : _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {}
#endif
inline Data::Builder getDataSection() { inline Data::Builder getDataSection() {
return _builder.getDataSectionAsBlob(); return _builder.getDataSectionAsBlob();
...@@ -495,9 +499,9 @@ public: ...@@ -495,9 +499,9 @@ public:
inline explicit Reader(_::ListReader reader): reader(reader) {} inline explicit Reader(_::ListReader reader): reader(reader) {}
inline uint size() const { return reader.size() / ELEMENTS; } inline uint size() const { return reader.size() / ELEMENTS; }
inline typename AnyStruct::Reader operator[](uint index) const { inline AnyStruct::Reader operator[](uint index) const {
KJ_IREQUIRE(index < size()); KJ_IREQUIRE(index < size());
return typename AnyStruct::Reader(reader.getStructElement(index * ELEMENTS)); return AnyStruct::Reader(reader.getStructElement(index * ELEMENTS));
} }
typedef _::IndexingIterator<const Reader, typename AnyStruct::Reader> Iterator; typedef _::IndexingIterator<const Reader, typename AnyStruct::Reader> Iterator;
...@@ -528,9 +532,9 @@ public: ...@@ -528,9 +532,9 @@ public:
inline Reader asReader() { return Reader(builder.asReader()); } inline Reader asReader() { return Reader(builder.asReader()); }
inline uint size() const { return builder.size() / ELEMENTS; } inline uint size() const { return builder.size() / ELEMENTS; }
inline typename AnyStruct::Builder operator[](uint index) { inline AnyStruct::Builder operator[](uint index) {
KJ_IREQUIRE(index < size()); KJ_IREQUIRE(index < size());
return typename AnyStruct::Builder(builder.getStructElement(index * ELEMENTS)); return AnyStruct::Builder(builder.getStructElement(index * ELEMENTS));
} }
typedef _::IndexingIterator<Builder, typename AnyStruct::Builder> Iterator; typedef _::IndexingIterator<Builder, typename AnyStruct::Builder> Iterator;
...@@ -551,9 +555,11 @@ public: ...@@ -551,9 +555,11 @@ public:
Reader() = default; Reader() = default;
inline Reader(_::ListReader reader): _reader(reader) {} inline Reader(_::ListReader reader): _reader(reader) {}
#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::LIST>> template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::LIST>>
inline Reader(T&& value) inline Reader(T&& value)
: _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {} : _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {}
#endif
inline ElementSize getElementSize() { return _reader.getElementSize(); } inline ElementSize getElementSize() { return _reader.getElementSize(); }
inline uint size() { return _reader.size() / ELEMENTS; } inline uint size() { return _reader.size() / ELEMENTS; }
...@@ -574,9 +580,11 @@ public: ...@@ -574,9 +580,11 @@ public:
inline Builder(decltype(nullptr)) {} inline Builder(decltype(nullptr)) {}
inline Builder(_::ListBuilder builder): _builder(builder) {} inline Builder(_::ListBuilder builder): _builder(builder) {}
#if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::LIST>> template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::LIST>>
inline Builder(T&& value) inline Builder(T&& value)
: _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {} : _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {}
#endif
inline ElementSize getElementSize() { return _builder.getElementSize(); } inline ElementSize getElementSize() { return _builder.getElementSize(); }
inline uint size() { return _builder.size() / ELEMENTS; } inline uint size() { return _builder.size() / ELEMENTS; }
...@@ -818,11 +826,11 @@ struct PointerHelpers<AnyPointer, Kind::OTHER> { ...@@ -818,11 +826,11 @@ struct PointerHelpers<AnyPointer, Kind::OTHER> {
template <> template <>
struct PointerHelpers<AnyStruct, Kind::OTHER> { struct PointerHelpers<AnyStruct, Kind::OTHER> {
static inline typename AnyStruct::Reader get( static inline AnyStruct::Reader get(
PointerReader reader, const word* defaultValue = nullptr) { PointerReader reader, const word* defaultValue = nullptr) {
return AnyStruct::Reader(reader.getStruct(defaultValue)); return AnyStruct::Reader(reader.getStruct(defaultValue));
} }
static inline typename AnyStruct::Builder get( static inline AnyStruct::Builder get(
PointerBuilder builder, const word* defaultValue = nullptr) { PointerBuilder builder, const word* defaultValue = nullptr) {
// TODO(someday): Allow specifying the size somehow? // TODO(someday): Allow specifying the size somehow?
return AnyStruct::Builder(builder.getStruct( return AnyStruct::Builder(builder.getStruct(
...@@ -831,31 +839,31 @@ struct PointerHelpers<AnyStruct, Kind::OTHER> { ...@@ -831,31 +839,31 @@ struct PointerHelpers<AnyStruct, Kind::OTHER> {
static inline void set(PointerBuilder builder, AnyStruct::Reader value) { static inline void set(PointerBuilder builder, AnyStruct::Reader value) {
builder.setStruct(value._reader); builder.setStruct(value._reader);
} }
static inline typename AnyStruct::Builder init( static inline AnyStruct::Builder init(
PointerBuilder builder, uint dataWordCount, uint pointerCount) { PointerBuilder builder, uint dataWordCount, uint pointerCount) {
return typename AnyStruct::Builder(builder.initStruct( return AnyStruct::Builder(builder.initStruct(
StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
} }
}; };
template <> template <>
struct PointerHelpers<AnyList, Kind::OTHER> { struct PointerHelpers<AnyList, Kind::OTHER> {
static inline typename AnyList::Reader get( static inline AnyList::Reader get(
PointerReader reader, const word* defaultValue = nullptr) { PointerReader reader, const word* defaultValue = nullptr) {
return AnyList::Reader(reader.getListAnySize(defaultValue)); return AnyList::Reader(reader.getListAnySize(defaultValue));
} }
static inline typename AnyList::Builder get( static inline AnyList::Builder get(
PointerBuilder builder, const word* defaultValue = nullptr) { PointerBuilder builder, const word* defaultValue = nullptr) {
return AnyList::Builder(builder.getListAnySize(defaultValue)); return AnyList::Builder(builder.getListAnySize(defaultValue));
} }
static inline void set(PointerBuilder builder, AnyList::Reader value) { static inline void set(PointerBuilder builder, AnyList::Reader value) {
builder.setList(value._reader); builder.setList(value._reader);
} }
static inline typename AnyList::Builder init( static inline AnyList::Builder init(
PointerBuilder builder, ElementSize elementSize, uint elementCount) { PointerBuilder builder, ElementSize elementSize, uint elementCount) {
return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS)); return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS));
} }
static inline typename AnyList::Builder init( static inline AnyList::Builder init(
PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) { PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) {
return AnyList::Builder(builder.initStructList( return AnyList::Builder(builder.initStructList(
elementCount * ELEMENTS, StructSize(dataWordCount * WORDS, pointerCount * POINTERS))); elementCount * ELEMENTS, StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
......
...@@ -103,6 +103,7 @@ public: ...@@ -103,6 +103,7 @@ public:
inline Builder(ArrayPtr<byte>& value): ArrayPtr<byte>(value) {} inline Builder(ArrayPtr<byte>& value): ArrayPtr<byte>(value) {}
inline Data::Reader asReader() const { return Data::Reader(*this); } inline Data::Reader asReader() const { return Data::Reader(*this); }
inline operator Reader() const { return asReader(); }
}; };
class Text::Builder: public kj::DisallowConstCopy { class Text::Builder: public kj::DisallowConstCopy {
...@@ -117,6 +118,7 @@ public: ...@@ -117,6 +118,7 @@ public:
} }
inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); } inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); }
inline operator Reader() const { return asReader(); }
inline operator kj::ArrayPtr<char>(); inline operator kj::ArrayPtr<char>();
inline kj::ArrayPtr<char> asArray(); inline kj::ArrayPtr<char> asArray();
......
...@@ -61,7 +61,7 @@ struct Void { ...@@ -61,7 +61,7 @@ struct Void {
inline constexpr bool operator!=(Void other) const { return false; } inline constexpr bool operator!=(Void other) const { return false; }
}; };
static constexpr Void VOID = Void(); static KJ_CONSTEXPR(const) Void VOID = Void();
// Constant value for `Void`, which is an empty struct. // Constant value for `Void`, which is an empty struct.
template <typename T> template <typename T>
...@@ -113,7 +113,13 @@ template <typename T, typename = typename T::_capnpPrivate::IsInterface> uint16_ ...@@ -113,7 +113,13 @@ template <typename T, typename = typename T::_capnpPrivate::IsInterface> uint16_
template <typename T, typename = typename schemas::EnumInfo<T>::IsEnum> uint32_t kindSfinae(int); template <typename T, typename = typename schemas::EnumInfo<T>::IsEnum> uint32_t kindSfinae(int);
template <typename T> uint64_t kindSfinae(...); template <typename T> uint64_t kindSfinae(...);
template <typename T, size_t s = sizeof(kindSfinae<T>(0))> struct Kind_; template <typename T>
struct MsvcWorkaround {
// TODO(msvc): Remove this once MSVC supports expression SFINAE.
enum { value = sizeof(kindSfinae<T>(0)) };
};
template <typename T, size_t s = MsvcWorkaround<T>::value> struct Kind_;
template <> struct Kind_<Void> { static constexpr Kind kind = Kind::PRIMITIVE; }; template <> struct Kind_<Void> { static constexpr Kind kind = Kind::PRIMITIVE; };
template <> struct Kind_<bool> { static constexpr Kind kind = Kind::PRIMITIVE; }; template <> struct Kind_<bool> { static constexpr Kind kind = Kind::PRIMITIVE; };
...@@ -158,6 +164,17 @@ inline constexpr Kind kind() { ...@@ -158,6 +164,17 @@ inline constexpr Kind kind() {
template <typename T, Kind k = CAPNP_KIND(T)> template <typename T, Kind k = CAPNP_KIND(T)>
struct List; struct List;
#if _MSC_VER
template <typename T, Kind k>
struct List {};
// For some reason, without this declaration, MSVC will error out on some uses of List
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
// is not defined. I do not understand this error, but adding this empty default declaration fixes
// it.
#endif
template <typename T> struct ListElementType_; template <typename T> struct ListElementType_;
template <typename T> struct ListElementType_<List<T>> { typedef T Type; }; template <typename T> struct ListElementType_<List<T>> { typedef T Type; };
template <typename T> using ListElementType = typename ListElementType_<T>::Type; template <typename T> using ListElementType = typename ListElementType_<T>::Type;
...@@ -213,8 +230,21 @@ using FromServer = typename kj::Decay<T>::Serves; ...@@ -213,8 +230,21 @@ using FromServer = typename kj::Decay<T>::Serves;
// FromBuilder<MyType::Server> = MyType (for any Cap'n Proto interface type). // FromBuilder<MyType::Server> = MyType (for any Cap'n Proto interface type).
namespace _ { // private namespace _ { // private
template <typename T, Kind k = CAPNP_KIND(T)> template <typename T, Kind k = CAPNP_KIND(T)>
struct PointerHelpers; struct PointerHelpers;
#if _MSC_VER
template <typename T, Kind k>
struct PointerHelpers {};
// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
// is not defined. I do not understand this error, but adding this empty default declaration fixes
// it.
#endif
} // namespace _ (private) } // namespace _ (private)
struct MessageSize { struct MessageSize {
...@@ -370,12 +400,12 @@ constexpr auto WORDS_PER_POINTER KJ_UNUSED = 1 * WORDS / POINTERS; ...@@ -370,12 +400,12 @@ constexpr auto WORDS_PER_POINTER KJ_UNUSED = 1 * WORDS / POINTERS;
constexpr WordCount POINTER_SIZE_IN_WORDS = 1 * POINTERS * WORDS_PER_POINTER; constexpr WordCount POINTER_SIZE_IN_WORDS = 1 * POINTERS * WORDS_PER_POINTER;
template <typename T> template <typename T>
inline constexpr decltype(BYTES / ELEMENTS) bytesPerElement() { inline KJ_CONSTEXPR() decltype(BYTES / ELEMENTS) bytesPerElement() {
return sizeof(T) * BYTES / ELEMENTS; return sizeof(T) * BYTES / ELEMENTS;
} }
template <typename T> template <typename T>
inline constexpr decltype(BITS / ELEMENTS) bitsPerElement() { inline KJ_CONSTEXPR() decltype(BITS / ELEMENTS) bitsPerElement() {
return sizeof(T) * 8 * BITS / ELEMENTS; return sizeof(T) * 8 * BITS / ELEMENTS;
} }
......
...@@ -31,30 +31,6 @@ namespace capnp { ...@@ -31,30 +31,6 @@ namespace capnp {
namespace _ { // private namespace _ { // private
namespace { namespace {
template <typename T, typename U>
void checkList(T reader, std::initializer_list<U> expected) {
ASSERT_EQ(expected.size(), reader.size());
for (uint i = 0; i < expected.size(); i++) {
EXPECT_EQ(expected.begin()[i], reader[i]);
}
}
template <typename T>
void checkList(T reader, std::initializer_list<float> expected) {
ASSERT_EQ(expected.size(), reader.size());
for (uint i = 0; i < expected.size(); i++) {
EXPECT_FLOAT_EQ(expected.begin()[i], reader[i]);
}
}
template <typename T>
void checkList(T reader, std::initializer_list<double> expected) {
ASSERT_EQ(expected.size(), reader.size());
for (uint i = 0; i < expected.size(); i++) {
EXPECT_DOUBLE_EQ(expected.begin()[i], reader[i]);
}
}
TEST(Encoding, AllTypes) { TEST(Encoding, AllTypes) {
MallocMessageBuilder builder; MallocMessageBuilder builder;
...@@ -541,7 +517,7 @@ TEST(Encoding, SmallStructLists) { ...@@ -541,7 +517,7 @@ TEST(Encoding, SmallStructLists) {
// Should match... // Should match...
EXPECT_EQ(defaultSegment.size(), segment.size()); EXPECT_EQ(defaultSegment.size(), segment.size());
for (size_t i = 0; i < std::min(segment.size(), defaultSegment.size()); i++) { for (size_t i = 0; i < kj::min(segment.size(), defaultSegment.size()); i++) {
EXPECT_EQ(reinterpret_cast<const uint64_t*>(defaultSegment.begin())[i], EXPECT_EQ(reinterpret_cast<const uint64_t*>(defaultSegment.begin())[i],
reinterpret_cast<const uint64_t*>(segment.begin())[i]); reinterpret_cast<const uint64_t*>(segment.begin())[i]);
} }
...@@ -973,16 +949,6 @@ TEST(Encoding, UpgradeStructInBuilderDoubleFarPointers) { ...@@ -973,16 +949,6 @@ TEST(Encoding, UpgradeStructInBuilderDoubleFarPointers) {
EXPECT_EQ(2u, builder.getSegmentsForOutput()[2].size()); EXPECT_EQ(2u, builder.getSegmentsForOutput()[2].size());
} }
void checkList(List<test::TestOldVersion>::Reader reader,
std::initializer_list<int64_t> expectedData,
std::initializer_list<Text::Reader> expectedPointers) {
ASSERT_EQ(expectedData.size(), reader.size());
for (uint i = 0; i < expectedData.size(); i++) {
EXPECT_EQ(expectedData.begin()[i], reader[i].getOld1());
EXPECT_EQ(expectedPointers.begin()[i], reader[i].getOld2());
}
}
void checkUpgradedList(test::TestAnyPointer::Builder root, void checkUpgradedList(test::TestAnyPointer::Builder root,
std::initializer_list<int64_t> expectedData, std::initializer_list<int64_t> expectedData,
std::initializer_list<Text::Reader> expectedPointers) { std::initializer_list<Text::Reader> expectedPointers) {
......
...@@ -43,6 +43,24 @@ namespace _ { // private ...@@ -43,6 +43,24 @@ namespace _ { // private
// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over // Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
// allocation and layout of memory, in order to squeeze out every last drop of performance. // allocation and layout of memory, in order to squeeze out every last drop of performance.
#if _MSC_VER
// Assume Windows is little-endian.
//
// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or
// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC
// intrinsics.
#ifndef __ORDER_BIG_ENDIAN__
#define __ORDER_BIG_ENDIAN__ 4321
#endif
#ifndef __ORDER_LITTLE_ENDIAN__
#define __ORDER_LITTLE_ENDIAN__ 1234
#endif
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif
#endif
#if CAPNP_REVERSE_ENDIAN #if CAPNP_REVERSE_ENDIAN
#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__ #define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__ #define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
......
...@@ -25,12 +25,14 @@ ...@@ -25,12 +25,14 @@
#include "arena.h" #include "arena.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace capnp { #if CAPNP_DEBUG_TYPES
namespace kj {
template <typename T, typename U> template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, kj::Quantity<T, U> value) { std::ostream& operator<<(std::ostream& os, kj::Quantity<T, U> value) {
return os << (value / kj::unit<kj::Quantity<T, U>>()); return os << (value / kj::unit<kj::Quantity<T, U>>());
} }
} }
#endif
namespace capnp { namespace capnp {
namespace _ { // private namespace _ { // private
......
...@@ -960,9 +960,8 @@ struct WireHelpers { ...@@ -960,9 +960,8 @@ struct WireHelpers {
// run with it and do bounds checks at access time, because how would we handle writes? // run with it and do bounds checks at access time, because how would we handle writes?
// Instead, we have to copy the struct to a new space now. // Instead, we have to copy the struct to a new space now.
WordCount newDataSize = std::max<WordCount>(oldDataSize, size.data); WordCount newDataSize = kj::max(oldDataSize, size.data);
WirePointerCount newPointerCount = WirePointerCount newPointerCount = kj::max(oldPointerCount, size.pointers);
std::max<WirePointerCount>(oldPointerCount, size.pointers);
WordCount totalSize = newDataSize + newPointerCount * WORDS_PER_POINTER; WordCount totalSize = newDataSize + newPointerCount * WORDS_PER_POINTER;
// Don't let allocate() zero out the object just yet. // Don't let allocate() zero out the object just yet.
...@@ -1282,9 +1281,8 @@ struct WireHelpers { ...@@ -1282,9 +1281,8 @@ struct WireHelpers {
// The structs in this list are smaller than expected, probably written using an older // The structs in this list are smaller than expected, probably written using an older
// version of the protocol. We need to make a copy and expand them. // version of the protocol. We need to make a copy and expand them.
WordCount newDataSize = std::max<WordCount>(oldDataSize, elementSize.data); WordCount newDataSize = kj::max(oldDataSize, elementSize.data);
WirePointerCount newPointerCount = WirePointerCount newPointerCount = kj::max(oldPointerCount, elementSize.pointers);
std::max<WirePointerCount>(oldPointerCount, elementSize.pointers);
auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS; auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS;
WordCount totalSize = newStep * elementCount; WordCount totalSize = newStep * elementCount;
...@@ -1309,8 +1307,8 @@ struct WireHelpers { ...@@ -1309,8 +1307,8 @@ struct WireHelpers {
// Copy pointer section. // Copy pointer section.
WirePointer* newPointerSection = reinterpret_cast<WirePointer*>(dst + newDataSize); WirePointer* newPointerSection = reinterpret_cast<WirePointer*>(dst + newDataSize);
WirePointer* oldPointerSection = reinterpret_cast<WirePointer*>(src + oldDataSize); WirePointer* oldPointerSection = reinterpret_cast<WirePointer*>(src + oldDataSize);
for (uint i = 0; i < oldPointerCount / POINTERS; i++) { for (uint j = 0; j < oldPointerCount / POINTERS; j++) {
transferPointer(origSegment, newPointerSection + i, oldSegment, oldPointerSection + i); transferPointer(origSegment, newPointerSection + j, oldSegment, oldPointerSection + j);
} }
dst += newStep * (1 * ELEMENTS); dst += newStep * (1 * ELEMENTS);
...@@ -1346,10 +1344,10 @@ struct WireHelpers { ...@@ -1346,10 +1344,10 @@ struct WireHelpers {
WirePointerCount newPointerCount = elementSize.pointers; WirePointerCount newPointerCount = elementSize.pointers;
if (oldSize == ElementSize::POINTER) { if (oldSize == ElementSize::POINTER) {
newPointerCount = std::max(newPointerCount, 1 * POINTERS); newPointerCount = kj::max(newPointerCount, 1 * POINTERS);
} else { } else {
// Old list contains data elements, so we need at least 1 word of data. // Old list contains data elements, so we need at least 1 word of data.
newDataSize = std::max(newDataSize, 1 * WORDS); newDataSize = kj::max(newDataSize, 1 * WORDS);
} }
auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS; auto newStep = (newDataSize + newPointerCount * WORDS_PER_POINTER) / ELEMENTS;
...@@ -1894,7 +1892,12 @@ struct WireHelpers { ...@@ -1894,7 +1892,12 @@ struct WireHelpers {
ElementSize elementSize = ref->listRef.elementSize(); ElementSize elementSize = ref->listRef.elementSize();
if (elementSize == ElementSize::INLINE_COMPOSITE) { if (elementSize == ElementSize::INLINE_COMPOSITE) {
#if _MSC_VER
// TODO(msvc): MSVC thinks decltype(WORDS/ELEMENTS) is a const type. /eyeroll
uint wordsPerElement;
#else
decltype(WORDS/ELEMENTS) wordsPerElement; decltype(WORDS/ELEMENTS) wordsPerElement;
#endif
ElementCount size; ElementCount size;
WordCount wordCount = ref->listRef.inlineCompositeWordCount(); WordCount wordCount = ref->listRef.inlineCompositeWordCount();
...@@ -2312,7 +2315,7 @@ bool PointerReader::isNull() const { ...@@ -2312,7 +2315,7 @@ bool PointerReader::isNull() const {
} }
bool PointerReader::isStruct() const { bool PointerReader::isStruct() const {
word* refTarget; word* refTarget = nullptr;
const WirePointer* ptr = pointer; const WirePointer* ptr = pointer;
SegmentReader* sgmt = segment; SegmentReader* sgmt = segment;
WireHelpers::followFars(ptr, refTarget, sgmt); WireHelpers::followFars(ptr, refTarget, sgmt);
...@@ -2320,7 +2323,7 @@ bool PointerReader::isStruct() const { ...@@ -2320,7 +2323,7 @@ bool PointerReader::isStruct() const {
} }
bool PointerReader::isList() const { bool PointerReader::isList() const {
word* refTarget; word* refTarget = nullptr;
const WirePointer* ptr = pointer; const WirePointer* ptr = pointer;
SegmentReader* sgmt = segment; SegmentReader* sgmt = segment;
WireHelpers::followFars(ptr, refTarget, sgmt); WireHelpers::followFars(ptr, refTarget, sgmt);
......
...@@ -96,7 +96,7 @@ static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = { ...@@ -96,7 +96,7 @@ static constexpr BitsPerElement BITS_PER_ELEMENT_TABLE[8] = {
0 * BITS / ELEMENTS 0 * BITS / ELEMENTS
}; };
inline constexpr BitsPerElement dataBitsPerElement(ElementSize size) { inline KJ_CONSTEXPR() BitsPerElement dataBitsPerElement(ElementSize size) {
return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)]; return _::BITS_PER_ELEMENT_TABLE[static_cast<int>(size)];
} }
...@@ -549,12 +549,26 @@ private: ...@@ -549,12 +549,26 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
#if _MSC_VER
// TODO(msvc): MSVC insists List{Reader,Builder}::operator= are deleted unless we
// define them explicitly. Don't know why, especially for the readers.
#define MSVC_DEFAULT_ASSIGNMENT_WORKAROUND(const_, type) \
inline type& operator=(const_ type& other) { \
memcpy(this, &other, sizeof(*this)); \
return *this; \
}
#else
#define MSVC_DEFAULT_ASSIGNMENT_WORKAROUND(const_, type)
#endif
class ListBuilder: public kj::DisallowConstCopy { class ListBuilder: public kj::DisallowConstCopy {
public: public:
inline ListBuilder() inline ListBuilder()
: segment(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS), : segment(nullptr), ptr(nullptr), elementCount(0 * ELEMENTS),
step(0 * BITS / ELEMENTS) {} step(0 * BITS / ELEMENTS) {}
MSVC_DEFAULT_ASSIGNMENT_WORKAROUND(, ListBuilder);
inline word* getLocation() { inline word* getLocation() {
// Get the object's location. // Get the object's location.
...@@ -631,6 +645,8 @@ public: ...@@ -631,6 +645,8 @@ public:
: segment(nullptr), ptr(nullptr), elementCount(0), step(0 * BITS / ELEMENTS), : segment(nullptr), ptr(nullptr), elementCount(0), step(0 * BITS / ELEMENTS),
structDataSize(0), structPointerCount(0), nestingLimit(0x7fffffff) {} structDataSize(0), structPointerCount(0), nestingLimit(0x7fffffff) {}
MSVC_DEFAULT_ASSIGNMENT_WORKAROUND(const, ListReader);
inline ElementCount size() const; inline ElementCount size() const;
// The number of elements in the list. // The number of elements in the list.
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <exception> #include <exception>
#include <string> #include <string>
#include <vector> #include <vector>
#include <unistd.h>
#include <errno.h> #include <errno.h>
namespace capnp { namespace capnp {
...@@ -193,7 +192,7 @@ kj::ArrayPtr<word> MallocMessageBuilder::allocateSegment(uint minimumSize) { ...@@ -193,7 +192,7 @@ kj::ArrayPtr<word> MallocMessageBuilder::allocateSegment(uint minimumSize) {
ownFirstSegment = true; ownFirstSegment = true;
} }
uint size = std::max(minimumSize, nextSize); uint size = kj::max(minimumSize, nextSize);
void* result = calloc(size, sizeof(word)); void* result = calloc(size, sizeof(word));
if (result == nullptr) { if (result == nullptr) {
......
...@@ -59,7 +59,7 @@ public: ...@@ -59,7 +59,7 @@ public:
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override {
KJ_ASSERT(maxBytes <= data.size() - readPos, "Overran end of stream."); KJ_ASSERT(maxBytes <= data.size() - readPos, "Overran end of stream.");
size_t amount = std::min(maxBytes, std::max(minBytes, preferredReadSize)); size_t amount = kj::min(maxBytes, kj::max(minBytes, preferredReadSize));
memcpy(buffer, data.data() + readPos, amount); memcpy(buffer, data.data() + readPos, amount);
readPos += amount; readPos += amount;
return amount; return amount;
...@@ -71,7 +71,7 @@ public: ...@@ -71,7 +71,7 @@ public:
} }
kj::ArrayPtr<const byte> tryGetReadBuffer() override { kj::ArrayPtr<const byte> tryGetReadBuffer() override {
size_t amount = std::min(data.size() - readPos, preferredReadSize); size_t amount = kj::min(data.size() - readPos, preferredReadSize);
return kj::arrayPtr(reinterpret_cast<const byte*>(data.data() + readPos), amount); return kj::arrayPtr(reinterpret_cast<const byte*>(data.data() + readPos), amount);
} }
...@@ -86,6 +86,8 @@ struct DisplayByteArray { ...@@ -86,6 +86,8 @@ struct DisplayByteArray {
: data(reinterpret_cast<const uint8_t*>(str.data())), size(str.size()) {} : data(reinterpret_cast<const uint8_t*>(str.data())), size(str.size()) {}
DisplayByteArray(const std::initializer_list<uint8_t>& list) DisplayByteArray(const std::initializer_list<uint8_t>& list)
: data(list.begin()), size(list.size()) {} : data(list.begin()), size(list.size()) {}
DisplayByteArray(kj::ArrayPtr<const byte> data)
: data(data.begin()), size(data.size()) {}
const uint8_t* data; const uint8_t* data;
size_t size; size_t size;
...@@ -128,16 +130,15 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked, ...@@ -128,16 +130,15 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked,
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// read // read
std::string roundTrip; kj::Array<byte> roundTrip = kj::heapArray<byte>(unpacked.size());
roundTrip.resize(unpacked.size());
{ {
PackedInputStream packedIn(pipe); PackedInputStream packedIn(pipe);
packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size()); packedIn.InputStream::read(roundTrip.begin(), roundTrip.size());
EXPECT_TRUE(pipe.allRead()); EXPECT_TRUE(pipe.allRead());
} }
if (roundTrip != std::string(reinterpret_cast<const char*>(unpacked.begin()), unpacked.size())) { if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) {
ADD_FAILURE() ADD_FAILURE()
<< "Tried to unpack: " << DisplayByteArray(packed) << "\n" << "Tried to unpack: " << DisplayByteArray(packed) << "\n"
<< "Expected: " << DisplayByteArray(unpacked) << "\n" << "Expected: " << DisplayByteArray(unpacked) << "\n"
...@@ -150,12 +151,11 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked, ...@@ -150,12 +151,11 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked,
{ {
PackedInputStream packedIn(pipe); PackedInputStream packedIn(pipe);
packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size()); packedIn.InputStream::read(roundTrip.begin(), roundTrip.size());
EXPECT_TRUE(pipe.allRead()); EXPECT_TRUE(pipe.allRead());
} }
if (roundTrip != if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) {
std::string(reinterpret_cast<const char*>(unpacked.begin()), unpacked.size())) {
ADD_FAILURE() ADD_FAILURE()
<< "Tried to unpack: " << DisplayByteArray(packed) << "\n" << "Tried to unpack: " << DisplayByteArray(packed) << "\n"
<< " Block size: " << blockSize << "\n" << " Block size: " << blockSize << "\n"
...@@ -202,8 +202,7 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked, ...@@ -202,8 +202,7 @@ void expectPacksTo(std::initializer_list<uint8_t> unpacked,
PackedInputStream packedIn(pipe); PackedInputStream packedIn(pipe);
packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size()); packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size());
if (roundTrip != if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) {
std::string(reinterpret_cast<const char*>(unpacked.begin()), unpacked.size())) {
ADD_FAILURE() ADD_FAILURE()
<< "Tried to unpack: " << DisplayByteArray(packed) << "\n" << "Tried to unpack: " << DisplayByteArray(packed) << "\n"
<< " Index: " << i << "\n" << " Index: " << i << "\n"
......
...@@ -304,7 +304,7 @@ int mkstemp(char *tpl) { ...@@ -304,7 +304,7 @@ int mkstemp(char *tpl) {
int error = errno; int error = errno;
if (error != EEXIST && error != EINTR) { if (error != EEXIST && error != EINTR) {
KJ_FAIL_SYSCALL("open(mktemp())", error); KJ_FAIL_SYSCALL("open(mktemp())", error, tpl);
} }
memset(end, 'X', strlen(end)); memset(end, 'X', strlen(end));
...@@ -313,7 +313,12 @@ int mkstemp(char *tpl) { ...@@ -313,7 +313,12 @@ int mkstemp(char *tpl) {
#endif #endif
TEST(Serialize, FileDescriptors) { TEST(Serialize, FileDescriptors) {
#if _WIN32
// TODO(cleanup): Find the Windows temp directory? Seems overly difficult.
char filename[] = "capnproto-serialize-test-XXXXXX";
#else
char filename[] = "/tmp/capnproto-serialize-test-XXXXXX"; char filename[] = "/tmp/capnproto-serialize-test-XXXXXX";
#endif
kj::AutoCloseFd tmpfile(mkstemp(filename)); kj::AutoCloseFd tmpfile(mkstemp(filename));
ASSERT_GE(tmpfile.get(), 0); ASSERT_GE(tmpfile.get(), 0);
......
...@@ -49,15 +49,17 @@ FlatArrayMessageReader::FlatArrayMessageReader( ...@@ -49,15 +49,17 @@ FlatArrayMessageReader::FlatArrayMessageReader(
return; return;
} }
uint segmentSize = table[1].get(); {
uint segmentSize = table[1].get();
KJ_REQUIRE(array.size() >= offset + segmentSize, KJ_REQUIRE(array.size() >= offset + segmentSize,
"Message ends prematurely in first segment.") { "Message ends prematurely in first segment.") {
return; return;
} }
segment0 = array.slice(offset, offset + segmentSize); segment0 = array.slice(offset, offset + segmentSize);
offset += segmentSize; offset += segmentSize;
}
if (segmentCount > 1) { if (segmentCount > 1) {
moreSegments = kj::heapArray<kj::ArrayPtr<const word>>(segmentCount - 1); moreSegments = kj::heapArray<kj::ArrayPtr<const word>>(segmentCount - 1);
...@@ -154,9 +156,9 @@ InputStreamMessageReader::InputStreamMessageReader( ...@@ -154,9 +156,9 @@ InputStreamMessageReader::InputStreamMessageReader(
} }
// Read sizes for all segments except the first. Include padding if necessary. // Read sizes for all segments except the first. Include padding if necessary.
_::WireValue<uint32_t> moreSizes[segmentCount & ~1]; KJ_STACK_ARRAY(_::WireValue<uint32_t>, moreSizes, segmentCount & ~1, 16, 64);
if (segmentCount > 1) { if (segmentCount > 1) {
inputStream.read(moreSizes, sizeof(moreSizes)); inputStream.read(moreSizes.begin(), moreSizes.size() * sizeof(moreSizes[0]));
for (uint i = 0; i < segmentCount - 1; i++) { for (uint i = 0; i < segmentCount - 1; i++) {
totalWords += moreSizes[i].get(); totalWords += moreSizes[i].get();
} }
...@@ -239,7 +241,7 @@ kj::ArrayPtr<const word> InputStreamMessageReader::getSegment(uint id) { ...@@ -239,7 +241,7 @@ kj::ArrayPtr<const word> InputStreamMessageReader::getSegment(uint id) {
void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) { void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message."); KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message.");
_::WireValue<uint32_t> table[(segments.size() + 2) & ~size_t(1)]; KJ_STACK_ARRAY(_::WireValue<uint32_t>, table, (segments.size() + 2) & ~size_t(1), 16, 64);
// We write the segment count - 1 because this makes the first word zero for single-segment // We write the segment count - 1 because this makes the first word zero for single-segment
// messages, improving compression. We don't bother doing this with segment sizes because // messages, improving compression. We don't bother doing this with segment sizes because
...@@ -254,7 +256,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons ...@@ -254,7 +256,7 @@ void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<cons
} }
KJ_STACK_ARRAY(kj::ArrayPtr<const byte>, pieces, segments.size() + 1, 4, 32); KJ_STACK_ARRAY(kj::ArrayPtr<const byte>, pieces, segments.size() + 1, 4, 32);
pieces[0] = kj::arrayPtr(reinterpret_cast<byte*>(table), sizeof(table)); pieces[0] = kj::arrayPtr(reinterpret_cast<byte*>(table.begin()), table.size() * sizeof(table[0]));
for (uint i = 0; i < segments.size(); i++) { for (uint i = 0; i < segments.size(); i++) {
pieces[i + 1] = kj::arrayPtr(reinterpret_cast<const byte*>(segments[i].begin()), pieces[i + 1] = kj::arrayPtr(reinterpret_cast<const byte*>(segments[i].begin()),
......
...@@ -56,7 +56,7 @@ void genericInitTestMessage(Builder builder) { ...@@ -56,7 +56,7 @@ void genericInitTestMessage(Builder builder) {
subBuilder.setUInt16Field(1234u); subBuilder.setUInt16Field(1234u);
subBuilder.setUInt32Field(56789012u); subBuilder.setUInt32Field(56789012u);
subBuilder.setUInt64Field(345678901234567890ull); subBuilder.setUInt64Field(345678901234567890ull);
subBuilder.setFloat32Field(-1.25e-10); subBuilder.setFloat32Field(-1.25e-10f);
subBuilder.setFloat64Field(345); subBuilder.setFloat64Field(345);
subBuilder.setTextField("baz"); subBuilder.setTextField("baz");
subBuilder.setDataField(data("qux")); subBuilder.setDataField(data("qux"));
...@@ -78,7 +78,7 @@ void genericInitTestMessage(Builder builder) { ...@@ -78,7 +78,7 @@ void genericInitTestMessage(Builder builder) {
subBuilder.setUInt16List({1234u, 5678u, 0u, 0xffffu}); subBuilder.setUInt16List({1234u, 5678u, 0u, 0xffffu});
subBuilder.setUInt32List({12345678u, 90123456u, 0u, 0xffffffffu}); subBuilder.setUInt32List({12345678u, 90123456u, 0u, 0xffffffffu});
subBuilder.setUInt64List({123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull}); subBuilder.setUInt64List({123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull});
subBuilder.setFloat32List({0, 1234567, 1e37, -1e37, 1e-37, -1e-37}); subBuilder.setFloat32List({0, 1234567, 1e37f, -1e37f, 1e-37f, -1e-37f});
subBuilder.setFloat64List({0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306}); subBuilder.setFloat64List({0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306});
subBuilder.setTextList({"quux", "corge", "grault"}); subBuilder.setTextList({"quux", "corge", "grault"});
subBuilder.setDataList({data("garply"), data("waldo"), data("fred")}); subBuilder.setDataList({data("garply"), data("waldo"), data("fred")});
......
...@@ -112,27 +112,44 @@ void checkDynamicTestMessageAllZero(DynamicStruct::Builder builder); ...@@ -112,27 +112,44 @@ void checkDynamicTestMessageAllZero(DynamicStruct::Builder builder);
void checkDynamicTestMessageAllZero(DynamicStruct::Reader reader); void checkDynamicTestMessageAllZero(DynamicStruct::Reader reader);
#endif // !CAPNP_LITE #endif // !CAPNP_LITE
template <typename T, typename U> template <typename T>
void checkList(T reader, std::initializer_list<U> expected) { inline void checkElement(T a, T b) {
EXPECT_EQ(a, b);
}
template <>
inline void checkElement<float>(float a, float b) {
EXPECT_FLOAT_EQ(a, b);
}
template <>
inline void checkElement<double>(double a, double b) {
EXPECT_DOUBLE_EQ(a, b);
}
template <typename T, typename L = T::Reads>
void checkList(T reader, std::initializer_list<decltype(reader[0])> expected) {
ASSERT_EQ(expected.size(), reader.size()); ASSERT_EQ(expected.size(), reader.size());
for (uint i = 0; i < expected.size(); i++) { for (uint i = 0; i < expected.size(); i++) {
EXPECT_EQ(expected.begin()[i], reader[i]); checkElement<decltype(reader[0])>(expected.begin()[i], reader[i]);
} }
} }
template <typename T> template <typename T, typename L = T::Builds, bool = false>
void checkList(T reader, std::initializer_list<float> expected) { void checkList(T reader, std::initializer_list<decltype(L::Reader()[0])> expected) {
ASSERT_EQ(expected.size(), reader.size()); ASSERT_EQ(expected.size(), reader.size());
for (uint i = 0; i < expected.size(); i++) { for (uint i = 0; i < expected.size(); i++) {
EXPECT_FLOAT_EQ(expected.begin()[i], reader[i]); checkElement<decltype(L::Reader()[0])>(expected.begin()[i], reader[i]);
} }
} }
template <typename T> inline void checkList(List<test::TestOldVersion>::Reader reader,
void checkList(T reader, std::initializer_list<double> expected) { std::initializer_list<int64_t> expectedData,
ASSERT_EQ(expected.size(), reader.size()); std::initializer_list<Text::Reader> expectedPointers) {
for (uint i = 0; i < expected.size(); i++) { ASSERT_EQ(expectedData.size(), reader.size());
EXPECT_DOUBLE_EQ(expected.begin()[i], reader[i]); for (uint i = 0; i < expectedData.size(); i++) {
EXPECT_EQ(expectedData.begin()[i], reader[i].getOld1());
EXPECT_EQ(expectedPointers.begin()[i], reader[i].getOld2());
} }
} }
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include "common.h" #include "common.h"
#include "debug.h" #include "debug.h"
#include <stdlib.h> #include <stdlib.h>
#ifdef _MSC_VER
#include <limits>
#endif
namespace kj { namespace kj {
namespace _ { // private namespace _ { // private
...@@ -56,4 +59,11 @@ void unreachable() { ...@@ -56,4 +59,11 @@ void unreachable() {
} }
} // namespace _ (private) } // namespace _ (private)
#if _MSC_VER
float nan() { return std::numeric_limits<float>::quiet_NaN(); }
#endif
} // namespace kj } // namespace kj
...@@ -461,9 +461,17 @@ template<typename T> constexpr T cp(T& t) noexcept { return t; } ...@@ -461,9 +461,17 @@ template<typename T> constexpr T cp(T& t) noexcept { return t; }
template<typename T> constexpr T cp(const T& t) noexcept { return t; } template<typename T> constexpr T cp(const T& t) noexcept { return t; }
// Useful to force a copy, particularly to pass into a function that expects T&&. // Useful to force a copy, particularly to pass into a function that expects T&&.
template <typename T, typename U, bool takeT> struct MinType_;
template <typename T, typename U> struct MinType_<T, U, true> { typedef T Type; };
template <typename T, typename U> struct MinType_<T, U, false> { typedef U Type; };
template <typename T, typename U>
using MinType = typename MinType_<T, U, sizeof(T) <= sizeof(U)>::Type;
// Resolves to the smaller of the two input types.
template <typename T, typename U> template <typename T, typename U>
inline KJ_CONSTEXPR() auto min(T&& a, U&& b) -> Decay<decltype(a < b ? a : b)> { inline KJ_CONSTEXPR() auto min(T&& a, U&& b) -> MinType<Decay<T>, Decay<U>> {
return a < b ? a : b; return MinType<Decay<T>, Decay<U>>(a < b ? a : b);
} }
template <typename T, typename U> template <typename T, typename U>
...@@ -555,13 +563,23 @@ static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_(); ...@@ -555,13 +563,23 @@ static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_();
#if __GNUC__ #if __GNUC__
inline constexpr float inf() { return __builtin_huge_valf(); } inline constexpr float inf() { return __builtin_huge_valf(); }
inline constexpr float nan() { return __builtin_nanf(""); } inline constexpr float nan() { return __builtin_nanf(""); }
#elif _MSC_VER #elif _MSC_VER
// Do what MSVC math.h does
#pragma warning(push) // Do what MSVC math.h does
#pragma warning(disable: 4756) // "overflow in constant arithmetic" #pragma warning(push)
inline constexpr float inf() { return (float)(1e300 * 1e300); } #pragma warning(disable: 4756) // "overflow in constant arithmetic"
#pragma warning(pop) inline constexpr float inf() { return (float)(1e300 * 1e300); }
inline constexpr float nan() { return inf() * 0.0F; } #pragma warning(pop)
float nan();
// Unfortunatley, inf() * 0.0f produces a NaN with the sign bit set, whereas our preferred
// canonical NaN should not have the sign bit set. std::numeric_limits<float>::quiet_NaN()
// returns the correct NaN, but we don't want to #include that here. So, we give up and make
// this out-of-line on MSVC.
//
// TODO(msvc): Can we do better?
#else #else
#error "Not sure how to support your compiler." #error "Not sure how to support your compiler."
#endif #endif
......
...@@ -22,19 +22,23 @@ ...@@ -22,19 +22,23 @@
#include "mutex.h" #include "mutex.h"
#include "debug.h" #include "debug.h"
#include "thread.h" #include "thread.h"
#include <unistd.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#if _WIN32 #if _WIN32
#include <windows.h> #include <windows.h>
#else #else
#include <pthread.h> #include <pthread.h>
#include <unistd.h>
#endif #endif
namespace kj { namespace kj {
namespace { namespace {
#if _WIN32
inline void delay() { Sleep(10); }
#else
inline void delay() { usleep(10000); } inline void delay() { usleep(10000); }
#endif
#if KJ_NO_EXCEPTIONS #if KJ_NO_EXCEPTIONS
#undef EXPECT_ANY_THROW #undef EXPECT_ANY_THROW
...@@ -128,18 +132,18 @@ TEST(Mutex, MutexGuarded) { ...@@ -128,18 +132,18 @@ TEST(Mutex, MutexGuarded) {
TEST(Mutex, Lazy) { TEST(Mutex, Lazy) {
Lazy<uint> lazy; Lazy<uint> lazy;
bool initStarted = false; volatile bool initStarted = false;
Thread thread([&]() { Thread thread([&]() {
EXPECT_EQ(123u, lazy.get([&](SpaceFor<uint>& space) -> Own<uint> { EXPECT_EQ(123u, lazy.get([&](SpaceFor<uint>& space) -> Own<uint> {
__atomic_store_n(&initStarted, true, __ATOMIC_RELAXED); initStarted = true;
delay(); delay();
return space.construct(123); return space.construct(123);
})); }));
}); });
// Spin until the initializer has been entered in the thread. // Spin until the initializer has been entered in the thread.
while (!__atomic_load_n(&initStarted, __ATOMIC_RELAXED)) { while (!initStarted) {
#if _WIN32 #if _WIN32
Sleep(0); Sleep(0);
#else #else
......
...@@ -243,7 +243,7 @@ void Mutex::assertLockedByCaller(Exclusivity exclusivity) { ...@@ -243,7 +243,7 @@ void Mutex::assertLockedByCaller(Exclusivity exclusivity) {
// held for debug purposes anyway, we just don't bother. // held for debug purposes anyway, we just don't bother.
} }
static BOOL nullInitializer(PINIT_ONCE initOnce, PVOID parameter, PVOID* context) { static BOOL WINAPI nullInitializer(PINIT_ONCE initOnce, PVOID parameter, PVOID* context) {
return true; return true;
} }
......
...@@ -61,7 +61,7 @@ private: ...@@ -61,7 +61,7 @@ private:
bool detached = false; bool detached = false;
#if _WIN32 #if _WIN32
static unsigned long runThread(void* ptr); static unsigned long __stdcall runThread(void* ptr);
#else #else
static void* runThread(void* ptr); static void* runThread(void* ptr);
#endif #endif
......
...@@ -67,6 +67,10 @@ struct Id { ...@@ -67,6 +67,10 @@ struct Id {
// ======================================================================================= // =======================================================================================
// Quantity and UnitRatio -- implement unit analysis via the type system // Quantity and UnitRatio -- implement unit analysis via the type system
#if !_MSC_VER
// TODO(msvc): MSVC has trouble with this intense templating. Luckily Cap'n Proto can deal with
// using regular integers in place of Quantity, so we can just skip all this.
template <typename T> constexpr bool isIntegral() { return false; } template <typename T> constexpr bool isIntegral() { return false; }
template <> constexpr bool isIntegral<char>() { return true; } template <> constexpr bool isIntegral<char>() { return true; }
template <> constexpr bool isIntegral<signed char>() { return true; } template <> constexpr bool isIntegral<signed char>() { return true; }
...@@ -350,11 +354,15 @@ private: ...@@ -350,11 +354,15 @@ private:
friend inline constexpr T unit(); friend inline constexpr T unit();
}; };
#endif // !_MSC_VER
template <typename T> template <typename T>
inline constexpr T unit() { return T(1); } inline constexpr T unit() { return T(1); }
// unit<Quantity<T, U>>() returns a Quantity of value 1. It also, intentionally, works on basic // unit<Quantity<T, U>>() returns a Quantity of value 1. It also, intentionally, works on basic
// numeric types. // numeric types.
#if !_MSC_VER
template <typename Number1, typename Number2, typename Unit> template <typename Number1, typename Number2, typename Unit>
inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit> b) inline constexpr auto operator*(Number1 a, Quantity<Number2, Unit> b)
-> Quantity<decltype(Number1(1) * Number2(1)), Unit> { -> Quantity<decltype(Number1(1) * Number2(1)), Unit> {
...@@ -425,6 +433,8 @@ inline constexpr T origin() { return T(0 * unit<UnitOf<T>>()); } ...@@ -425,6 +433,8 @@ inline constexpr T origin() { return T(0 * unit<UnitOf<T>>()); }
// origin<Absolute<T, U>>() returns an Absolute of value 0. It also, intentionally, works on basic // origin<Absolute<T, U>>() returns an Absolute of value 0. It also, intentionally, works on basic
// numeric types. // numeric types.
#endif // !_MSC_VER
} // namespace kj } // namespace kj
#endif // KJ_UNITS_H_ #endif // KJ_UNITS_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