@@ -27,8 +27,8 @@ namespace internal {
2727 *
2828 * Notes:
2929 * - Intended for append-then-read patterns.
30- * - size_ increments before construction finishes. If readers iterate up to size()
31- * concurrently with writers, you need a constructed/published protocol.
30+ * - size_ increments before construction finishes. If readers iterate up to
31+ * size() concurrently with writers, you need a constructed/published protocol.
3232 * - clear()/destruction are NOT concurrent with pushes/reads.
3333 */
3434template <typename T, std::size_t BaseSegmentSize = 1024 ,
@@ -41,7 +41,8 @@ class concurrent_vector {
4141
4242 public:
4343 concurrent_vector () noexcept : size_(0 ) {
44- for (auto & p : segments_) p.store (nullptr , std::memory_order_relaxed);
44+ for (auto & p : segments_)
45+ p.store (nullptr , std::memory_order_relaxed);
4546 }
4647
4748 concurrent_vector (const concurrent_vector& other) : concurrent_vector() {
@@ -55,17 +56,19 @@ class concurrent_vector {
5556 }
5657 return *this ;
5758 }
58-
59+
5960 // Movable (needed so Stan can return-by-value)
6061 concurrent_vector (concurrent_vector&& other) noexcept : size_(0 ) {
61- for (auto & p : segments_) p.store (nullptr , std::memory_order_relaxed);
62+ for (auto & p : segments_)
63+ p.store (nullptr , std::memory_order_relaxed);
6264 move_from_ (other);
6365 }
6466
6567 concurrent_vector& operator =(concurrent_vector&& other) noexcept {
6668 if (this != &other) {
6769 destroy_all_ ();
68- for (auto & p : segments_) p.store (nullptr , std::memory_order_relaxed);
70+ for (auto & p : segments_)
71+ p.store (nullptr , std::memory_order_relaxed);
6972 size_.store (0 , std::memory_order_relaxed);
7073 move_from_ (other);
7174 }
@@ -87,13 +90,16 @@ class concurrent_vector {
8790 }
8891
8992 // Pre-allocate enough segments to back indices [0, capacity-1].
90- // Safe to call concurrently with emplace_back (may race allocating segments; losers free).
93+ // Safe to call concurrently with emplace_back (may race allocating segments;
94+ // losers free).
9195 void reserve (std::size_t capacity) {
92- if (capacity == 0 ) return ;
96+ if (capacity == 0 )
97+ return ;
9398 const std::size_t last = capacity - 1 ;
9499 const std::size_t last_seg = segment_index_ (last);
95100 if (last_seg >= MaxSegments) {
96- throw std::length_error (" concurrent_vector::reserve: exceeds MaxSegments" );
101+ throw std::length_error (
102+ " concurrent_vector::reserve: exceeds MaxSegments" );
97103 }
98104 for (std::size_t s = 0 ; s <= last_seg; ++s) {
99105 ensure_segment_ (s);
@@ -124,11 +130,13 @@ class concurrent_vector {
124130
125131 // Bounds-checked access.
126132 T& at (std::size_t i) {
127- if (i >= size ()) throw std::out_of_range (" concurrent_vector::at" );
133+ if (i >= size ())
134+ throw std::out_of_range (" concurrent_vector::at" );
128135 return *data_at (i);
129136 }
130137 const T& at (std::size_t i) const {
131- if (i >= size ()) throw std::out_of_range (" concurrent_vector::at" );
138+ if (i >= size ())
139+ throw std::out_of_range (" concurrent_vector::at" );
132140 return *data_at (i);
133141 }
134142
@@ -154,13 +162,22 @@ class concurrent_vector {
154162 reference operator *() const { return (*v_)[i_]; }
155163 pointer operator ->() const { return &(*v_)[i_]; }
156164
157- iterator& operator ++() { ++i_; return *this ; }
158- iterator operator ++(int ) { iterator tmp = *this ; ++(*this ); return tmp; }
165+ iterator& operator ++() {
166+ ++i_;
167+ return *this ;
168+ }
169+ iterator operator ++(int ) {
170+ iterator tmp = *this ;
171+ ++(*this );
172+ return tmp;
173+ }
159174
160175 friend bool operator ==(const iterator& a, const iterator& b) {
161176 return a.v_ == b.v_ && a.i_ == b.i_ ;
162177 }
163- friend bool operator !=(const iterator& a, const iterator& b) { return !(a == b); }
178+ friend bool operator !=(const iterator& a, const iterator& b) {
179+ return !(a == b);
180+ }
164181
165182 private:
166183 concurrent_vector* v_;
@@ -181,21 +198,32 @@ class concurrent_vector {
181198 reference operator *() const { return (*v_)[i_]; }
182199 pointer operator ->() const { return &(*v_)[i_]; }
183200
184- const_iterator& operator ++() { ++i_; return *this ; }
185- const_iterator operator ++(int ) { const_iterator tmp = *this ; ++(*this ); return tmp; }
201+ const_iterator& operator ++() {
202+ ++i_;
203+ return *this ;
204+ }
205+ const_iterator operator ++(int ) {
206+ const_iterator tmp = *this ;
207+ ++(*this );
208+ return tmp;
209+ }
186210
187211 friend bool operator ==(const const_iterator& a, const const_iterator& b) {
188212 return a.v_ == b.v_ && a.i_ == b.i_ ;
189213 }
190- friend bool operator !=(const const_iterator& a, const const_iterator& b) { return !(a == b); }
214+ friend bool operator !=(const const_iterator& a, const const_iterator& b) {
215+ return !(a == b);
216+ }
191217
192218 private:
193219 const concurrent_vector* v_;
194220 std::size_t i_;
195221 };
196222
197223 iterator begin () noexcept { return iterator (this , 0 ); }
198- iterator end () noexcept { return iterator (this , size ()); } // snapshot at call time
224+ iterator end () noexcept {
225+ return iterator (this , size ());
226+ } // snapshot at call time
199227
200228 const_iterator begin () const noexcept { return const_iterator (this , 0 ); }
201229 const_iterator end () const noexcept { return const_iterator (this , size ()); }
@@ -205,13 +233,15 @@ class concurrent_vector {
205233
206234 T& back () {
207235 const std::size_t n = size ();
208- if (n == 0 ) throw std::out_of_range (" concurrent_vector::back on empty" );
236+ if (n == 0 )
237+ throw std::out_of_range (" concurrent_vector::back on empty" );
209238 return (*this )[n - 1 ];
210239 }
211240
212241 const T& back () const {
213242 const std::size_t n = size ();
214- if (n == 0 ) throw std::out_of_range (" concurrent_vector::back on empty" );
243+ if (n == 0 )
244+ throw std::out_of_range (" concurrent_vector::back on empty" );
215245 return (*this )[n - 1 ];
216246 }
217247 // -------------------------
@@ -235,16 +265,19 @@ class concurrent_vector {
235265
236266#if defined(__GNUG__) || defined(__clang__)
237267 if constexpr (sizeof (std::size_t ) == 8 ) {
238- return 63u - static_cast <std::size_t >(
239- __builtin_clzll (static_cast <unsigned long long >(x)));
268+ return 63u
269+ - static_cast <std::size_t >(
270+ __builtin_clzll (static_cast <unsigned long long >(x)));
240271 } else {
241- return 31u - static_cast <std::size_t >(
242- __builtin_clzl (static_cast <unsigned long >(x)));
272+ return 31u
273+ - static_cast <std::size_t >(
274+ __builtin_clzl (static_cast <unsigned long >(x)));
243275 }
244276#else
245277 std::size_t s = 0 ;
246278 std::size_t t = x;
247- while (t >>= 1 ) ++s;
279+ while (t >>= 1 )
280+ ++s;
248281 return s;
249282#endif
250283 }
@@ -263,7 +296,8 @@ class concurrent_vector {
263296
264297 T* ensure_segment_ (std::size_t s) {
265298 T* seg = segment_ptr_ (s);
266- if (seg) return seg;
299+ if (seg)
300+ return seg;
267301
268302 const std::size_t n = segment_size_ (s);
269303 void * raw = ::operator new (sizeof (T) * n);
@@ -299,7 +333,8 @@ class concurrent_vector {
299333
300334 for (auto & a : segments_) {
301335 void * p = a.exchange (nullptr , std::memory_order_acq_rel);
302- if (p) ::operator delete (p);
336+ if (p)
337+ ::operator delete (p);
303338 }
304339 }
305340
@@ -317,7 +352,8 @@ class concurrent_vector {
317352
318353 void copy_from_ (const concurrent_vector& other) {
319354 const std::size_t n = other.size ();
320- if (n == 0 ) return ;
355+ if (n == 0 )
356+ return ;
321357
322358 reserve (n);
323359 // Important: we want size_ to match, but we must construct elements.
@@ -326,7 +362,7 @@ class concurrent_vector {
326362 emplace_back (other[i]);
327363 }
328364 }
329-
365+
330366 std::atomic<std::size_t > size_;
331367 std::array<std::atomic<void *>, MaxSegments> segments_;
332368};
0 commit comments