capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

arena-test.c++ (8156B)


      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 #include "arena.h"
     23 #include "debug.h"
     24 #include <kj/compat/gtest.h>
     25 #include <stdint.h>
     26 
     27 namespace kj {
     28 namespace {
     29 
     30 struct TestObject {
     31   TestObject() {
     32     index = count;
     33     KJ_ASSERT(index != throwAt);
     34     ++count;
     35   }
     36   TestObject(const TestObject& other) {
     37     KJ_ASSERT(other.index != throwAt);
     38     index = -1;
     39     copiedCount++;
     40   }
     41   ~TestObject() noexcept(false) {
     42     if (index == -1) {
     43       --copiedCount;
     44     } else {
     45       --count;
     46       EXPECT_EQ(index, count);
     47       KJ_ASSERT(count != throwAt);
     48     }
     49   }
     50 
     51   int index;
     52 
     53   static int count;
     54   static int copiedCount;
     55   static int throwAt;
     56 };
     57 
     58 int TestObject::count = 0;
     59 int TestObject::copiedCount = 0;
     60 int TestObject::throwAt = -1;
     61 
     62 TEST(Arena, Object) {
     63   TestObject::count = 0;
     64   TestObject::throwAt = -1;
     65 
     66   {
     67     Arena arena;
     68 
     69     TestObject& obj1 = arena.allocate<TestObject>();
     70     TestObject& obj2 = arena.allocate<TestObject>();
     71 
     72     EXPECT_LT(&obj1, &obj2);
     73 
     74     EXPECT_EQ(2, TestObject::count);
     75   }
     76 
     77   EXPECT_EQ(0, TestObject::count);
     78 }
     79 
     80 TEST(Arena, TrivialObject) {
     81   Arena arena;
     82 
     83   int& i1 = arena.allocate<int>();
     84   int& i2 = arena.allocate<int>();
     85 
     86   // Trivial objects should be tightly-packed.
     87   EXPECT_EQ(&i1 + 1, &i2);
     88 }
     89 
     90 TEST(Arena, OwnObject) {
     91   TestObject::count = 0;
     92   TestObject::throwAt = -1;
     93 
     94   Arena arena;
     95 
     96   {
     97     Own<TestObject> obj1 = arena.allocateOwn<TestObject>();
     98     Own<TestObject> obj2 = arena.allocateOwn<TestObject>();
     99     EXPECT_LT(obj1.get(), obj2.get());
    100 
    101     EXPECT_EQ(2, TestObject::count);
    102   }
    103 
    104   EXPECT_EQ(0, TestObject::count);
    105 }
    106 
    107 TEST(Arena, Array) {
    108   TestObject::count = 0;
    109   TestObject::throwAt = -1;
    110 
    111   {
    112     Arena arena;
    113     ArrayPtr<TestObject> arr1 = arena.allocateArray<TestObject>(4);
    114     ArrayPtr<TestObject> arr2 = arena.allocateArray<TestObject>(2);
    115     EXPECT_EQ(4u, arr1.size());
    116     EXPECT_EQ(2u, arr2.size());
    117     EXPECT_LE(arr1.end(), arr2.begin());
    118     EXPECT_EQ(6, TestObject::count);
    119   }
    120 
    121   EXPECT_EQ(0, TestObject::count);
    122 }
    123 
    124 TEST(Arena, TrivialArray) {
    125   Arena arena;
    126   ArrayPtr<int> arr1 = arena.allocateArray<int>(16);
    127   ArrayPtr<int> arr2 = arena.allocateArray<int>(8);
    128 
    129   // Trivial arrays should be tightly-packed.
    130   EXPECT_EQ(arr1.end(), arr2.begin());
    131 }
    132 
    133 TEST(Arena, OwnArray) {
    134   TestObject::count = 0;
    135   TestObject::throwAt = -1;
    136 
    137   Arena arena;
    138 
    139   {
    140     Array<TestObject> arr1 = arena.allocateOwnArray<TestObject>(4);
    141     Array<TestObject> arr2 = arena.allocateOwnArray<TestObject>(2);
    142     EXPECT_EQ(4u, arr1.size());
    143     EXPECT_EQ(2u, arr2.size());
    144     EXPECT_LE(arr1.end(), arr2.begin());
    145     EXPECT_EQ(6, TestObject::count);
    146   }
    147 
    148   EXPECT_EQ(0, TestObject::count);
    149 }
    150 
    151 #ifndef KJ_NO_EXCEPTIONS
    152 
    153 TEST(Arena, ObjectThrow) {
    154   TestObject::count = 0;
    155   TestObject::throwAt = 1;
    156 
    157   {
    158     Arena arena;
    159 
    160     arena.allocate<TestObject>();
    161     EXPECT_ANY_THROW(arena.allocate<TestObject>());
    162     EXPECT_EQ(1, TestObject::count);
    163   }
    164 
    165   EXPECT_EQ(0, TestObject::count);
    166 }
    167 
    168 TEST(Arena, ArrayThrow) {
    169   TestObject::count = 0;
    170   TestObject::throwAt = 2;
    171 
    172   {
    173     Arena arena;
    174     EXPECT_ANY_THROW(arena.allocateArray<TestObject>(4));
    175     EXPECT_EQ(2, TestObject::count);
    176   }
    177 
    178   EXPECT_EQ(0, TestObject::count);
    179 }
    180 
    181 #endif
    182 
    183 TEST(Arena, Alignment) {
    184   Arena arena;
    185 
    186   char& c = arena.allocate<char>();
    187   long& l = arena.allocate<long>();
    188   char& c2 = arena.allocate<char>();
    189   ArrayPtr<char> arr = arena.allocateArray<char>(8);
    190 
    191   EXPECT_EQ(alignof(long) + sizeof(long), implicitCast<size_t>(&c2 - &c));
    192   EXPECT_EQ(alignof(long), implicitCast<size_t>(reinterpret_cast<char*>(&l) - &c));
    193   EXPECT_EQ(sizeof(char), implicitCast<size_t>(arr.begin() - &c2));
    194 }
    195 
    196 TEST(Arena, EndOfChunk) {
    197   union {
    198     byte scratch[64];
    199     uint64_t align;
    200   };
    201   Arena arena(arrayPtr(scratch, sizeof(scratch)));
    202 
    203   // First allocation will come from somewhere in the scratch space (after the chunk header).
    204   uint64_t& i = arena.allocate<uint64_t>();
    205   EXPECT_GE(reinterpret_cast<byte*>(&i), scratch);
    206   EXPECT_LT(reinterpret_cast<byte*>(&i), scratch + sizeof(scratch));
    207 
    208   // Next allocation will come at the next position.
    209   uint64_t& i2 = arena.allocate<uint64_t>();
    210   EXPECT_EQ(&i + 1, &i2);
    211 
    212   // Allocate the rest of the scratch space.
    213   size_t spaceLeft = scratch + sizeof(scratch) - reinterpret_cast<byte*>(&i2 + 1);
    214   ArrayPtr<byte> remaining = arena.allocateArray<byte>(spaceLeft);
    215   EXPECT_EQ(reinterpret_cast<byte*>(&i2 + 1), remaining.begin());
    216 
    217   // Next allocation comes from somewhere new.
    218   uint64_t& i3 = arena.allocate<uint64_t>();
    219   EXPECT_NE(remaining.end(), reinterpret_cast<byte*>(&i3));
    220 }
    221 
    222 TEST(Arena, EndOfChunkAlignment) {
    223   union {
    224     byte scratch[34];
    225     uint64_t align;
    226   };
    227   Arena arena(arrayPtr(scratch, sizeof(scratch)));
    228 
    229   // Figure out where we are...
    230   byte* start = arena.allocateArray<byte>(0).begin();
    231 
    232   // Allocate enough space so that we're 24 bytes into the scratch space.  (On 64-bit systems, this
    233   // should be zero.)
    234   arena.allocateArray<byte>(24 - (start - scratch));
    235 
    236   // Allocating a 16-bit integer works.  Now we're at 26 bytes; 8 bytes are left.
    237   uint16_t& i = arena.allocate<uint16_t>();
    238   EXPECT_EQ(scratch + 24, reinterpret_cast<byte*>(&i));
    239 
    240   // Although there is technically enough space to allocate a uint64, it is not aligned correctly,
    241   // so it will be allocated elsewhere instead.
    242   uint64_t& i2 = arena.allocate<uint64_t>();
    243   EXPECT_TRUE(reinterpret_cast<byte*>(&i2) < scratch ||
    244               reinterpret_cast<byte*>(&i2) > scratch + sizeof(scratch));
    245 }
    246 
    247 TEST(Arena, TooBig) {
    248   Arena arena(1024);
    249 
    250   byte& b1 = arena.allocate<byte>();
    251 
    252   ArrayPtr<byte> arr = arena.allocateArray<byte>(1024);
    253 
    254   byte& b2 = arena.allocate<byte>();
    255 
    256   // The array should not have been allocated anywhere near that first byte.
    257   EXPECT_TRUE(arr.begin() < &b1 || arr.begin() > &b1 + 512);
    258 
    259   // The next byte should have been allocated after the array.
    260   EXPECT_EQ(arr.end(), &b2);
    261 
    262   // Write to the array to make sure it's valid.
    263   memset(arr.begin(), 0xbe, arr.size());
    264 }
    265 
    266 TEST(Arena, MultiSegment) {
    267   // Sorry, this test makes assumptions about the size of ChunkHeader.
    268   Arena arena(sizeof(void*) == 4 ? 32 : 40);
    269 
    270   uint64_t& i1 = arena.allocate<uint64_t>();
    271   uint64_t& i2 = arena.allocate<uint64_t>();
    272   uint64_t& i3 = arena.allocate<uint64_t>();
    273 
    274   EXPECT_EQ(&i1 + 1, &i2);
    275   EXPECT_NE(&i2 + 1, &i3);
    276 
    277   i1 = 1234;
    278   i2 = 5678;
    279   i3 = 9012;
    280 }
    281 
    282 TEST(Arena, Constructor) {
    283   Arena arena;
    284 
    285   EXPECT_EQ(123u, arena.allocate<uint64_t>(123));
    286   EXPECT_EQ("foo", arena.allocate<StringPtr>("foo", 3));
    287 }
    288 
    289 TEST(Arena, Strings) {
    290   Arena arena;
    291 
    292   StringPtr foo = arena.copyString("foo");
    293   StringPtr bar = arena.copyString("bar");
    294   StringPtr quux = arena.copyString("quux");
    295   StringPtr corge = arena.copyString("corge");
    296 
    297   EXPECT_EQ("foo", foo);
    298   EXPECT_EQ("bar", bar);
    299   EXPECT_EQ("quux", quux);
    300   EXPECT_EQ("corge", corge);
    301 
    302   EXPECT_EQ(foo.end() + 1, bar.begin());
    303   EXPECT_EQ(bar.end() + 1, quux.begin());
    304   EXPECT_EQ(quux.end() + 1, corge.begin());
    305 }
    306 
    307 }  // namespace
    308 }  // namespace kj