Incorporate changes from Dasynq upstream.
[oweals/dinit.git] / src / dasynq / dasynq-svec.h
1 #ifndef DASYNQ_SVEC_H_INCLUDED
2 #define DASYNQ_SVEC_H_INCLUDED
3
4 #include <cstddef>
5 #include <cstdlib>
6 #include <utility>
7 #include <new>
8
9 // Vector with possibility to shrink capacity arbitrarily
10
11 namespace dasynq {
12
13 template <typename T>
14 class svector
15 {
16     private:
17     T * array;
18     size_t size_v;
19     size_t capacity_v;
20
21     void check_capacity()
22     {
23         if (size_v == capacity_v) {
24             // double capacity now:
25             if (capacity_v == 0) capacity_v = 1;
26             T * new_array = (T *) std::malloc(capacity_v * 2 * sizeof(T));
27             if (new_array == nullptr) {
28                 throw std::bad_alloc();  
29             }
30             for (size_t i = 0; i < size_v; i++) {
31                 new (&new_array[i]) T(std::move(array[i]));
32                 array[i].T::~T();
33             }
34             std::free(array);
35             array = new_array;
36             capacity_v *= 2;
37         }
38     }
39
40     public:
41     using size_type = size_t;
42     
43     svector() : array(nullptr), size_v(0), capacity_v(0)
44     {
45     
46     }
47     
48     svector(const svector<T> &other)
49     {
50         capacity_v = other.size_v;
51         size_v = other.size_v;
52         array = (T *) std::malloc(capacity_v * sizeof(T));
53         if (array == nullptr) {
54             throw std::bad_alloc();
55         }
56         for (size_t i = 0; i < size_v; i++) {
57             new (&array[i]) T(other[i]);
58         }
59     }
60     
61     ~svector()
62     {
63         for (size_t i = 0; i < size_v; i++) {
64             array[i].T::~T();
65         }
66         std::free(array);
67     }
68
69     void push_back(const T &t)
70     {
71         check_capacity();
72         new (&array[size_v]) T(t);
73         size_v++;
74     }
75     
76     void push_back(T &&t)
77     {
78         check_capacity();        
79         new (&array[size_v]) T(t);
80         size_v++;
81     }
82     
83     template <typename ...U>
84     void emplace_back(U... args)
85     {
86         check_capacity();
87         new (&array[size_v]) T(args...);
88         size_v++;
89     }
90     
91     void pop_back()
92     {
93         size_v--;
94     }
95     
96     T &operator[](size_t index)
97     {
98         return array[index];
99     }
100     
101     const T &operator[](size_t index) const
102     {
103         return array[index];
104     }
105     
106     size_t size() const
107     {
108         return size_v;
109     }
110     
111     size_t capacity() const
112     {
113         return capacity_v;
114     }
115     
116     bool empty() const
117     {
118         return size_v == 0;
119     }
120     
121     void reserve(size_t amount)
122     {
123         if (capacity_v < amount) {
124             T * new_array = (T *) std::malloc(amount * sizeof(T));
125             if (new_array == nullptr) {
126                 throw std::bad_alloc();
127             }
128             for (size_t i = 0; i < size_v; i++) {
129                 new (&new_array[i]) T(std::move(array[i]));
130                 array[i].T::~T();
131             }
132             std::free(array);
133             array = new_array;
134             capacity_v = amount;
135         }
136     }
137     
138     void shrink_to(size_t amount)
139     {
140         if (capacity_v > amount) {
141             T * new_array = (T *) std::malloc(amount * sizeof(T));
142             if (new_array == nullptr) {
143                 return;
144             }
145             for (size_t i = 0; i < size_v; i++) {
146                 new (&new_array[i]) T(std::move(array[i]));
147                 array[i].T::~T();
148             }
149             std::free(array);
150             array = new_array;
151             capacity_v = amount;            
152         }
153     }
154     
155     T &back()
156     {
157         return array[size_v - 1];
158     }
159
160     T* begin()
161     {
162         return array;
163     }
164     
165     const T *begin() const
166     {
167         return array;
168     }
169
170     T* end()
171     {
172         return array + size_v;
173     }
174     
175     const T *end() const
176     {
177         return array + size_v;
178     }
179 };
180
181
182 } // namespace
183
184 #endif