ezEngine  Milestone 7
Map_inl.h
1 #pragma once
2 
3 #include <Foundation/Math/Math.h>
4 
5 // ***** Const Iterator *****
6 
7 #define STACK_SIZE 48
8 
9 template <typename KeyType, typename ValueType, typename Comparer>
11 {
12  const ezInt32 dir0 = 0;
13  const ezInt32 dir1 = 1;
14 
15  if (m_pElement == nullptr)
16  {
17  EZ_ASSERT_DEV(m_pElement != nullptr, "The Iterator is invalid (end).");
18  return;
19  }
20 
21  // if this element has a right child, go there and then search for the left most child of that
22  if (m_pElement->m_pLink[dir1] != m_pElement->m_pLink[dir1]->m_pLink[dir1])
23  {
24  m_pElement = m_pElement->m_pLink[dir1];
25 
26  while (m_pElement->m_pLink[dir0] != m_pElement->m_pLink[dir0]->m_pLink[dir0])
27  m_pElement = m_pElement->m_pLink[dir0];
28 
29  return;
30  }
31 
32  // if this element has a parent and this element is that parents left child, go directly to the parent
33  if ((m_pElement->m_pParent != m_pElement->m_pParent->m_pParent) &&
34  (m_pElement->m_pParent->m_pLink[dir0] == m_pElement))
35  {
36  m_pElement = m_pElement->m_pParent;
37  return;
38  }
39 
40  // if this element has a parent and this element is that parents right child, search for the next parent, whose left child this is
41  if ((m_pElement->m_pParent != m_pElement->m_pParent->m_pParent) &&
42  (m_pElement->m_pParent->m_pLink[dir1] == m_pElement))
43  {
44  while (m_pElement->m_pParent->m_pLink[dir1] == m_pElement)
45  m_pElement = m_pElement->m_pParent;
46 
47  // if we are at the root node..
48  if ((m_pElement->m_pParent == m_pElement->m_pParent->m_pParent) ||
49  (m_pElement->m_pParent == nullptr))
50  {
51  m_pElement = nullptr;
52  return;
53  }
54 
55  m_pElement = m_pElement->m_pParent;
56  return;
57  }
58 
59  m_pElement = nullptr;
60  return;
61 }
62 
63 template <typename KeyType, typename ValueType, typename Comparer>
65 {
66  const ezInt32 dir0 = 1;
67  const ezInt32 dir1 = 0;
68 
69  if (m_pElement == nullptr)
70  {
71  EZ_ASSERT_DEV(m_pElement != nullptr, "The Iterator is invalid (end).");
72  return;
73  }
74 
75  // if this element has a right child, go there and then search for the left most child of that
76  if (m_pElement->m_pLink[dir1] != m_pElement->m_pLink[dir1]->m_pLink[dir1])
77  {
78  m_pElement = m_pElement->m_pLink[dir1];
79 
80  while (m_pElement->m_pLink[dir0] != m_pElement->m_pLink[dir0]->m_pLink[dir0])
81  m_pElement = m_pElement->m_pLink[dir0];
82 
83  return;
84  }
85 
86  // if this element has a parent and this element is that parents left child, go directly to the parent
87  if ((m_pElement->m_pParent != m_pElement->m_pParent->m_pParent) &&
88  (m_pElement->m_pParent->m_pLink[dir0] == m_pElement))
89  {
90  m_pElement = m_pElement->m_pParent;
91  return;
92  }
93 
94  // if this element has a parent and this element is that parents right child, search for the next parent, whose left child this is
95  if ((m_pElement->m_pParent != m_pElement->m_pParent->m_pParent) &&
96  (m_pElement->m_pParent->m_pLink[dir1] == m_pElement))
97  {
98  while (m_pElement->m_pParent->m_pLink[dir1] == m_pElement)
99  m_pElement = m_pElement->m_pParent;
100 
101  // if we are at the root node..
102  if ((m_pElement->m_pParent == m_pElement->m_pParent->m_pParent) ||
103  (m_pElement->m_pParent == nullptr))
104  {
105  m_pElement = nullptr;
106  return;
107  }
108 
109  m_pElement = m_pElement->m_pParent;
110  return;
111  }
112 
113  m_pElement = nullptr;
114  return;
115 }
116 
117 // ***** ezMapBase *****
118 
119 template <typename KeyType, typename ValueType, typename Comparer>
120 EZ_FORCE_INLINE ezMapBase<KeyType, ValueType, Comparer>::NilNode::NilNode() : m_pParent(nullptr), m_uiLevel(0)
121 {
122 }
123 
124 template <typename KeyType, typename ValueType, typename Comparer>
126 {
127  m_uiCount = 0;
128 
129  m_NilNode.m_uiLevel = 0;
130  m_NilNode.m_pLink[0] = reinterpret_cast<Node*>(&m_NilNode);
131  m_NilNode.m_pLink[1] = reinterpret_cast<Node*>(&m_NilNode);
132  m_NilNode.m_pParent = reinterpret_cast<Node*>(&m_NilNode);
133 
134  m_pFreeElementStack = nullptr;
135  m_pRoot = reinterpret_cast<Node*>(&m_NilNode);
136 }
137 
138 template <typename KeyType, typename ValueType, typename Comparer>
139 ezMapBase<KeyType, ValueType, Comparer>::ezMapBase(const Comparer& comparer, ezAllocatorBase* pAllocator) : m_Elements(pAllocator), m_Comparer(comparer)
140 {
141  Constructor();
142 }
143 
144 template <typename KeyType, typename ValueType, typename Comparer>
146 {
147  Constructor();
148 
149  operator=(cc);
150 }
151 
152 template <typename KeyType, typename ValueType, typename Comparer>
154 {
155  Clear();
156 }
157 
158 template <typename KeyType, typename ValueType, typename Comparer>
160 {
161  Clear();
162 
163  for (ConstIterator it = rhs.GetIterator(); it.IsValid(); ++it)
164  Insert(it.Key(), it.Value());
165 }
166 
167 template <typename KeyType, typename ValueType, typename Comparer>
169 {
170  for (Iterator it = GetIterator(); it.IsValid(); ++it)
171  ezMemoryUtils::Destruct<Node>(it.m_pElement, 1);
172 
173  m_pFreeElementStack = nullptr;
174  m_Elements.Clear();
175 
176  m_uiCount = 0;
177 
178  m_NilNode.m_uiLevel = 0;
179  m_NilNode.m_pLink[0] = reinterpret_cast<Node*>(&m_NilNode);
180  m_NilNode.m_pLink[1] = reinterpret_cast<Node*>(&m_NilNode);
181  m_NilNode.m_pParent = reinterpret_cast<Node*>(&m_NilNode);
182 
183  m_pRoot = reinterpret_cast<Node*>(&m_NilNode);
184 }
185 
186 template <typename KeyType, typename ValueType, typename Comparer>
188 {
189  return (m_uiCount == 0);
190 }
191 
192 template <typename KeyType, typename ValueType, typename Comparer>
194 {
195  return m_uiCount;
196 }
197 
198 
199 template <typename KeyType, typename ValueType, typename Comparer>
201 {
202  return Iterator(GetLeftMost());
203 }
204 
205 template <typename KeyType, typename ValueType, typename Comparer>
207 {
208  return ConstIterator(GetLeftMost());
209 }
210 
211 template <typename KeyType, typename ValueType, typename Comparer>
213 {
214  return Iterator(GetRightMost());
215 }
216 
217 template <typename KeyType, typename ValueType, typename Comparer>
219 {
220  return ConstIterator(GetRightMost());
221 }
222 
223 template <typename KeyType, typename ValueType, typename Comparer>
225 {
226  if (IsEmpty())
227  return nullptr;
228 
229  Node* pNode = m_pRoot;
230 
231  while (pNode->m_pLink[0] != &m_NilNode)
232  pNode = pNode->m_pLink[0];
233 
234  return pNode;
235 }
236 
237 template <typename KeyType, typename ValueType, typename Comparer>
239 {
240  if (IsEmpty())
241  return nullptr;
242 
243  Node* pNode = m_pRoot;
244 
245  while (pNode->m_pLink[1] != &m_NilNode)
246  pNode = pNode->m_pLink[1];
247 
248  return pNode;
249 }
250 
251 template <typename KeyType, typename ValueType, typename Comparer>
253 {
254  Node* pNode = m_pRoot;
255 
256  while (pNode != &m_NilNode)
257  {
258  const ezInt32 dir = (ezInt32) m_Comparer.Less(pNode->m_Key, key);
259  const ezInt32 dir2= (ezInt32) m_Comparer.Less(key, pNode->m_Key);
260 
261  if (dir == dir2)
262  break;
263 
264  pNode = pNode->m_pLink[dir];
265  }
266 
267  if (pNode == &m_NilNode)
268  return nullptr;
269 
270  return pNode;
271 }
272 
273 template <typename KeyType, typename ValueType, typename Comparer>
275 {
276  return Iterator(Internal_Find(key));
277 }
278 
279 template <typename KeyType, typename ValueType, typename Comparer>
281 {
282  return ConstIterator(Internal_Find(key));
283 }
284 
285 template <typename KeyType, typename ValueType, typename Comparer>
286 EZ_FORCE_INLINE bool ezMapBase<KeyType, ValueType, Comparer>::Contains(const KeyType& key) const
287 {
288  return Internal_Find(key) != nullptr;
289 }
290 
291 template <typename KeyType, typename ValueType, typename Comparer>
293 {
294  Node* pNode = m_pRoot;
295  Node* pNodeSmaller = nullptr;
296 
297  while (pNode != &m_NilNode)
298  {
299  const ezInt32 dir = (ezInt32) m_Comparer.Less(pNode->m_Key, key);
300  const ezInt32 dir2= (ezInt32) m_Comparer.Less(key, pNode->m_Key);
301 
302  if (dir == dir2)
303  return pNode;
304 
305  if (dir == 0)
306  pNodeSmaller = pNode;
307 
308  pNode = pNode->m_pLink[dir];
309  }
310 
311  return pNodeSmaller;
312 }
313 
314 template <typename KeyType, typename ValueType, typename Comparer>
316 {
317  return Iterator(Internal_LowerBound(key));
318 }
319 
320 template <typename KeyType, typename ValueType, typename Comparer>
322 {
323  return ConstIterator(Internal_LowerBound(key));
324 }
325 
326 template <typename KeyType, typename ValueType, typename Comparer>
328 {
329  Node* pNode = m_pRoot;
330  Node* pNodeSmaller = nullptr;
331 
332  while (pNode != &m_NilNode)
333  {
334  const ezInt32 dir = (ezInt32) m_Comparer.Less(pNode->m_Key, key);
335  const ezInt32 dir2= (ezInt32) m_Comparer.Less(key, pNode->m_Key);
336 
337  if (dir == dir2)
338  {
339  ConstIterator it(pNode);
340  ++it;
341  return it.m_pElement;
342  }
343 
344  if (dir == 0)
345  pNodeSmaller = pNode;
346 
347  pNode = pNode->m_pLink[dir];
348  }
349 
350  return pNodeSmaller;
351 }
352 
353 template <typename KeyType, typename ValueType, typename Comparer>
355 {
356  return Iterator(Internal_UpperBound(key));
357 }
358 
359 template <typename KeyType, typename ValueType, typename Comparer>
361 {
362  return ConstIterator(Internal_UpperBound(key));
363 }
364 
365 template <typename KeyType, typename ValueType, typename Comparer>
367 {
368  return FindOrAdd(key).Value();
369 }
370 
371 template <typename KeyType, typename ValueType, typename Comparer>
373 {
374  Node* pNilNode = reinterpret_cast<Node*>(&m_NilNode);
375  Node* pInsertedNode = nullptr;
376 
377  {
378  Node* root = m_pRoot;
379 
380  if (m_pRoot != pNilNode)
381  {
382  Node* it = m_pRoot;
383  Node* up[STACK_SIZE];
384 
385  ezInt32 top = 0;
386  ezUInt32 dir = 0;
387 
388  while (true)
389  {
390  if (m_Comparer.Equal(it->m_Key, key))
391  {
392  if (bExisted)
393  *bExisted = true;
394 
395  return Iterator(it);
396  }
397 
398  dir = m_Comparer.Less(it->m_Key, key) ? 1 : 0;
399 
400  EZ_ASSERT_DEBUG(top < STACK_SIZE, "ezMapBase's internal stack is not large enough to be able to sort %i elements.", GetCount());
401  up[top++] = it;
402 
403  if (it->m_pLink[dir] == pNilNode)
404  break;
405 
406  it = it->m_pLink[dir];
407  }
408 
409  pInsertedNode = AcquireNode(key, ValueType(), 1, it);
410  it->m_pLink[dir] = pInsertedNode;
411 
412  while (--top >= 0)
413  {
414  if (top != 0)
415  dir = (up[top - 1]->m_pLink[1] == up[top]) ? 1 : 0;
416 
417  up[top] = SkewNode(up[top]);
418  up[top] = SplitNode(up[top]);
419 
420  if (top != 0)
421  {
422  up[top - 1]->m_pLink[dir] = up[top];
423  up[top - 1]->m_pLink[dir]->m_pParent = up[top - 1];
424  }
425  else
426  root = up[top];
427  }
428  }
429  else
430  {
431  pInsertedNode = AcquireNode(key, ValueType(), 1, pNilNode);
432  root = pInsertedNode;
433  }
434 
435  m_pRoot = root;
436  m_pRoot->m_pParent = pNilNode;
437  m_NilNode.m_pParent = pNilNode;
438  }
439 
440  EZ_ASSERT_DEBUG(pInsertedNode != nullptr, "Implementation Error.");
441 
442  if (bExisted)
443  *bExisted = false;
444 
445  return Iterator(pInsertedNode);
446 }
447 
448 template <typename KeyType, typename ValueType, typename Comparer>
450 {
451  auto it = FindOrAdd(key);
452  it.Value() = value;
453 
454  return it;
455 }
456 
457 template <typename KeyType, typename ValueType, typename Comparer>
459 {
460  bool bRemoved = true;
461  m_pRoot = Remove(m_pRoot, key, bRemoved);
462  m_pRoot->m_pParent = reinterpret_cast<Node*>(&m_NilNode);
463  m_NilNode.m_pParent = reinterpret_cast<Node*>(&m_NilNode);
464 
465  return bRemoved;
466 }
467 
468 template <typename KeyType, typename ValueType, typename Comparer>
469 typename ezMapBase<KeyType, ValueType, Comparer>::Node* ezMapBase<KeyType, ValueType, Comparer>::AcquireNode(const KeyType& key, const ValueType& value, ezInt32 uiLevel, Node* pParent)
470 {
471  Node* pNode;
472 
473  if (m_pFreeElementStack == nullptr)
474  {
475  m_Elements.PushBack();
476  pNode = &m_Elements.PeekBack();
477  }
478  else
479  {
480  pNode = m_pFreeElementStack;
481  m_pFreeElementStack = m_pFreeElementStack->m_pParent;
482  }
483 
484  ezMemoryUtils::Construct(pNode, 1);
485 
486  pNode->m_pParent = pParent;
487  pNode->m_Key = key;
488  pNode->m_Value = value;
489  pNode->m_uiLevel = uiLevel;
490  pNode->m_pLink[0] = reinterpret_cast<Node*>(&m_NilNode);
491  pNode->m_pLink[1] = reinterpret_cast<Node*>(&m_NilNode);
492 
493  ++m_uiCount;
494 
495  return pNode;
496 }
497 
498 template <typename KeyType, typename ValueType, typename Comparer>
500 {
501  EZ_ASSERT_DEV(pNode != nullptr, "pNode is invalid.");
502  EZ_ASSERT_DEV(pNode != &m_NilNode, "pNode is invalid.");
503 
504  ezMemoryUtils::Destruct<Node>(pNode, 1);
505 
506  // try to reduce the element array, if possible
507  if (pNode == &m_Elements.PeekBack())
508  {
509  m_Elements.PopBack();
510  }
511  else
512  if (pNode == &m_Elements.PeekFront())
513  {
514  m_Elements.PopFront();
515  }
516  else
517  {
518  pNode->m_pParent = m_pFreeElementStack;
519  m_pFreeElementStack = pNode;
520  }
521 
522  --m_uiCount;
523 }
524 
525 template <typename KeyType, typename ValueType, typename Comparer>
527 {
528  if ((root->m_pLink[0]->m_uiLevel == root->m_uiLevel) && (root->m_uiLevel != 0))
529  {
530  Node* save = root->m_pLink[0];
531  root->m_pLink[0] = save->m_pLink[1];
532  root->m_pLink[0]->m_pParent = root;
533  save->m_pLink[1] = root;
534  save->m_pLink[1]->m_pParent = save;
535  root = save;
536  }
537 
538  return root;
539 }
540 
541 template <typename KeyType, typename ValueType, typename Comparer>
543 {
544  if ((root->m_pLink[1]->m_pLink[1]->m_uiLevel == root->m_uiLevel) && (root->m_uiLevel != 0))
545  {
546  Node* save = root->m_pLink[1];
547  root->m_pLink[1] = save->m_pLink[0];
548  root->m_pLink[1]->m_pParent = root;
549  save->m_pLink[0] = root;
550  save->m_pLink[0]->m_pParent = save;
551  root = save;
552  ++root->m_uiLevel;
553  }
554 
555  return root;
556 }
557 
558 template <typename KeyType, typename ValueType, typename Comparer>
559 typename ezMapBase<KeyType, ValueType, Comparer>::Node* ezMapBase<KeyType, ValueType, Comparer>::Remove(Node* root, const KeyType& key, bool& bRemoved)
560 {
561  bRemoved = false;
562 
563  Node* ToErase = reinterpret_cast<Node*>(&m_NilNode);
564  Node* ToOverride = reinterpret_cast<Node*>(&m_NilNode);
565 
566  if (root != &m_NilNode)
567  {
568  Node* it = root;
569  Node* up[STACK_SIZE];
570  ezInt32 top = 0;
571  ezInt32 dir = 0;
572 
573  while (true)
574  {
575  EZ_ASSERT_DEBUG(top >= 0 && top < STACK_SIZE, "Implementation error");
576  up[top++] = it;
577 
578  if (it == &m_NilNode)
579  return root;
580 
581  if (m_Comparer.Equal(it->m_Key, key))
582  break;
583 
584  dir = m_Comparer.Less(it->m_Key, key) ? 1 : 0;
585 
586  it = it->m_pLink[dir];
587  }
588 
589  ToOverride = it;
590 
591  if ((it->m_pLink[0] == &m_NilNode) || (it->m_pLink[1] == &m_NilNode))
592  {
593  ezInt32 dir2 = it->m_pLink[0] == &m_NilNode;
594 
595  if (--top != 0)
596  {
597  EZ_ASSERT_DEBUG(top >= 1 && top < STACK_SIZE, "Implementation error");
598  up[top - 1]->m_pLink[dir] = it->m_pLink[dir2];
599  up[top - 1]->m_pLink[dir]->m_pParent = up[top - 1];
600  }
601  else
602  root = it->m_pLink[1];
603  }
604  else
605  {
606  Node* heir = it->m_pLink[1];
607  Node* prev = it;
608 
609  while (heir->m_pLink[0] != &m_NilNode)
610  {
611  EZ_ASSERT_DEBUG(top >= 0 && top < STACK_SIZE, "Implementation error");
612  up[top++] = prev = heir;
613 
614  heir = heir->m_pLink[0];
615  }
616 
617  ToErase = heir;
618  ToOverride = it;
619 
620  prev->m_pLink[prev == it] = heir->m_pLink[1];
621  prev->m_pLink[prev == it]->m_pParent = prev;
622  }
623 
624  while (--top >= 0)
625  {
626  if (top != 0)
627  {
628  EZ_ASSERT_DEBUG(top >= 1 && top < STACK_SIZE, "Implementation error");
629  dir = up[top - 1]->m_pLink[1] == up[top];
630  }
631 
632  EZ_ASSERT_DEBUG(top >= 0 && top < STACK_SIZE, "Implementation error");
633 
634  if ((up[top]->m_pLink[0]->m_uiLevel < up[top]->m_uiLevel - 1) || (up[top]->m_pLink[1]->m_uiLevel < up[top]->m_uiLevel - 1))
635  {
636  if (up[top]->m_pLink[1]->m_uiLevel > --up[top]->m_uiLevel)
637  up[top]->m_pLink[1]->m_uiLevel = up[top]->m_uiLevel;
638 
639  up[top] = SkewNode(up[top]);
640  up[top]->m_pLink[1] = SkewNode(up[top]->m_pLink[1]);
641  up[top]->m_pLink[1]->m_pParent = up[top];
642 
643  up[top]->m_pLink[1]->m_pLink[1] = SkewNode(up[top]->m_pLink[1]->m_pLink[1]);
644  up[top] = SplitNode(up[top]);
645  up[top]->m_pLink[1] = SplitNode(up[top]->m_pLink[1]);
646  up[top]->m_pLink[1]->m_pParent = up[top];
647  }
648 
649  if (top != 0)
650  {
651  EZ_ASSERT_DEBUG(top >= 1 && top < STACK_SIZE, "Implementation error");
652 
653  up[top - 1]->m_pLink[dir] = up[top];
654  up[top - 1]->m_pLink[dir]->m_pParent = up[top - 1];
655  }
656  else
657  {
658  EZ_ASSERT_DEBUG(top >= 0 && top < STACK_SIZE, "Implementation error");
659  root = up[top];
660  }
661  }
662  }
663 
664  root->m_pParent = reinterpret_cast<Node*>(&m_NilNode);
665 
666 
667  // if necessary, swap nodes
668  if (ToErase != &m_NilNode)
669  {
670  Node* parent = ToOverride->m_pParent;
671 
672  if (parent != &m_NilNode)
673  {
674  if (parent->m_pLink[0] == ToOverride)
675  {
676  parent->m_pLink[0] = ToErase;
677  parent->m_pLink[0]->m_pParent = parent;
678  }
679  if (parent->m_pLink[1] == ToOverride)
680  {
681  parent->m_pLink[1] = ToErase;
682  parent->m_pLink[1]->m_pParent = parent;
683  }
684  }
685  else
686  root = ToErase;
687 
688  ToErase->m_uiLevel = ToOverride->m_uiLevel;
689  ToErase->m_pLink[0] = ToOverride->m_pLink[0];
690  ToErase->m_pLink[0]->m_pParent = ToErase;
691  ToErase->m_pLink[1] = ToOverride->m_pLink[1];
692  ToErase->m_pLink[1]->m_pParent = ToErase;
693  }
694 
695  // remove the erased node
696  if (ToOverride != &m_NilNode)
697  {
698  bRemoved = true;
699  ReleaseNode(ToOverride);
700  }
701 
702  return root;
703 }
704 
705 template <typename KeyType, typename ValueType, typename Comparer>
707 {
708  EZ_ASSERT_DEV(pos.m_pElement != nullptr, "The Iterator(pos) is invalid.");
709 
710  Iterator temp(pos);
711  ++temp;
712  Remove(pos.Key());
713  return temp;
714 }
715 
716 template <typename KeyType, typename ValueType, typename Comparer>
718 {
719  if (GetCount() != rhs.GetCount())
720  return false;
721 
722  auto itLhs = GetIterator();
723  auto itRhs = rhs.GetIterator();
724 
725  while (itLhs.IsValid())
726  {
727  if (!m_Comparer.Equal(itLhs.Key(), itRhs.Key()))
728  return false;
729 
730  if (itLhs.Value() != itRhs.Value())
731  return false;
732 
733  ++itLhs;
734  ++itRhs;
735  }
736 
737  return true;
738 }
739 
740 template <typename KeyType, typename ValueType, typename Comparer>
742 {
743  return !operator==(rhs);
744 }
745 
746 #undef STACK_SIZE
747 
748 
749 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
750 ezMap<KeyType, ValueType, Comparer, AllocatorWrapper>::ezMap() : ezMapBase<KeyType, ValueType, Comparer>(Comparer(), AllocatorWrapper::GetAllocator())
751 {
752 }
753 
754 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
755 ezMap<KeyType, ValueType, Comparer, AllocatorWrapper>::ezMap(const Comparer& comparer, ezAllocatorBase* pAllocator) : ezMapBase<KeyType, ValueType, Comparer>(comparer, pAllocator)
756 {
757 }
758 
759 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
760 ezMap<KeyType, ValueType, Comparer, AllocatorWrapper>::ezMap(const ezMap<KeyType, ValueType, Comparer, AllocatorWrapper>& other) : ezMapBase<KeyType, ValueType, Comparer>(other, AllocatorWrapper::GetAllocator())
761 {
762 }
763 
764 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
765 ezMap<KeyType, ValueType, Comparer, AllocatorWrapper>::ezMap(const ezMapBase<KeyType, ValueType, Comparer>& other) : ezMapBase<KeyType, ValueType, Comparer>(other, AllocatorWrapper::GetAllocator())
766 {
767 }
768 
769 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
771 {
773 }
774 
775 template <typename KeyType, typename ValueType, typename Comparer, typename AllocatorWrapper>
777 {
779 }
780