3
3
#include " defs.h"
4
4
#include " queue_chunk.h"
5
5
6
- template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>>
6
+ template <typename T, ui32 TSize, class D = TNoAction, typename TChunk = TQueueChunk<T, TSize>>
7
7
class TOneOneQueueInplace : TNonCopyable {
8
- static_assert (std::is_integral<T>::value || std::is_pointer<T>::value, " expect std::is_integral<T>::value || std::is_pointer<T>::valuer " );
8
+ static_assert (std::is_integral<T>::value || std::is_pointer<T>::value, " expect std::is_integral<T>::value || std::is_pointer<T>::value " );
9
9
10
10
TChunk* ReadFrom;
11
11
ui32 ReadPosition;
12
12
ui32 WritePosition;
13
13
TChunk* WriteTo;
14
14
15
- friend class TReadIterator ;
16
-
17
15
public:
18
16
class TReadIterator {
19
17
TChunk* ReadFrom;
@@ -28,14 +26,15 @@ class TOneOneQueueInplace : TNonCopyable {
28
26
29
27
inline T Next () {
30
28
TChunk* head = ReadFrom;
31
- if (ReadPosition != TChunk::EntriesCount) {
32
- return AtomicLoad (&head->Entries [ReadPosition++]);
33
- } else if (TChunk* next = AtomicLoad (&head->Next )) {
34
- ReadFrom = next;
29
+ if (ReadPosition == TChunk::EntriesCount) [[unlikely]] {
30
+ head = AtomicLoad (&head->Next );
31
+ if (!head) {
32
+ return T{};
33
+ }
34
+ ReadFrom = head;
35
35
ReadPosition = 0 ;
36
- return Next ();
37
36
}
38
- return T{} ;
37
+ return AtomicLoad (&head-> Entries [ReadPosition++]) ;
39
38
}
40
39
};
41
40
@@ -48,71 +47,83 @@ class TOneOneQueueInplace : TNonCopyable {
48
47
}
49
48
50
49
~TOneOneQueueInplace () {
51
- Y_DEBUG_ABORT_UNLESS (Head () == 0 );
52
- delete ReadFrom;
53
- }
54
-
55
- struct TPtrCleanDestructor {
56
- static inline void Destroy (TOneOneQueueInplace<T, TSize>* x) noexcept {
57
- while (T head = x->Pop ())
50
+ if constexpr (!std::is_same_v<D, TNoAction>) {
51
+ while (T x = Pop ()) {
52
+ D::Destroy (x);
53
+ }
54
+ delete ReadFrom;
55
+ } else {
56
+ TChunk* next = ReadFrom;
57
+ do {
58
+ TChunk* head = next;
59
+ next = AtomicLoad (&head->Next );
58
60
delete head;
59
- delete x ;
61
+ } while (next) ;
60
62
}
61
- };
63
+ }
62
64
63
65
struct TCleanDestructor {
64
66
static inline void Destroy (TOneOneQueueInplace<T, TSize>* x) noexcept {
65
- while (x->Pop () != nullptr )
66
- continue ;
67
67
delete x;
68
68
}
69
69
};
70
70
71
- struct TPtrCleanInplaceMallocDestructor {
72
- template <typename TPtrVal>
73
- static inline void Destroy (TOneOneQueueInplace<TPtrVal*, TSize>* x) noexcept {
74
- while (TPtrVal* head = x->Pop ()) {
75
- head->~TPtrVal ();
76
- free (head);
71
+ struct TPtrCleanDestructor {
72
+ static inline void Destroy (TOneOneQueueInplace<T, TSize>* x) noexcept {
73
+ while (T head = x->Pop ()) {
74
+ ::CheckedDelete (head);
77
75
}
78
76
delete x;
79
77
}
80
78
};
81
79
82
- void Push (T x) noexcept {
83
- if (WritePosition != TChunk::EntriesCount) {
84
- AtomicStore (&WriteTo->Entries [WritePosition], x);
85
- ++WritePosition;
86
- } else {
80
+ void Push (T x) {
81
+ if (WritePosition == TChunk::EntriesCount) [[unlikely]] {
87
82
TChunk* next = new TChunk ();
88
- next->Entries [0 ] = x ;
83
+ AtomicStore (& next->Entries [0 ], x) ;
89
84
AtomicStore (&WriteTo->Next , next);
90
85
WriteTo = next;
91
86
WritePosition = 1 ;
87
+ } else {
88
+ AtomicStore (&WriteTo->Entries [WritePosition++], x);
92
89
}
93
90
}
94
91
95
92
T Head () {
96
93
TChunk* head = ReadFrom;
97
- if (ReadPosition != TChunk::EntriesCount) {
98
- return AtomicLoad (&head->Entries [ReadPosition]);
99
- } else if (TChunk* next = AtomicLoad (&head->Next )) {
100
- ReadFrom = next;
94
+ if (ReadPosition == TChunk::EntriesCount) [[unlikely]] {
95
+ TChunk* next = AtomicLoad (&head->Next );
96
+ if (!next) {
97
+ return T{};
98
+ }
101
99
delete head;
100
+ head = next;
101
+ ReadFrom = next;
102
102
ReadPosition = 0 ;
103
- return Head ();
104
103
}
105
- return T{} ;
104
+ return AtomicLoad (&head-> Entries [ReadPosition]) ;
106
105
}
107
106
108
107
T Pop () {
109
108
T ret = Head ();
110
- if (ret)
109
+ if (ret) {
111
110
++ReadPosition;
111
+ }
112
112
return ret;
113
113
}
114
114
115
115
TReadIterator Iterator () {
116
116
return TReadIterator (ReadFrom, ReadPosition);
117
117
}
118
+
119
+ /* *
120
+ * Swap must synchronize with both reader and writer
121
+ */
122
+ void Swap (TOneOneQueueInplace& other) {
123
+ using std::swap;
124
+ swap (ReadFrom, other.ReadFrom );
125
+ swap (ReadPosition, other.ReadPosition );
126
+ swap (WritePosition, other.WritePosition );
127
+ swap (WriteTo, other.WriteTo );
128
+ }
118
129
};
0 commit comments