Skip to content

Commit 43463e3

Browse files
committed
[debug] Add "Iterating" helper to avoid calling erase() when iterating a obs::fast_list
1 parent 72940d0 commit 43463e3

5 files changed

Lines changed: 44 additions & 0 deletions

File tree

obs/fast_list.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010

1111
#include <algorithm>
12+
#include <cassert>
1213
#include <functional>
1314
#include <vector>
1415

@@ -17,6 +18,9 @@ namespace obs {
1718
template<typename T>
1819
class fast_list {
1920
std::vector<T*> m_list;
21+
#ifndef NDEBUG
22+
int m_iterating = 0;
23+
#endif
2024

2125
public:
2226
using iterator = typename std::vector<T*>::iterator;
@@ -33,10 +37,21 @@ class fast_list {
3337
}
3438

3539
void erase(T* value) {
40+
assert(m_iterating == 0);
3641
auto it = std::find(m_list.begin(), m_list.end(), value);
3742
if (it != m_list.end())
3843
m_list.erase(it);
3944
}
45+
46+
#ifndef NDEBUG
47+
void set_iterating(const bool state) {
48+
if (state)
49+
++m_iterating;
50+
else
51+
--m_iterating;
52+
}
53+
#endif
54+
4055
};
4156

4257
} // namespace obs

obs/lists.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ namespace obs {
2121
using default_list = safe_list<T>;
2222
#endif
2323

24+
#ifdef _DEBUG
25+
template<typename List>
26+
struct Iterating {
27+
List& m_list;
28+
Iterating(List& list) : m_list(list) {
29+
m_list.set_iterating(true);
30+
}
31+
~Iterating() {
32+
m_list.set_iterating(false);
33+
}
34+
};
35+
#endif
36+
2437
} // namespace obs
2538

2639
#endif

obs/observers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class observers {
3232

3333
template<typename ...Args>
3434
void notify_observers(void (observer_type::*method)(Args...), Args ...args) {
35+
#ifdef _DEBUG
36+
Iterating<list_type> flag(m_observers);
37+
#endif
3538
for (auto observer : m_observers) {
3639
if (observer)
3740
(observer->*method)(std::forward<Args>(args)...);

obs/safe_list.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,13 @@ class safe_list {
359359
delete_nodes(false);
360360
}
361361

362+
#ifndef NDEBUG
363+
void set_iterating(const bool) {
364+
// No need to set a flag here for debugging purposes as we support
365+
// calling erase() member function when we're iterating the items.
366+
}
367+
#endif
368+
362369
private:
363370
// Deletes nodes from the list. If "all" is true, deletes all nodes,
364371
// if it's false, it deletes only nodes with value == nullptr, which

obs/signal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class signal<R(Args...), List> : public signal_base {
7070
template<typename U = R, typename...Args2>
7171
typename std::enable_if<std::is_void<U>::value, void>::type
7272
operator()(Args2&&...args) {
73+
#ifdef _DEBUG
74+
Iterating<slot_list> flag(m_slots);
75+
#endif
7376
for (auto slot : m_slots)
7477
if (slot)
7578
(*slot)(std::forward<Args2>(args)...);
@@ -78,6 +81,9 @@ class signal<R(Args...), List> : public signal_base {
7881
template<typename U = R, typename...Args2>
7982
typename std::enable_if<!std::is_void<U>::value, U>::type
8083
operator()(Args2&&...args) {
84+
#ifdef _DEBUG
85+
Iterating<slot_list> flag(m_slots);
86+
#endif
8187
U result = {};
8288
for (auto slot : m_slots)
8389
if (slot)

0 commit comments

Comments
 (0)