17
17
#include < functional>
18
18
#include < stdint.h>
19
19
#include " llvm/Support/Allocator.h"
20
+ #include " Atomic.h"
20
21
#include " Debug.h"
21
22
#include " Mutex.h"
22
23
@@ -422,7 +423,22 @@ template <class ElemTy> struct ConcurrentReadableArray {
422
423
struct Storage {
423
424
std::atomic<size_t > Count;
424
425
typename std::aligned_storage<sizeof (ElemTy), alignof (ElemTy)>::type Elem;
425
-
426
+
427
+ static Storage *allocate (size_t capacity) {
428
+ auto size = sizeof (Storage) + (capacity - 1 ) * sizeof (Storage ().Elem );
429
+ auto *ptr = reinterpret_cast <Storage *>(malloc (size));
430
+ if (!ptr) swift::crash (" Could not allocate memory." );
431
+ ptr->Count .store (0 , std::memory_order_relaxed);
432
+ return ptr;
433
+ }
434
+
435
+ void deallocate () {
436
+ for (size_t i = 0 ; i < Count; i++) {
437
+ data ()[i].~ElemTy ();
438
+ }
439
+ free (this );
440
+ }
441
+
426
442
ElemTy *data () {
427
443
return reinterpret_cast <ElemTy *>(&Elem);
428
444
}
@@ -434,33 +450,22 @@ template <class ElemTy> struct ConcurrentReadableArray {
434
450
Mutex WriterLock;
435
451
std::vector<Storage *> FreeList;
436
452
437
- Storage *allocate (size_t capacity) {
438
- auto size = sizeof (Storage) + (capacity - 1 ) * sizeof (Storage ().Elem );
439
- auto *ptr = reinterpret_cast <Storage *>(malloc (size));
440
- if (!ptr) swift::crash (" Could not allocate memory." );
441
- ptr->Count .store (0 , std::memory_order_relaxed);
442
- return ptr;
443
- }
453
+ public:
454
+ // This type cannot be safely copied, moved, or deleted.
455
+ ConcurrentReadableArray (const ConcurrentReadableArray &) = delete ;
456
+ ConcurrentReadableArray (ConcurrentReadableArray &&) = delete ;
457
+ ConcurrentReadableArray &operator =(const ConcurrentReadableArray &) = delete ;
444
458
445
- void deallocate (Storage *storage) {
446
- if (storage == nullptr ) return ;
447
-
448
- auto *data = storage->data ();
449
- for (size_t i = 0 ; i < storage->Count ; i++) {
450
- data[i].~ElemTy ();
451
- }
452
- free (storage);
453
- }
459
+ ConcurrentReadableArray () : Capacity(0 ), ReaderCount(0 ), Elements(nullptr ) {}
454
460
455
- public:
456
461
void push_back (const ElemTy &elem) {
457
462
ScopedLock guard (WriterLock);
458
463
459
464
auto *storage = Elements.load (std::memory_order_relaxed);
460
465
auto count = storage ? storage->Count .load (std::memory_order_relaxed) : 0 ;
461
466
if (count >= Capacity) {
462
467
auto newCapacity = std::max ((size_t )16 , count * 2 );
463
- auto *newStorage = allocate (newCapacity);
468
+ auto *newStorage = Storage:: allocate (newCapacity);
464
469
if (storage) {
465
470
std::copy (storage->data (), storage->data () + count, newStorage->data ());
466
471
newStorage->Count .store (count, std::memory_order_relaxed);
@@ -477,7 +482,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
477
482
478
483
if (ReaderCount.load (std::memory_order_acquire) == 0 )
479
484
for (Storage *storage : FreeList)
480
- deallocate (storage );
485
+ storage-> deallocate ();
481
486
}
482
487
483
488
// / Read the contents of the array. The parameter `f` is called with
@@ -486,9 +491,9 @@ template <class ElemTy> struct ConcurrentReadableArray {
486
491
// / `read` was called. The pointer becomes invalid after `f` returns.
487
492
template <class F > auto read (F f) -> decltype(f(nullptr , 0 )) {
488
493
ReaderCount.fetch_add (1 , std::memory_order_acquire);
489
- auto *storage = Elements.load (std::memory_order_consume );
494
+ auto *storage = Elements.load (SWIFT_MEMORY_ORDER_CONSUME );
490
495
auto count = storage->Count .load (std::memory_order_acquire);
491
- auto *ptr = storage->data ();
496
+ const auto *ptr = storage->data ();
492
497
493
498
decltype (f (nullptr , 0 )) result = f (ptr, count);
494
499
@@ -499,7 +504,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
499
504
500
505
// / Get the current count. It's just a snapshot and may be obsolete immediately.
501
506
size_t count () {
502
- return read ([](ElemTy *ptr, size_t count) -> size_t {
507
+ return read ([](const ElemTy *ptr, size_t count) -> size_t {
503
508
return count;
504
509
});
505
510
}
0 commit comments