SHOW:
|
|
- or go back to the newest paste.
1 | #ifndef COMMON_CONTAINERS_GRID_H | |
2 | #define COMMON_CONTAINERS_GRID_H | |
3 | ||
4 | #include "Common/Basics.h" | |
5 | ||
6 | #include <utility> //For std::move() | |
7 | #include <stdexcept> //For std::out_of_range exception. | |
8 | ||
9 | class cPoint; | |
10 | class cRect; | |
11 | ||
12 | namespace Common { | |
13 | ||
14 | - | template<class Type> class GridIterator; |
14 | + | template<typename Type, typename ContainerType> class GridIterator; |
15 | ||
16 | /* | |
17 | A resizable 2D array container, that resizes without harming the relative location of the elements held | |
18 | by the container, and supports negative indices, like a 2D Cartesian grid. | |
19 | */ | |
20 | template<typename Type> | |
21 | class Grid | |
22 | { | |
23 | public: | |
24 | - | typedef GridIterator<Type> iterator; |
24 | + | typedef GridIterator<Type, Grid> iterator; |
25 | typedef GridIterator<const Type, const Grid<Type> > const_iterator; | |
26 | ||
27 | - | Grid() : memory(nullptr), boundsOffset(0) |
27 | + | |
28 | enum CopyMode {MoveConstructor, CopyConstructor}; | |
29 | ||
30 | public: | |
31 | Grid() : memory(nullptr) | |
32 | { } | |
33 | ||
34 | //Construct and call Resize(). | |
35 | Grid(const cRect &newBounds, const Type &value = Type()) : memory(nullptr) | |
36 | { | |
37 | this->Resize(newBounds, value); | |
38 | } | |
39 | ||
40 | ~Grid() | |
41 | { | |
42 | //Clear the grid, calling the destructors on any constructed elements. | |
43 | this->Clear(); | |
44 | ||
45 | //Deallocate any reserved memory. | |
46 | this->deallocate(this->memory); | |
47 | } | |
48 | ||
49 | //Copy constructor. | |
50 | Grid(const Grid &other) : memory(nullptr) | |
51 | { | |
52 | //Note: Both Reserve() and copyElements() can throw exceptions. If they succeed properly, they will save the new state | |
53 | //to member-variables - but no member-variables should be manually altered within this function before their call. | |
54 | ||
55 | //Reserve enough memory. | |
56 | this->Reserve(other.capacity); | |
57 | ||
58 | //Copy-construct the elements. | |
59 | this->copyElements(other.memory, other.capacity, this->memory, this->capacity, other.bounds, CopyMode::CopyConstructor); | |
60 | ||
61 | //Save the new bounds (once we are sure copyElements() didn't throw). | |
62 | this->bounds = other.bounds; | |
63 | } | |
64 | ||
65 | //Move constructor. | |
66 | Grid(Grid &&other) : memory(nullptr) | |
67 | { | |
68 | this->operator=(std::forward<Grid>(other)); | |
69 | } | |
70 | ||
71 | //Assignment operator | |
72 | Grid &operator=(const Grid &other) | |
73 | { | |
74 | Grid<Type> temp(other); | |
75 | this->Swap(temp); | |
76 | return *this; | |
77 | } | |
78 | ||
79 | //Move-assignment. | |
80 | Grid &operator=(Grid &&other) | |
81 | { | |
82 | this->Swap(other); | |
83 | - | this->ensureCapacity(newBounds, true); |
83 | + | |
84 | - | this->constructAdditions(this->bounds, newBounds, value); |
84 | + | |
85 | ||
86 | //Swaps the contents of this grid with 'other'. | |
87 | - | this->boundsOffset = this->capacity.Index(this->bounds.position); |
87 | + | void Swap(Grid &other) throw() |
88 | { | |
89 | //Swap pointers. | |
90 | std::swap(this->memory, other.memory); | |
91 | ||
92 | //Swap bounds and capacity. | |
93 | std::swap(this->bounds, other.bounds); | |
94 | std::swap(this->capacity, other.capacity); | |
95 | } | |
96 | ||
97 | //================================================================ | |
98 | ||
99 | //Erases the grid, resetting the bounds to (0,0,0,0). | |
100 | //Does not free the reserved capacity. Call Conserve() afterward to do that. | |
101 | void Clear() | |
102 | - | this->ensureCapacity(newCapacity, false); |
102 | + | |
103 | this->Resize(cRect(0,0,0,0)); | |
104 | } | |
105 | ||
106 | //Resets the grid to (0,0,0,0) and releases the reserved memory as well. | |
107 | //This is the same as calling Clear() followed by Conserve(). | |
108 | void Reset() | |
109 | { | |
110 | this->Clear(); | |
111 | this->Conserve(); | |
112 | } | |
113 | ||
114 | //================================================================ | |
115 | ||
116 | //Returns true if the width *or* the height (or both) of the grid is 0, *even* if its position is *not* at (0,0). | |
117 | bool IsEmpty() const | |
118 | { | |
119 | return this->bounds.IsEmpty(); | |
120 | - | void Expand(int amount) |
120 | + | |
121 | ||
122 | - | this->Expand(amount, amount, amount, amount); |
122 | + | |
123 | bool IsNull() const | |
124 | { | |
125 | - | void Expand(int horizontal, int vertical) |
125 | + | |
126 | } | |
127 | - | this->Expand(horizontal, horizontal, vertical, vertical); |
127 | + | |
128 | //================================================================ | |
129 | ||
130 | - | void Expand(int left, int right, int top, int bottom) |
130 | + | |
131 | //If Grid doesn't have enough capacity, it'll reallocate storage and move the elements to new memory addresses. | |
132 | //Throws std::bad_alloc if the allocation failed, and rethrows any exceptions thrown by element constructors or destructors. | |
133 | void Resize(const cRect &newBounds, const Type &value = Type()) | |
134 | { | |
135 | - | this->Resize(newBounds); |
135 | + | try |
136 | { | |
137 | //[CAN THROW - Make sure no member variables are changed before these function calls] | |
138 | cRect newCapacity = this->ensureCapacity(newBounds, true); | |
139 | - | void Shrink(int amount) |
139 | + | |
140 | //[CAN THROW - Make sure no member variables are changed before these function calls] | |
141 | - | this->Shrink(amount, amount, amount, amount); |
141 | + | this->constructAdditions(this->bounds, newBounds, value); |
142 | ||
143 | //Record the new capacity, after we are sure no exceptions were thrown and everything succeeded. | |
144 | - | void Shrink(int horizontal, int vertical) |
144 | + | this->capacity = newCapacity; |
145 | } | |
146 | - | this->Shrink(horizontal, horizontal, vertical, vertical); |
146 | + | catch(std::exception &exception) |
147 | { | |
148 | Log::Message(MSG_SOURCE("Common", Log::Severity::Error)) << "std::exception caught, when resizing to:\n" | |
149 | - | void Shrink(int left, int right, int top, int bottom) |
149 | + | << "newBounds = " << Log_HighlightValue(newBounds.ToString()) << "\n" |
150 | << "exception.what() = " << Log_HighlightBad(exception.what()) << Log::FlushStream; | |
151 | throw; | |
152 | } | |
153 | catch(...) | |
154 | - | this->Resize(newBounds); |
154 | + | |
155 | Log::Message(MSG_SOURCE("Common", Log::Severity::Error)) << "Unknown exception caught, when resizing to:\n" | |
156 | << "newBounds = " << Log_HighlightValue(newBounds.ToString()) << Log::FlushStream; | |
157 | throw; | |
158 | } | |
159 | ||
160 | this->bounds = newBounds; | |
161 | } | |
162 | ||
163 | const cRect &GetBounds() const | |
164 | { | |
165 | return this->bounds; | |
166 | } | |
167 | ||
168 | //================================================================ | |
169 | ||
170 | //Reserves 'newCapacity' amount of memory, without actually resizing the grid. This will reallocate the memory and move the elements to new addresses. | |
171 | //Reserve() will not allow the grid to shrink smaller than the capacity currently is reserved to. | |
172 | //Throws std::bad_alloc if the allocation failed, and rethrows any exceptions thrown by element constructors. | |
173 | void Reserve(const cRect &newCapacity) | |
174 | { | |
175 | //[CAN THROW - Make sure no member variables are changed before this function call] | |
176 | this->capacity = this->ensureCapacity(newCapacity, false); | |
177 | } | |
178 | ||
179 | //Releases all capacity that is no longer needed. This will reallocate the memory and move the elements to new addresses. | |
180 | void Conserve() | |
181 | { | |
182 | //[CAN THROW - Make sure no member variables are changed before this function call] | |
183 | this->reallocateMemory(this->bounds); | |
184 | } | |
185 | ||
186 | //Returns the amount of memory held in reserve for future resizing. | |
187 | const cRect &GetCapacity() const | |
188 | { | |
189 | return this->capacity; | |
190 | } | |
191 | ||
192 | //================================================================ | |
193 | ||
194 | //Resizes the grid. Negative values shrink the grid. | |
195 | void Expand(int amount, const Type &value = Type()) | |
196 | { | |
197 | this->Expand(amount, amount, amount, amount, value); | |
198 | } | |
199 | ||
200 | void Expand(int horizontal, int vertical, const Type &value = Type()) | |
201 | { | |
202 | this->Expand(horizontal, horizontal, vertical, vertical, value); | |
203 | } | |
204 | ||
205 | void Expand(int left, int right, int top, int bottom, const Type &value = Type()) | |
206 | { | |
207 | cRect newBounds = this->bounds; | |
208 | newBounds.Pad(left, right, top, bottom); | |
209 | ||
210 | this->Resize(newBounds, value); | |
211 | } | |
212 | - | size_t constructed = 0, destructed = 0, preserved = 0, ignored = 0; |
212 | + | |
213 | //Resizes the grid. Negative values enlarge the grid. | |
214 | - | for(cPoint point : totalArea) |
214 | + | void Shrink(int amount, const Type &value = Type()) |
215 | { | |
216 | this->Shrink(amount, amount, amount, amount, value); | |
217 | } | |
218 | - | //Do nothing - this area is already constructed. |
218 | + | |
219 | - | preserved++; |
219 | + | void Shrink(int horizontal, int vertical, const Type &value = Type()) |
220 | { | |
221 | - | else if(newBounds.Contains(point)) |
221 | + | this->Shrink(horizontal, horizontal, vertical, vertical, value); |
222 | } | |
223 | - | //Needs to be constructed. |
223 | + | |
224 | - | this->construct((*this)[point], value); |
224 | + | void Shrink(int left, int right, int top, int bottom, const Type &value = Type()) |
225 | { | |
226 | - | constructed++; |
226 | + | |
227 | newBounds.Pad(-left, -right, -top, -bottom); | |
228 | - | else if(oldBounds.Contains(point)) |
228 | + | |
229 | this->Resize(newBounds, value); | |
230 | } | |
231 | ||
232 | //================================================================ | |
233 | - | destructed++; |
233 | + | |
234 | //Throws std::out_of_range if out of range. | |
235 | Type &At(const cPoint &pos) | |
236 | { | |
237 | - | //Do nothing - this area is already destructed. |
237 | + | |
238 | { | |
239 | - | ignored++; |
239 | + | |
240 | + "\t'pos' = " + pos.ToString() | |
241 | + "\n\t'bounds' = " + this->bounds.ToString(); | |
242 | ||
243 | throw std::out_of_range(message); | |
244 | } | |
245 | ||
246 | return (*this)[pos]; | |
247 | } | |
248 | ||
249 | //Doesn't check for range. | |
250 | Type &operator[](const cPoint &pos) | |
251 | { | |
252 | //Convert the point to a index into the memory. | |
253 | size_t index = this->capacity.Index(pos); | |
254 | ||
255 | return this->memory[index]; | |
256 | } | |
257 | ||
258 | //Doesn't check for range. Index-based lookup for iteration (from index '0' to "this->bounds: (width * height)"). | |
259 | Type &AtIndex(unsigned index) | |
260 | { | |
261 | cPoint pos = this->bounds.FromIndex(index); | |
262 | int newIndex = this->capacity.Index(std::move(pos)); | |
263 | ||
264 | return this->memory[newIndex]; | |
265 | } | |
266 | - | //Ensures *at least* enough room for 'bounds'. |
266 | + | |
267 | //Const version, for const_iterator. | |
268 | - | void ensureCapacity(const cRect &bounds, bool addExtra) |
268 | + | const Type &AtIndex(unsigned index) const |
269 | { | |
270 | cPoint pos = this->bounds.FromIndex(index); | |
271 | int newIndex = this->capacity.Index(std::move(pos)); | |
272 | ||
273 | return this->memory[newIndex]; | |
274 | } | |
275 | ||
276 | //================================================================ | |
277 | ||
278 | iterator begin() | |
279 | { return iterator(*this, 0); } | |
280 | iterator end() | |
281 | { return iterator(*this, this->bounds.Area()); } | |
282 | ||
283 | const_iterator begin() const | |
284 | { return const_iterator(*this, 0); } | |
285 | const_iterator end() const | |
286 | { return const_iterator(*this, this->bounds.Area()); } | |
287 | ||
288 | //================================================================ | |
289 | ||
290 | private: | |
291 | //Constructs all the new elements between oldBounds and newBounds setting them to 'value'. | |
292 | //If 'newBounds' is smaller than 'oldBounds', deconstructs the old elements. | |
293 | void constructAdditions(const cRect &oldBounds, const cRect &newBounds, const Type &value = Type()) | |
294 | { | |
295 | //The largest extent of both rects. | |
296 | cRect totalArea = cRect::Encompassing(oldBounds, newBounds); | |
297 | //The overlapping portion of both rects (if any). | |
298 | cRect reducedArea = cRect::Intersection(oldBounds, newBounds); | |
299 | ||
300 | //------------------------------------------- | |
301 | ||
302 | //If a constructor throws an exception, we want to know which element it was, | |
303 | //so we keep track of what the last point was before the exception was thrown. | |
304 | cPoint lastPoint; | |
305 | ||
306 | try | |
307 | { | |
308 | for(cPoint point : newBounds) | |
309 | { | |
310 | if(reducedArea.Contains(point)) | |
311 | { | |
312 | //Do nothing - this area is already constructed. | |
313 | } | |
314 | else | |
315 | { | |
316 | lastPoint = point; | |
317 | - | this->memory = this->allocate(newCapacity); |
317 | + | |
318 | //Needs to be constructed. | |
319 | this->construct((*this)[point], value); | |
320 | } | |
321 | } | |
322 | } | |
323 | catch(...) | |
324 | { | |
325 | //Since we caught an exception, destruct every element we had previously constructed. | |
326 | for(cPoint point : newBounds) | |
327 | { | |
328 | if(reducedArea.Contains(point)) | |
329 | - | Type *newMemory = this->allocate(newCapacity); |
329 | + | { |
330 | //Do nothing - this area is already constructed. | |
331 | } | |
332 | else if(point == lastPoint) | |
333 | { | |
334 | //Stop here - we didn't construct anything beyond this element. | |
335 | break; | |
336 | - | this->moveElements(oldMemory, oldCapacity, newMemory, newCapacity, this->bounds); |
336 | + | } |
337 | else | |
338 | { | |
339 | //Destruct the element we previously constructed. | |
340 | - | oldMemory = nullptr; |
340 | + | this->destruct((*this)[point]); |
341 | } | |
342 | - | //And store the new pointer. |
342 | + | |
343 | - | this->memory = newMemory; |
343 | + | |
344 | throw; | |
345 | } | |
346 | ||
347 | //------------------------------------------- | |
348 | ||
349 | //Destruct any elements that we no longer want (if we're resizing smaller than our previous size). | |
350 | - | //Called by 'reallocateMemory' only. |
350 | + | for(cPoint point : oldBounds) |
351 | - | void moveElements(Type *oldMemory, const cRect &oldCapacity, Type *newMemory, |
351 | + | |
352 | - | const cRect &newCapacity, const cRect &bounds) |
352 | + | |
353 | { | |
354 | //Do nothing - we're preserving these elements. | |
355 | } | |
356 | else | |
357 | { | |
358 | //Needs to be destructed. | |
359 | this->destruct((*this)[point]); | |
360 | } | |
361 | } | |
362 | } | |
363 | ||
364 | //================================================================ | |
365 | ||
366 | //Construct a single element. | |
367 | - | //The length of each 'row' of the grid's capacity in memory. |
367 | + | |
368 | - | size_t oldStride = oldCapacity.size.width; |
368 | + | |
369 | - | size_t newStride = newCapacity.size.width; |
369 | + | |
370 | } | |
371 | ||
372 | //Constructs an element with move semantics. | |
373 | void moveConstruct(Type &element, Type &&value) | |
374 | { | |
375 | - | //The number of rows and columns of actual elements we need to move. |
375 | + | |
376 | - | size_t rows = bounds.size.height; |
376 | + | |
377 | - | size_t columns = bounds.size.width; |
377 | + | |
378 | //Destruct a single element. | |
379 | - | for(size_t row = 0; row < rows; row++) |
379 | + | |
380 | { | |
381 | - | for(size_t column = 0; column < columns; column++) |
381 | + | |
382 | } | |
383 | - | size_t oldIndex = (row * oldStride) + column; |
383 | + | |
384 | //Destructs multiple elements in a block of memory. | |
385 | void destructBounds(Type *memory, const cRect &capacity, const cRect &bounds) | |
386 | - | size_t newIndex = (row * newStride) + column; |
386 | + | |
387 | //The initial offset of the actual bounds from the memory capacity. | |
388 | size_t offset = capacity.Index(bounds.position); | |
389 | - | //Construct the new location, and move the element. |
389 | + | |
390 | - | this->moveConstruct(newMemory[newIndex], std::move(oldMemory[oldIndex])); |
390 | + | //Destruct all the old elements. |
391 | for(cPoint pos : bounds.size) | |
392 | - | //Destruct old location. |
392 | + | |
393 | - | this->destruct(oldMemory[oldIndex]); |
393 | + | //Convert to position in the bound's area (from {0,0} to {width, height}) |
394 | //to the actual location in the memory capacity. | |
395 | size_t index = (pos.y * capacity.size.width) + pos.x; | |
396 | index += offset; | |
397 | ||
398 | //Destruct the element we constructed in the previous for() loops. | |
399 | this->destruct(memory[index]); | |
400 | } | |
401 | } | |
402 | - | unsigned int boundsOffset; //The offset of 'bounds' within 'capacity'. Only used for AtIndex, for faster iteration. |
402 | + | |
403 | //================================================================ | |
404 | - | cRect bounds; //Current grid boundries. |
404 | + | |
405 | - | cRect capacity; //Currently allocated memory capacity, garunteed to be at least 'bounds' and maybe larger. |
405 | + | //Ensures *at least* enough room for 'bounds'. Returns the resulting capacity. |
406 | //If 'addExtra' is true, includes even more capacity for future growth. | |
407 | cRect ensureCapacity(const cRect &bounds, bool addExtra) | |
408 | { | |
409 | //Check whether we have enough capacity to resize. | |
410 | if(!this->capacity.Contains(bounds)) | |
411 | { | |
412 | - | //A random-access iterator for iterating over each element of a Common::Grid. |
412 | + | |
413 | - | template <typename Type> |
413 | + | |
414 | if(addExtra) | |
415 | { | |
416 | //If we're bothering to grow in size, we might as well reserve a little extra for future growth. | |
417 | - | GridIterator(Common::Grid<Type> &grid, unsigned index) : grid(grid), index(index) |
417 | + | |
418 | int quarterHeight = (bounds.size.height / 4) + 1; | |
419 | ||
420 | desiredCapacity.Pad(quarterWidth, quarterWidth, quarterHeight, quarterHeight); | |
421 | } | |
422 | ||
423 | //Allocate and move the elements. | |
424 | //[CAN THROW - Make sure no member variables are changed before this function call] | |
425 | this->reallocateMemory(desiredCapacity); | |
426 | ||
427 | //Return the new capacity. | |
428 | return desiredCapacity; | |
429 | } | |
430 | ||
431 | //Return the current capacity. | |
432 | return this->capacity; | |
433 | } | |
434 | ||
435 | //================================================================ | |
436 | ||
437 | //This allocates enough memory for 'capacity', without constructing any elements. | |
438 | Type *allocate(const cRect &capacity) | |
439 | { | |
440 | //Allocate the new memory. | |
441 | size_t numElements = capacity.size.Area(); | |
442 | size_t numBytes = (sizeof(Type) * numElements); | |
443 | void *data = ::operator new(numBytes); | |
444 | ||
445 | return static_cast<Type*>(data); | |
446 | } | |
447 | ||
448 | //This deallocates 'memory', without calling any destructors. | |
449 | void deallocate(Type *data) | |
450 | { | |
451 | - | GridIterator &operator++() |
451 | + | |
452 | } | |
453 | ||
454 | //================================================================ | |
455 | ||
456 | //Reallocates the memory and migrates the elements over using moveElements(). | |
457 | //Throws std::bad_alloc if the allocation failed, and throws any exceptions thrown by element constructors. | |
458 | - | GridIterator operator++(int) |
458 | + | |
459 | { | |
460 | if(!this->memory) | |
461 | { | |
462 | //If we don't have any memory, just allocate some and don't worry about moving any elements. | |
463 | //[CAN THROW - Make sure no member variables are changed before this function call] | |
464 | this->memory = this->allocate(newCapacity); | |
465 | - | GridIterator &operator--() |
465 | + | |
466 | else if(newCapacity.IsEmpty()) | |
467 | { | |
468 | //Destruct all the old elements. | |
469 | this->destructBounds(this->memory, this->capacity, this->bounds); | |
470 | ||
471 | - | GridIterator operator--(int) |
471 | + | |
472 | this->deallocate(this->memory); | |
473 | this->memory = nullptr; | |
474 | } | |
475 | else | |
476 | { | |
477 | //Allocate the new memory. | |
478 | //Note: I put the allocated memory into a unique_ptr here, incase moveElements() throws. | |
479 | //This way, the new memory is properly released. | |
480 | //[CAN THROW - Make sure no member variables are changed before this function call] | |
481 | - | GridIterator operator+(int n) |
481 | + | std::unique_ptr<Type, use_operator_delete> newMemory(this->allocate(newCapacity)); |
482 | ||
483 | //A few extra variables for readability. | |
484 | Type *oldMemory = this->memory; | |
485 | const cRect &oldCapacity = this->capacity; | |
486 | ||
487 | //Move the elements. | |
488 | - | GridIterator &operator+=(int n) |
488 | + | //[CAN THROW - Make sure no member variables are changed before this function call] |
489 | this->copyElements(oldMemory, oldCapacity, newMemory.get(), newCapacity, this->bounds, CopyMode::MoveConstructor); | |
490 | ||
491 | //Delete the old memory. | |
492 | this->deallocate(oldMemory); | |
493 | ||
494 | //And store the new pointer. Have the unique_ptr release ownership of the memory as well. | |
495 | - | GridIterator operator-(int n) |
495 | + | this->memory = newMemory.release(); |
496 | } | |
497 | ||
498 | //Record the new capacity. | |
499 | this->capacity = newCapacity; | |
500 | } | |
501 | ||
502 | - | GridIterator &operator-=(int n) |
502 | + | //Called by 'reallocateMemory' and the copy-constructor. |
503 | void copyElements(Type *oldMemory, const cRect &oldCapacity, Type *newMemory, | |
504 | const cRect &newCapacity, const cRect &bounds, CopyMode copyMode = CopyMode::CopyConstructor) | |
505 | { | |
506 | //Insanity preservation. | |
507 | //Assert that our elements are actually within the capacity of both the new and old blocks of memory. | |
508 | BOOST_ASSERT(oldCapacity.Contains(bounds)); | |
509 | BOOST_ASSERT(newCapacity.Contains(bounds)); | |
510 | ||
511 | - | Common::Grid<Type> &grid; |
511 | + | |
512 | BOOST_ASSERT(!oldCapacity.IsEmpty()); | |
513 | BOOST_ASSERT(!newCapacity.IsEmpty()); | |
514 | ||
515 | //Assert that neither pointer to the allocated memory is empty. | |
516 | BOOST_ASSERT(oldMemory != nullptr); | |
517 | BOOST_ASSERT(newMemory != nullptr); | |
518 | ||
519 | //================================================================= | |
520 | ||
521 | //The initial offset of the actual bounds from the memory capacity. | |
522 | size_t oldOffset = oldCapacity.Index(bounds.position); | |
523 | size_t newOffset = newCapacity.Index(bounds.position); | |
524 | ||
525 | //Incase a constructor throws an exception, keep track of the last position we successfully constructed. | |
526 | cPoint lastPos; | |
527 | ||
528 | try | |
529 | { | |
530 | //Move-construct all the new elements. | |
531 | for(cPoint pos : bounds.size) | |
532 | { | |
533 | lastPos = pos; | |
534 | ||
535 | //Convert to position in the bound's area (from {0,0} to {width, height}) | |
536 | //to the actual location in the memory capacity. | |
537 | size_t oldIndex = (pos.y * oldCapacity.size.width) + pos.x; | |
538 | oldIndex += oldOffset; | |
539 | ||
540 | size_t newIndex = (pos.y * newCapacity.size.width) + pos.x; | |
541 | newIndex += newOffset; | |
542 | ||
543 | //Construct the new location. | |
544 | if(copyMode == CopyMode::MoveConstructor) | |
545 | { | |
546 | //Move-constructor. | |
547 | this->moveConstruct(newMemory[newIndex], std::move(oldMemory[oldIndex])); | |
548 | } | |
549 | else | |
550 | { | |
551 | //Copy-constructor. | |
552 | this->construct(newMemory[newIndex], oldMemory[oldIndex]); | |
553 | } | |
554 | } | |
555 | } | |
556 | catch(...) | |
557 | { | |
558 | //Since we just caught an exception thrown from one of the element move-constructors, | |
559 | //destruct all the new elements we just constructed, up until the failed constructor. | |
560 | for(cPoint pos : bounds.size) | |
561 | { | |
562 | if(pos == lastPos) | |
563 | break; | |
564 | ||
565 | //Convert to position in the bound's area (from {0,0} to {width, height}) | |
566 | //to the actual location in the memory capacity. | |
567 | size_t newIndex = (pos.y * newCapacity.size.width) + pos.x; | |
568 | newIndex += newOffset; | |
569 | ||
570 | //Destruct the element we constructed in the previous for() loops. | |
571 | this->destruct(newMemory[newIndex]); | |
572 | } | |
573 | ||
574 | throw; | |
575 | } | |
576 | ||
577 | //Destruct all the old elements, unless we are copying and not moving. | |
578 | if(copyMode == CopyMode::MoveConstructor) | |
579 | { | |
580 | this->destructBounds(oldMemory, oldCapacity, bounds); | |
581 | } | |
582 | } | |
583 | ||
584 | //================================================================ | |
585 | ||
586 | private: | |
587 | Type *memory; | |
588 | ||
589 | cRect bounds; //Current grid boundaries. | |
590 | cRect capacity; //Currently allocated memory capacity, guaranteed to be at least 'bounds' and maybe larger. | |
591 | }; | |
592 | ||
593 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
594 | //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX// | |
595 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
596 | ||
597 | /* | |
598 | A random-access iterator for iterating over each element of a Common::Grid. | |
599 | ||
600 | I'm doing a trick here, by taking the type of the container as a second template parameter. | |
601 | This allows me to do this: | |
602 | typedef GridIterator<const Type, const Grid<Type> > const_iterator; | |
603 | ||
604 | ...instead of having to create two seperate iterator classes (one for regular iterator and one for const). | |
605 | */ | |
606 | template <typename Type, typename ContainerType = typename Common::Grid<Type> > | |
607 | class GridIterator | |
608 | { | |
609 | public: | |
610 | GridIterator(ContainerType &grid, unsigned index) : grid(grid), index(index) | |
611 | { | |
612 | this->maxIndex = this->grid.GetBounds().Area(); | |
613 | } | |
614 | ||
615 | //================================================================ | |
616 | ||
617 | //De-reference. | |
618 | Type &operator*() | |
619 | { | |
620 | return this->grid.AtIndex(this->index); | |
621 | } | |
622 | Type &operator->() | |
623 | { | |
624 | return (operator*()); | |
625 | } | |
626 | ||
627 | //================================================================ | |
628 | ||
629 | //Comparison. | |
630 | bool operator==(const GridIterator &other) const | |
631 | { | |
632 | return (&this->grid == &other.grid) && (this->index == other.index); | |
633 | } | |
634 | ||
635 | bool operator!=(const GridIterator &other) const | |
636 | { | |
637 | return !operator==(other); | |
638 | } | |
639 | ||
640 | //================================================================ | |
641 | ||
642 | //Increment/decrement. | |
643 | GridIterator &operator++() | |
644 | { | |
645 | this->index++; | |
646 | Limit(this->index, this->maxIndex); | |
647 | return *this; | |
648 | } | |
649 | ||
650 | GridIterator operator++(int) | |
651 | { | |
652 | GridIterator temp(*this); | |
653 | ++(*this); | |
654 | return temp; | |
655 | } | |
656 | ||
657 | GridIterator &operator--() | |
658 | { | |
659 | this->index--; | |
660 | return *this; | |
661 | } | |
662 | ||
663 | GridIterator operator--(int) | |
664 | { | |
665 | GridIterator temp(*this); | |
666 | --(*this); | |
667 | return temp; | |
668 | } | |
669 | ||
670 | //================================================================ | |
671 | ||
672 | //Random access. | |
673 | GridIterator operator+(int n) const | |
674 | { | |
675 | GridIterator temp(*this); | |
676 | temp.index += n; | |
677 | return temp; | |
678 | } | |
679 | ||
680 | GridIterator &operator+=(int n) | |
681 | { | |
682 | this->index += n; | |
683 | Limit(this->index, this->maxIndex); | |
684 | return *this; | |
685 | } | |
686 | ||
687 | GridIterator operator-(int n) const | |
688 | { | |
689 | GridIterator temp(*this); | |
690 | temp.index -= n; | |
691 | return temp; | |
692 | } | |
693 | ||
694 | GridIterator &operator-=(int n) | |
695 | { | |
696 | this->index -= n; | |
697 | return *this; | |
698 | } | |
699 | ||
700 | //================================================================ | |
701 | ||
702 | private: | |
703 | ContainerType &grid; | |
704 | ||
705 | unsigned index; //The current index. | |
706 | unsigned maxIndex; //The maximum value (and the result returned by 'std::end()'. | |
707 | }; | |
708 | ||
709 | //================================================================ | |
710 | ||
711 | } //End of namespace. | |
712 | ||
713 | #endif // COMMON_CONTAINERS_GRID_H |