Commit 28f1425350fe9d903a463316f6863786a286a729
1 parent
cac6c667
Added template metaprogramming example to vector
Showing
2 changed files
with
64 additions
and
63 deletions
examples11/06-template_metaprogramming/testvector.cpp
... | ... | @@ -2,35 +2,26 @@ |
2 | 2 | using namespace std; |
3 | 3 | #include "vector.h" |
4 | 4 | |
5 | -template<class C> void printvector (vector<C> v) | |
6 | -{ | |
7 | - cout << v << endl; | |
8 | -} | |
9 | - | |
10 | -int | |
11 | -main () | |
12 | -{ | |
13 | - vector<int> a (10); | |
14 | - cout << a << endl; | |
15 | - a[0] = 15; | |
16 | - a[5] = 32; | |
17 | - vector<int> b(10); | |
18 | - a.push_back(4); | |
19 | - a.push_back(5); | |
20 | - a.push_back(6); | |
21 | - a.push_back(7); | |
22 | - a.push_back(8); | |
23 | - a.push_back(9); | |
24 | - a.push_back(10); | |
25 | - cout << a.push_back(11) << endl; | |
26 | - auto x = a.push_back(12,13,14); | |
27 | - cout << get<0>(x) << endl; | |
28 | - cout << get<0>(get<1>(x)) << endl; | |
29 | - cout << get<0>(get<1>(get<1>(x))) << endl; | |
5 | +template <class C> void printvector(vector<C> v) { cout << v << endl; } | |
30 | 6 | |
31 | - int arg = 15; | |
7 | +int main() { | |
8 | + vector<string> a(0); | |
9 | + vector<string> b(0); | |
10 | + a.push_back("1"); | |
11 | + a.push_back("2"); | |
12 | + a.push_back("3"); | |
13 | + a.push_back("4"); | |
14 | + a.push_back("5"); | |
15 | + a.push_back("6"); | |
16 | + a.push_back("7"); | |
17 | + a.reserve(11); // to avoid reallocation and reference invalidation | |
18 | + auto [x, y, z] = a.push_back("8", "9", "10"); | |
19 | + printvector(a); | |
20 | + x = "108"; | |
21 | + y = "109"; | |
22 | + z = "110"; | |
23 | + string arg = "11"; | |
32 | 24 | a.push_back(arg); |
33 | - b=a; | |
34 | - printvector (b); | |
35 | - | |
25 | + b = a; | |
26 | + printvector(b); | |
36 | 27 | } | ... | ... |
examples11/06-template_metaprogramming/vector.h
... | ... | @@ -2,8 +2,8 @@ |
2 | 2 | #define __VECTOR_H__ |
3 | 3 | #include <cstring> |
4 | 4 | #include <limits> |
5 | -#include <type_traits> | |
6 | 5 | #include <tuple> |
6 | +#include <type_traits> | |
7 | 7 | |
8 | 8 | template <class C> class vector { |
9 | 9 | C *data; |
... | ... | @@ -25,33 +25,37 @@ private: |
25 | 25 | free(ptr); |
26 | 26 | } |
27 | 27 | |
28 | + void reserve_internal(unsigned capacity) { | |
29 | + unsigned int newcap = capacity; | |
30 | + C *newdata; | |
31 | + if constexpr (!std::is_trivially_copyable<C>()) { | |
32 | + newdata = | |
33 | + static_cast<C *>(std::aligned_alloc(alignof(C), newcap * sizeof(C))); | |
34 | + if (!newdata) | |
35 | + throw bad_alloc(); | |
36 | + unsigned i; | |
37 | + try { | |
38 | + for (i = 0; i < size; i++) | |
39 | + new (newdata + i) C(std::move(data[i])); | |
40 | + } catch (...) { | |
41 | + destroy_array(newdata, i); | |
42 | + throw; | |
43 | + } | |
44 | + destroy_array(data, size); | |
45 | + } else { | |
46 | + newdata = static_cast<C *>(std::realloc(data, newcap * sizeof(C))); | |
47 | + if (!newdata) | |
48 | + throw bad_alloc(); | |
49 | + } | |
50 | + data = newdata; | |
51 | + cap = newcap; | |
52 | + } | |
53 | + | |
28 | 54 | void resize_before_push() { |
29 | 55 | if (size >= cap) { |
30 | 56 | if (cap > std::numeric_limits<decltype(size)>::max() / (2 * sizeof(C))) |
31 | 57 | throw bad_alloc(); |
32 | - unsigned int newcap = (cap == 0) ? 1 : 2 * cap; | |
33 | - C *newdata; | |
34 | - if constexpr (!std::is_trivially_copyable<C>()) { | |
35 | - newdata = static_cast<C *>( | |
36 | - std::aligned_alloc(alignof(C), newcap * sizeof(C))); | |
37 | - if (!newdata) | |
38 | - throw bad_alloc(); | |
39 | - unsigned i; | |
40 | - try { | |
41 | - for (i = 0; i < size; i++) | |
42 | - new (newdata + i) C(std::move(data[i])); | |
43 | - } catch (...) { | |
44 | - destroy_array(newdata, i); | |
45 | - throw; | |
46 | - } | |
47 | - destroy_array(data, size); | |
48 | - } else { | |
49 | - newdata = static_cast<C *>(std::realloc(data, newcap * sizeof(C))); | |
50 | - if (!newdata) | |
51 | - throw bad_alloc(); | |
52 | - } | |
53 | - data = newdata; | |
54 | - cap = newcap; | |
58 | + reserve_internal((cap == 0) ? 1 : 2 * cap); | |
55 | 59 | } |
56 | 60 | } |
57 | 61 | |
... | ... | @@ -150,20 +154,26 @@ private: |
150 | 154 | } |
151 | 155 | |
152 | 156 | public: |
153 | - | |
154 | - C& push_back(C&& s) | |
155 | - { | |
156 | - return push_back_single(std::forward<C>(s)); | |
157 | + void reserve(unsigned capacity) { | |
158 | + if (capacity > std::numeric_limits<decltype(size)>::max() / (2 * sizeof(C))) | |
159 | + throw bad_alloc(); | |
160 | + unsigned int cap_rounded_up = round_up_to_power_of_2(capacity); | |
161 | + reserve_internal(cap_rounded_up); | |
157 | 162 | } |
158 | 163 | |
159 | - std::tuple<> push_back() | |
160 | - { | |
161 | - return std::tuple<>{}; | |
164 | + std::tuple<C &> push_back(C &&s) { | |
165 | + C &r = push_back_single(std::forward<C>(s)); | |
166 | + return std::tuple<C &>(r); | |
162 | 167 | } |
163 | 168 | |
164 | - template <class T, class... Args> auto push_back(T&& a, Args &&... args) { | |
165 | - return std::tuple(push_back(std::forward<C>(a)),push_back(args...)); | |
166 | - } | |
169 | +private: | |
170 | + std::tuple<> push_back() { return std::tuple<>(); } | |
167 | 171 | |
172 | +public: | |
173 | + template <class T, class... Args> auto push_back(T &&a, Args &&... args) { | |
174 | + auto op1 = push_back(std::forward<C>(a)); | |
175 | + auto op2 = push_back(args...); | |
176 | + return std::tuple_cat(op1, op2); | |
177 | + } | |
168 | 178 | }; |
169 | 179 | #endif /* __VECTOR_H__ */ | ... | ... |