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