layout-test.c++ (17923B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #define CAPNP_PRIVATE 23 #include "layout.h" 24 #include "message.h" 25 #include "arena.h" 26 #include <kj/compat/gtest.h> 27 28 #if CAPNP_DEBUG_TYPES 29 namespace kj { 30 template <typename T, typename U> 31 String KJ_STRINGIFY(kj::Quantity<T, U> value) { 32 return kj::str(unboundAs<uint64_t>(value / kj::unit<kj::Quantity<T, U>>())); 33 } 34 35 // Hack: Allow direct comparisons and multiplications so that we don't have to rewrite the code 36 // below. 37 template <uint64_t maxN, typename T> 38 inline constexpr Bounded<65535, T> operator*(uint a, Bounded<maxN, T> b) { 39 return assumeBits<16>(a * unbound(b)); 40 } 41 template <uint b> 42 inline constexpr Bounded<65535, uint> operator*(uint a, BoundedConst<b>) { 43 return assumeBits<16>(a * b); 44 } 45 } 46 #endif 47 48 namespace capnp { 49 namespace _ { // private 50 namespace { 51 52 TEST(WireFormat, SimpleRawDataStruct) { 53 AlignedData<2> data = {{ 54 // Struct ref, offset = 1, dataSize = 1, pointerCount = 0 55 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 56 // Content for the data section. 57 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 58 }}; 59 60 StructReader reader = PointerReader::getRootUnchecked(data.words).getStruct(nullptr); 61 62 EXPECT_EQ(0xefcdab8967452301ull, reader.getDataField<uint64_t>(0 * ELEMENTS)); 63 EXPECT_EQ(0u, reader.getDataField<uint64_t>(1 * ELEMENTS)); 64 EXPECT_EQ(0x67452301u, reader.getDataField<uint32_t>(0 * ELEMENTS)); 65 EXPECT_EQ(0xefcdab89u, reader.getDataField<uint32_t>(1 * ELEMENTS)); 66 EXPECT_EQ(0u, reader.getDataField<uint32_t>(2 * ELEMENTS)); 67 EXPECT_EQ(0x2301u, reader.getDataField<uint16_t>(0 * ELEMENTS)); 68 EXPECT_EQ(0x6745u, reader.getDataField<uint16_t>(1 * ELEMENTS)); 69 EXPECT_EQ(0xab89u, reader.getDataField<uint16_t>(2 * ELEMENTS)); 70 EXPECT_EQ(0xefcdu, reader.getDataField<uint16_t>(3 * ELEMENTS)); 71 EXPECT_EQ(0u, reader.getDataField<uint16_t>(4 * ELEMENTS)); 72 73 EXPECT_EQ(321u ^ 0xefcdab8967452301ull, reader.getDataField<uint64_t>(0 * ELEMENTS, 321u)); 74 EXPECT_EQ(321u ^ 0x67452301u, reader.getDataField<uint32_t>(0 * ELEMENTS, 321u)); 75 EXPECT_EQ(321u ^ 0x2301u, reader.getDataField<uint16_t>(0 * ELEMENTS, 321u)); 76 EXPECT_EQ(321u, reader.getDataField<uint64_t>(1 * ELEMENTS, 321u)); 77 EXPECT_EQ(321u, reader.getDataField<uint32_t>(2 * ELEMENTS, 321u)); 78 EXPECT_EQ(321u, reader.getDataField<uint16_t>(4 * ELEMENTS, 321u)); 79 80 // Bits 81 EXPECT_TRUE (reader.getDataField<bool>(0 * ELEMENTS)); 82 EXPECT_FALSE(reader.getDataField<bool>(1 * ELEMENTS)); 83 EXPECT_FALSE(reader.getDataField<bool>(2 * ELEMENTS)); 84 EXPECT_FALSE(reader.getDataField<bool>(3 * ELEMENTS)); 85 EXPECT_FALSE(reader.getDataField<bool>(4 * ELEMENTS)); 86 EXPECT_FALSE(reader.getDataField<bool>(5 * ELEMENTS)); 87 EXPECT_FALSE(reader.getDataField<bool>(6 * ELEMENTS)); 88 EXPECT_FALSE(reader.getDataField<bool>(7 * ELEMENTS)); 89 90 EXPECT_TRUE (reader.getDataField<bool>( 8 * ELEMENTS)); 91 EXPECT_TRUE (reader.getDataField<bool>( 9 * ELEMENTS)); 92 EXPECT_FALSE(reader.getDataField<bool>(10 * ELEMENTS)); 93 EXPECT_FALSE(reader.getDataField<bool>(11 * ELEMENTS)); 94 EXPECT_FALSE(reader.getDataField<bool>(12 * ELEMENTS)); 95 EXPECT_TRUE (reader.getDataField<bool>(13 * ELEMENTS)); 96 EXPECT_FALSE(reader.getDataField<bool>(14 * ELEMENTS)); 97 EXPECT_FALSE(reader.getDataField<bool>(15 * ELEMENTS)); 98 99 EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS)); 100 EXPECT_FALSE(reader.getDataField<bool>(64 * ELEMENTS)); 101 102 EXPECT_TRUE (reader.getDataField<bool>(0 * ELEMENTS, false)); 103 EXPECT_FALSE(reader.getDataField<bool>(1 * ELEMENTS, false)); 104 EXPECT_TRUE (reader.getDataField<bool>(63 * ELEMENTS, false)); 105 EXPECT_FALSE(reader.getDataField<bool>(64 * ELEMENTS, false)); 106 EXPECT_FALSE(reader.getDataField<bool>(0 * ELEMENTS, true)); 107 EXPECT_TRUE (reader.getDataField<bool>(1 * ELEMENTS, true)); 108 EXPECT_FALSE(reader.getDataField<bool>(63 * ELEMENTS, true)); 109 EXPECT_TRUE (reader.getDataField<bool>(64 * ELEMENTS, true)); 110 } 111 112 static const AlignedData<2> SUBSTRUCT_DEFAULT = {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; 113 static const AlignedData<2> STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT = 114 {{0,0,0,0,1,0,0,0, 0,0,0,0,0,0,0,0}}; 115 116 static constexpr StructSize STRUCTLIST_ELEMENT_SIZE(1 * WORDS, 1 * POINTERS); 117 118 static void setupStruct(StructBuilder builder) { 119 builder.setDataField<uint64_t>(0 * ELEMENTS, 0x1011121314151617ull); 120 builder.setDataField<uint32_t>(2 * ELEMENTS, 0x20212223u); 121 builder.setDataField<uint16_t>(6 * ELEMENTS, 0x3031u); 122 builder.setDataField<uint8_t>(14 * ELEMENTS, 0x40u); 123 builder.setDataField<bool>(120 * ELEMENTS, false); 124 builder.setDataField<bool>(121 * ELEMENTS, false); 125 builder.setDataField<bool>(122 * ELEMENTS, true); 126 builder.setDataField<bool>(123 * ELEMENTS, false); 127 builder.setDataField<bool>(124 * ELEMENTS, true); 128 builder.setDataField<bool>(125 * ELEMENTS, true); 129 builder.setDataField<bool>(126 * ELEMENTS, true); 130 builder.setDataField<bool>(127 * ELEMENTS, false); 131 132 { 133 StructBuilder subStruct = builder.getPointerField(0 * POINTERS).initStruct( 134 StructSize(1 * WORDS, 0 * POINTERS)); 135 subStruct.setDataField<uint32_t>(0 * ELEMENTS, 123); 136 } 137 138 { 139 ListBuilder list = builder.getPointerField(1 * POINTERS) 140 .initList(ElementSize::FOUR_BYTES, 3 * ELEMENTS); 141 EXPECT_EQ(3 * ELEMENTS, list.size()); 142 list.setDataElement<int32_t>(0 * ELEMENTS, 200); 143 list.setDataElement<int32_t>(1 * ELEMENTS, 201); 144 list.setDataElement<int32_t>(2 * ELEMENTS, 202); 145 } 146 147 { 148 ListBuilder list = builder.getPointerField(2 * POINTERS).initStructList( 149 4 * ELEMENTS, STRUCTLIST_ELEMENT_SIZE); 150 EXPECT_EQ(4 * ELEMENTS, list.size()); 151 for (int i = 0; i < 4; i++) { 152 StructBuilder element = list.getStructElement(i * ELEMENTS); 153 element.setDataField<int32_t>(0 * ELEMENTS, 300 + i); 154 element.getPointerField(0 * POINTERS) 155 .initStruct(StructSize(1 * WORDS, 0 * POINTERS)) 156 .setDataField<int32_t>(0 * ELEMENTS, 400 + i); 157 } 158 } 159 160 { 161 ListBuilder list = builder.getPointerField(3 * POINTERS) 162 .initList(ElementSize::POINTER, 5 * ELEMENTS); 163 EXPECT_EQ(5 * ELEMENTS, list.size()); 164 for (uint i = 0; i < 5; i++) { 165 ListBuilder element = list.getPointerElement(i * ELEMENTS) 166 .initList(ElementSize::TWO_BYTES, (i + 1) * ELEMENTS); 167 EXPECT_EQ((i + 1) * ELEMENTS, element.size()); 168 for (uint j = 0; j <= i; j++) { 169 element.setDataElement<uint16_t>(j * ELEMENTS, 500 + j); 170 } 171 } 172 } 173 } 174 175 static void checkStruct(StructBuilder builder) { 176 EXPECT_EQ(0x1011121314151617ull, builder.getDataField<uint64_t>(0 * ELEMENTS)); 177 EXPECT_EQ(0x20212223u, builder.getDataField<uint32_t>(2 * ELEMENTS)); 178 EXPECT_EQ(0x3031u, builder.getDataField<uint16_t>(6 * ELEMENTS)); 179 EXPECT_EQ(0x40u, builder.getDataField<uint8_t>(14 * ELEMENTS)); 180 EXPECT_FALSE(builder.getDataField<bool>(120 * ELEMENTS)); 181 EXPECT_FALSE(builder.getDataField<bool>(121 * ELEMENTS)); 182 EXPECT_TRUE (builder.getDataField<bool>(122 * ELEMENTS)); 183 EXPECT_FALSE(builder.getDataField<bool>(123 * ELEMENTS)); 184 EXPECT_TRUE (builder.getDataField<bool>(124 * ELEMENTS)); 185 EXPECT_TRUE (builder.getDataField<bool>(125 * ELEMENTS)); 186 EXPECT_TRUE (builder.getDataField<bool>(126 * ELEMENTS)); 187 EXPECT_FALSE(builder.getDataField<bool>(127 * ELEMENTS)); 188 189 { 190 StructBuilder subStruct = builder.getPointerField(0 * POINTERS).getStruct( 191 StructSize(1 * WORDS, 0 * POINTERS), SUBSTRUCT_DEFAULT.words); 192 EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS)); 193 } 194 195 { 196 ListBuilder list = builder.getPointerField(1 * POINTERS) 197 .getList(ElementSize::FOUR_BYTES, nullptr); 198 ASSERT_EQ(3 * ELEMENTS, list.size()); 199 EXPECT_EQ(200, list.getDataElement<int32_t>(0 * ELEMENTS)); 200 EXPECT_EQ(201, list.getDataElement<int32_t>(1 * ELEMENTS)); 201 EXPECT_EQ(202, list.getDataElement<int32_t>(2 * ELEMENTS)); 202 } 203 204 { 205 ListBuilder list = builder.getPointerField(2 * POINTERS) 206 .getStructList(STRUCTLIST_ELEMENT_SIZE, nullptr); 207 ASSERT_EQ(4 * ELEMENTS, list.size()); 208 for (int i = 0; i < 4; i++) { 209 StructBuilder element = list.getStructElement(i * ELEMENTS); 210 EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS)); 211 EXPECT_EQ(400 + i, 212 element.getPointerField(0 * POINTERS) 213 .getStruct(StructSize(1 * WORDS, 0 * POINTERS), 214 STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) 215 .getDataField<int32_t>(0 * ELEMENTS)); 216 } 217 } 218 219 { 220 ListBuilder list = builder.getPointerField(3 * POINTERS).getList(ElementSize::POINTER, nullptr); 221 ASSERT_EQ(5 * ELEMENTS, list.size()); 222 for (uint i = 0; i < 5; i++) { 223 ListBuilder element = list.getPointerElement(i * ELEMENTS) 224 .getList(ElementSize::TWO_BYTES, nullptr); 225 ASSERT_EQ((i + 1) * ELEMENTS, element.size()); 226 for (uint j = 0; j <= i; j++) { 227 EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); 228 } 229 } 230 } 231 } 232 233 static void checkStruct(StructReader reader) { 234 EXPECT_EQ(0x1011121314151617ull, reader.getDataField<uint64_t>(0 * ELEMENTS)); 235 EXPECT_EQ(0x20212223u, reader.getDataField<uint32_t>(2 * ELEMENTS)); 236 EXPECT_EQ(0x3031u, reader.getDataField<uint16_t>(6 * ELEMENTS)); 237 EXPECT_EQ(0x40u, reader.getDataField<uint8_t>(14 * ELEMENTS)); 238 EXPECT_FALSE(reader.getDataField<bool>(120 * ELEMENTS)); 239 EXPECT_FALSE(reader.getDataField<bool>(121 * ELEMENTS)); 240 EXPECT_TRUE (reader.getDataField<bool>(122 * ELEMENTS)); 241 EXPECT_FALSE(reader.getDataField<bool>(123 * ELEMENTS)); 242 EXPECT_TRUE (reader.getDataField<bool>(124 * ELEMENTS)); 243 EXPECT_TRUE (reader.getDataField<bool>(125 * ELEMENTS)); 244 EXPECT_TRUE (reader.getDataField<bool>(126 * ELEMENTS)); 245 EXPECT_FALSE(reader.getDataField<bool>(127 * ELEMENTS)); 246 247 { 248 StructReader subStruct = reader.getPointerField(0 * POINTERS) 249 .getStruct(SUBSTRUCT_DEFAULT.words); 250 EXPECT_EQ(123u, subStruct.getDataField<uint32_t>(0 * ELEMENTS)); 251 } 252 253 { 254 ListReader list = reader.getPointerField(1 * POINTERS).getList(ElementSize::FOUR_BYTES, nullptr); 255 ASSERT_EQ(3 * ELEMENTS, list.size()); 256 EXPECT_EQ(200, list.getDataElement<int32_t>(0 * ELEMENTS)); 257 EXPECT_EQ(201, list.getDataElement<int32_t>(1 * ELEMENTS)); 258 EXPECT_EQ(202, list.getDataElement<int32_t>(2 * ELEMENTS)); 259 } 260 261 { 262 ListReader list = reader.getPointerField(2 * POINTERS) 263 .getList(ElementSize::INLINE_COMPOSITE, nullptr); 264 ASSERT_EQ(4 * ELEMENTS, list.size()); 265 for (int i = 0; i < 4; i++) { 266 StructReader element = list.getStructElement(i * ELEMENTS); 267 EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS)); 268 EXPECT_EQ(400 + i, 269 element.getPointerField(0 * POINTERS) 270 .getStruct(STRUCTLIST_ELEMENT_SUBSTRUCT_DEFAULT.words) 271 .getDataField<int32_t>(0 * ELEMENTS)); 272 } 273 } 274 275 { 276 ListReader list = reader.getPointerField(3 * POINTERS).getList(ElementSize::POINTER, nullptr); 277 ASSERT_EQ(5 * ELEMENTS, list.size()); 278 for (uint i = 0; i < 5; i++) { 279 ListReader element = list.getPointerElement(i * ELEMENTS) 280 .getList(ElementSize::TWO_BYTES, nullptr); 281 ASSERT_EQ((i + 1) * ELEMENTS, element.size()); 282 for (uint j = 0; j <= i; j++) { 283 EXPECT_EQ(500u + j, element.getDataElement<uint16_t>(j * ELEMENTS)); 284 } 285 } 286 } 287 } 288 289 TEST(WireFormat, StructRoundTrip_OneSegment) { 290 MallocMessageBuilder message; 291 BuilderArena arena(&message); 292 auto allocation = arena.allocate(1 * WORDS); 293 SegmentBuilder* segment = allocation.segment; 294 word* rootLocation = allocation.words; 295 296 StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) 297 .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); 298 setupStruct(builder); 299 300 // word count: 301 // 1 root pointer 302 // 6 root struct 303 // 1 sub message 304 // 2 3-element int32 list 305 // 13 struct list 306 // 1 tag 307 // 12 4x struct 308 // 1 data section 309 // 1 pointer section 310 // 1 sub-struct 311 // 11 list list 312 // 5 pointers to sub-lists 313 // 6 sub-lists (4x 1 word, 1x 2 words) 314 // ----- 315 // 34 316 kj::ArrayPtr<const kj::ArrayPtr<const word>> segments = arena.getSegmentsForOutput(); 317 ASSERT_EQ(1u, segments.size()); 318 EXPECT_EQ(34u, segments[0].size()); 319 320 checkStruct(builder); 321 checkStruct(builder.asReader()); 322 checkStruct(PointerReader::getRootUnchecked(segment->getStartPtr()).getStruct(nullptr)); 323 checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) 324 .getStruct(nullptr)); 325 } 326 327 TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { 328 MallocMessageBuilder message(0, AllocationStrategy::FIXED_SIZE); 329 BuilderArena arena(&message); 330 auto allocation = arena.allocate(1 * WORDS); 331 SegmentBuilder* segment = allocation.segment; 332 word* rootLocation = allocation.words; 333 334 StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) 335 .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); 336 setupStruct(builder); 337 338 // Verify that we made 15 segments. 339 kj::ArrayPtr<const kj::ArrayPtr<const word>> segments = arena.getSegmentsForOutput(); 340 ASSERT_EQ(15u, segments.size()); 341 342 // Check that each segment has the expected size. Recall that the first word of each segment will 343 // actually be a pointer to the first thing allocated within that segment. 344 EXPECT_EQ( 1u, segments[ 0].size()); // root ref 345 EXPECT_EQ( 7u, segments[ 1].size()); // root struct 346 EXPECT_EQ( 2u, segments[ 2].size()); // sub-struct 347 EXPECT_EQ( 3u, segments[ 3].size()); // 3-element int32 list 348 EXPECT_EQ(10u, segments[ 4].size()); // struct list 349 EXPECT_EQ( 2u, segments[ 5].size()); // struct list substruct 1 350 EXPECT_EQ( 2u, segments[ 6].size()); // struct list substruct 2 351 EXPECT_EQ( 2u, segments[ 7].size()); // struct list substruct 3 352 EXPECT_EQ( 2u, segments[ 8].size()); // struct list substruct 4 353 EXPECT_EQ( 6u, segments[ 9].size()); // list list 354 EXPECT_EQ( 2u, segments[10].size()); // list list sublist 1 355 EXPECT_EQ( 2u, segments[11].size()); // list list sublist 2 356 EXPECT_EQ( 2u, segments[12].size()); // list list sublist 3 357 EXPECT_EQ( 2u, segments[13].size()); // list list sublist 4 358 EXPECT_EQ( 3u, segments[14].size()); // list list sublist 5 359 360 checkStruct(builder); 361 checkStruct(builder.asReader()); 362 checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) 363 .getStruct(nullptr)); 364 } 365 366 TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { 367 MallocMessageBuilder message(8, AllocationStrategy::FIXED_SIZE); 368 BuilderArena arena(&message); 369 auto allocation = arena.allocate(1 * WORDS); 370 SegmentBuilder* segment = allocation.segment; 371 word* rootLocation = allocation.words; 372 373 StructBuilder builder = PointerBuilder::getRoot(segment, nullptr, rootLocation) 374 .initStruct(StructSize(2 * WORDS, 4 * POINTERS)); 375 setupStruct(builder); 376 377 // Verify that we made 6 segments. 378 kj::ArrayPtr<const kj::ArrayPtr<const word>> segments = arena.getSegmentsForOutput(); 379 ASSERT_EQ(6u, segments.size()); 380 381 // Check that each segment has the expected size. Recall that each object will be prefixed by an 382 // extra word if its parent is in a different segment. 383 EXPECT_EQ( 8u, segments[0].size()); // root ref + struct + sub 384 EXPECT_EQ( 3u, segments[1].size()); // 3-element int32 list 385 EXPECT_EQ(10u, segments[2].size()); // struct list 386 EXPECT_EQ( 8u, segments[3].size()); // struct list substructs 387 EXPECT_EQ( 8u, segments[4].size()); // list list + sublist 1,2 388 EXPECT_EQ( 7u, segments[5].size()); // list list sublist 3,4,5 389 390 checkStruct(builder); 391 checkStruct(builder.asReader()); 392 checkStruct(PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), 4) 393 .getStruct(nullptr)); 394 } 395 396 inline bool isNan(float f) { return f != f; } 397 inline bool isNan(double f) { return f != f; } 398 399 TEST(WireFormat, NanPatching) { 400 EXPECT_EQ(0x7fc00000u, mask(kj::nan(), 0)); 401 EXPECT_TRUE(isNan(unmask<float>(0x7fc00000u, 0))); 402 EXPECT_TRUE(isNan(unmask<float>(0x7fc00001u, 0))); 403 EXPECT_TRUE(isNan(unmask<float>(0x7fc00005u, 0))); 404 EXPECT_EQ(0x7fc00000u, mask(unmask<float>(0x7fc00000u, 0), 0)); 405 EXPECT_EQ(0x7ff8000000000000ull, mask((double)kj::nan(), 0)); 406 EXPECT_TRUE(isNan(unmask<double>(0x7ff8000000000000ull, 0))); 407 EXPECT_TRUE(isNan(unmask<double>(0x7ff8000000000001ull, 0))); 408 EXPECT_TRUE(isNan(unmask<double>(0x7ff8000000000005ull, 0))); 409 EXPECT_EQ(0x7ff8000000000000ull, mask(unmask<double>(0x7ff8000000000000ull, 0), 0)); 410 } 411 412 } // namespace 413 } // namespace _ (private) 414 } // namespace capnp