Skip to content

Commit 4a19842

Browse files
authored
Merge pull request #154 from adya/dev
BSTArray: Added insert/emplace to any position
2 parents b4660c3 + 06f80d1 commit 4a19842

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

include/RE/B/BSTArray.h

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,23 @@ namespace RE
406406
set_size(newSize);
407407
}
408408

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+
409426
BSTArray(BSTArray&&) = default;
410427

411428
explicit inline BSTArray(size_type a_count)
@@ -555,6 +572,53 @@ namespace RE
555572
return elem;
556573
}
557574

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+
558622
inline void pop_back()
559623
{
560624
assert(!empty());
@@ -630,13 +694,25 @@ namespace RE
630694
set_size(a_newSize);
631695
}
632696

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()); }
634701

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
636705
{
637706
auto cap = a_hint;
638707
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));
640716
}
641717

642718
inline void release()

include/RE/B/BSTEvent.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,48 @@ namespace RE
6161
AddEventSink(a_sink);
6262
}
6363

64+
/// Adds an event sink to the front of sinks list.
65+
///
66+
/// When there is an ongoing notification, sinks are prepended to a pending list.
67+
/// Consider the following case: Add(A), Add(B), notifying=true, Add(C), Prepend(D), Prepend(E), notifying = false
68+
/// Sinks: A, B
69+
/// Pending: E, D, C
70+
/// Result: A, B, E, D, C
71+
///
72+
/// However without notifying the same chain of calls will look like this:
73+
/// Sinks: E, D, A, B, C
74+
///
75+
/// The relative order of C, D, and E is guaranteed in both cases, but, previous sinks may appear both before and after the new sinks.
76+
void PrependEventSink(Sink* a_eventSink)
77+
{
78+
if (!a_eventSink) {
79+
return;
80+
}
81+
82+
BSSpinLockGuard locker(lock);
83+
84+
if (notifying) {
85+
if (std::find(pendingRegisters.begin(), pendingRegisters.end(), a_eventSink) == pendingRegisters.end()) {
86+
pendingRegisters.push_front(a_eventSink);
87+
}
88+
} else {
89+
if (std::find(sinks.begin(), sinks.end(), a_eventSink) == sinks.end()) {
90+
sinks.push_front(a_eventSink);
91+
}
92+
}
93+
94+
auto it = std::find(pendingUnregisters.begin(), pendingUnregisters.end(), a_eventSink);
95+
if (it != pendingUnregisters.end()) {
96+
pendingUnregisters.erase(it);
97+
}
98+
}
99+
100+
template <class SinkEvent>
101+
inline void PrependEventSink(BSTEventSink<SinkEvent>* a_sink)
102+
{
103+
PrependEventSink(a_sink);
104+
}
105+
64106
void RemoveEventSink(Sink* a_eventSink)
65107
{
66108
if (!a_eventSink) {

include/RE/S/ScriptEventSourceHolder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ namespace RE
136136
GetEventSource<T>()->AddEventSink(a_sink);
137137
}
138138

139+
template <class T>
140+
inline void PrependEventSink(BSTEventSink<T>* a_sink)
141+
{
142+
GetEventSource<T>()->PrependEventSink(a_sink);
143+
}
144+
139145
template <class T>
140146
inline void RemoveEventSink(BSTEventSink<T>* a_sink)
141147
{

0 commit comments

Comments
 (0)