00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef __VECTOR_HH
00019 # define __VECTOR_HH
00020
00021 # include <atomic>
00022 # include <cassert>
00023 # include "simple_stack.hh"
00024
00025 namespace lockfree {
00026
00027 template <typename T, size_t SEG_SIZE = 1024u,
00028 typename Alloc = std::allocator<T> >
00029 struct vector {
00030 private:
00031 struct seg_table {
00032 size_t n_segments;
00033 T** segments;
00034 };
00035
00036 typedef typename Alloc::template rebind<seg_table>::other st_alloc_t;
00037 typedef typename Alloc::template rebind<T*>::other pt_alloc_t;
00038
00039 Alloc alloc;
00040 st_alloc_t st_alloc;
00041 pt_alloc_t pt_alloc;
00042 std::atomic<seg_table*> table;
00043 simple_stack<seg_table*> free;
00044 T default_value;
00045
00046
00047
00048
00049 void set_size(size_t size) {
00050 size_t isize = (size+SEG_SIZE-1)/SEG_SIZE;
00051 seg_table* t = table.load();
00052 if (t->n_segments >= isize) {
00053 return ;
00054 }
00055 seg_table* newt = st_alloc.allocate(1);
00056 newt->n_segments = isize;
00057 newt->segments = pt_alloc.allocate(isize);
00058 size_t delete_from = isize;
00059 do {
00060 t = table.load();
00061 if (t->n_segments >= isize) {
00062 for (size_t i = delete_from; i < isize; ++i) {
00063 for (size_t j = 0; j < SEG_SIZE; ++j)
00064 alloc.destroy(newt->segments[i] + j);
00065 alloc.deallocate(newt->segments[i], SEG_SIZE);
00066 }
00067 pt_alloc.deallocate(newt->segments, isize);
00068 st_alloc.deallocate(newt, 1);
00069 return ;
00070 }
00071 size_t i = 0;
00072 for (; (i < t->n_segments); ++i) {
00073 if (i >= delete_from) {
00074 for (size_t j = 0; j < SEG_SIZE; ++j)
00075 alloc.destroy(newt->segments[i] + j);
00076 alloc.deallocate(newt->segments[i], SEG_SIZE);
00077 }
00078 newt->segments[i] = t->segments[i];
00079 }
00080 size_t delete_from_next = i;
00081 for (; (i < delete_from); ++i) {
00082 newt->segments[i] = alloc.allocate(SEG_SIZE);
00083 for (size_t j = 0; j < SEG_SIZE; ++j)
00084 alloc.construct(newt->segments[i] + j, default_value);
00085 }
00086 delete_from = delete_from_next;
00087 } while (!table.compare_exchange_strong(t, newt));
00088 free.push((seg_table*)(t));
00089 }
00090
00091 public:
00092 vector(T default_value = T(), Alloc alloc = Alloc())
00093 : alloc(alloc), st_alloc(alloc), pt_alloc(alloc),
00094 table(st_alloc.allocate(1)), default_value(default_value) {
00095 table.load()->n_segments = 0;
00096 }
00097
00098 T& operator[](size_t n) {
00099 seg_table* t = table.load();
00100 assert(n < (SEG_SIZE*t->n_segments));
00101 return t->segments[n/SEG_SIZE][n%SEG_SIZE];
00102 }
00103
00104 const T& operator[](size_t n) const {
00105 seg_table* t = table.load();
00106 assert(n < (SEG_SIZE*t->n_segments));
00107 return t->segments[n/SEG_SIZE][n%SEG_SIZE];
00108 }
00109
00110 void resize(size_t size) {
00111 set_size(size);
00112 }
00113
00114 void collect() {
00115 while (true) {
00116 typename simple_stack<seg_table*>::wrapped w = free.pop();
00117 if (w.end())
00118 break ;
00119 seg_table *t = *w;
00120 if (t->n_segments > 0)
00121 pt_alloc.deallocate(t->segments, t->n_segments);
00122 st_alloc.deallocate(t, 1);
00123 }
00124 }
00125
00126 size_t size() const {
00127 return table.load()->n_segments * SEG_SIZE;
00128 }
00129
00130 ~vector() {
00131 collect();
00132 seg_table* t = table.load();
00133 for (size_t i = 0; i < t->n_segments; ++i) {
00134 for (size_t j = 0; j < SEG_SIZE; ++j) {
00135 alloc.destroy(t->segments[i] + j);
00136 }
00137 alloc.deallocate(t->segments[i], SEG_SIZE);
00138 }
00139 if (t->n_segments > 0)
00140 pt_alloc.deallocate(t->segments, t->n_segments);
00141 st_alloc.deallocate(t, 1);
00142 }
00143 };
00144 }
00145
00146 #endif