@@ -406,6 +406,23 @@ namespace RE
406
406
set_size (newSize);
407
407
}
408
408
409
+ inline BSTArray (const std::initializer_list<T> a_list)
410
+ {
411
+ if (a_list.size () == 0 ) {
412
+ return ;
413
+ }
414
+
415
+ const auto newSize = a_list.size ();
416
+ const auto newData = allocate (newSize);
417
+ size_type i = 0 ;
418
+ for (const auto & elem : a_list) {
419
+ std::construct_at (newData + i++, elem);
420
+ }
421
+
422
+ set_allocator_traits (newData, newSize);
423
+ set_size (newSize);
424
+ }
425
+
409
426
BSTArray (BSTArray&&) = default ;
410
427
411
428
explicit inline BSTArray (size_type a_count)
@@ -555,6 +572,53 @@ namespace RE
555
572
return elem;
556
573
}
557
574
575
+ inline void insert (const_iterator position, const value_type& a_value) { emplace (position, a_value); }
576
+ inline void insert (const_iterator position, value_type&& a_value) { emplace (position, std::move (a_value)); }
577
+
578
+ inline void push_front (const value_type& a_value) { emplace (cbegin (), a_value); }
579
+ inline void push_front (value_type&& a_value) { emplace (cbegin (), std::move (a_value)); }
580
+
581
+ template <class ... Args>
582
+ inline reference emplace (const_iterator position, Args&&... a_args)
583
+ {
584
+ assert (position >= cbegin () && position <= cend ());
585
+
586
+ if (position == cend ()) {
587
+ return emplace_back (std::forward<Args>(a_args)...);
588
+ }
589
+
590
+ pointer oldData;
591
+ pointer newData;
592
+ size_type newCapacity;
593
+
594
+ if (size () == capacity ()) {
595
+ newCapacity = next_capacity ();
596
+ newData = allocate (newCapacity); // manually grow capacity to avoid unnecessary memcpy from change_capacity
597
+ oldData = data ();
598
+ } else {
599
+ newData = data ();
600
+ oldData = nullptr ;
601
+ newCapacity = capacity ();
602
+ }
603
+
604
+ const auto headPartToCopy = position - cbegin ();
605
+ const auto tailPartToCopy = cend () - position;
606
+ const auto tailBytesToCopy = tailPartToCopy * sizeof (T);
607
+ std::memcpy (newData + headPartToCopy + 1 , cend () - tailPartToCopy, tailBytesToCopy);
608
+ std::construct_at (newData + headPartToCopy, std::forward<Args>(a_args)...);
609
+ const auto headBytesToCopy = headPartToCopy * sizeof (T);
610
+ std::memcpy (newData, cbegin (), headBytesToCopy);
611
+
612
+ if (oldData) {
613
+ deallocate (oldData);
614
+ set_allocator_traits (newData, newCapacity);
615
+ }
616
+
617
+ set_size (size () + 1 );
618
+
619
+ return *(newData + headPartToCopy);
620
+ }
621
+
558
622
inline void pop_back ()
559
623
{
560
624
assert (!empty ());
@@ -630,13 +694,25 @@ namespace RE
630
694
set_size (a_newSize);
631
695
}
632
696
633
- inline void grow_capacity () { grow_capacity (capacity ()); }
697
+ // / Calculates the next value for the array capacity.
698
+ // / Capacity grows exponentially: hint * 2^level, where level is the number of times the capacity has grown.
699
+ [[nodiscard]]
700
+ inline size_type next_capacity () const { return next_capacity (capacity ()); }
634
701
635
- inline void grow_capacity (size_type a_hint)
702
+ // / Calculates the next value for the array capacity.
703
+ // / Capacity grows exponentially: hint * 2^level, where level is the number of times the capacity has grown.
704
+ inline size_type next_capacity (size_type a_hint) const
636
705
{
637
706
auto cap = a_hint;
638
707
cap = cap > 0 ? static_cast <size_type>(std::ceil (static_cast <float >(cap) * GROWTH_FACTOR)) : DF_CAP;
639
- change_capacity (cap);
708
+ return cap;
709
+ }
710
+
711
+ inline void grow_capacity () { grow_capacity (capacity ()); }
712
+
713
+ inline void grow_capacity (size_type a_hint)
714
+ {
715
+ change_capacity (next_capacity (a_hint));
640
716
}
641
717
642
718
inline void release ()
0 commit comments