Commit 28f1425350fe9d903a463316f6863786a286a729

Authored by Grzegorz Jabłoński
1 parent cac6c667

Added template metaprogramming example to vector

examples11/06-template_metaprogramming/testvector.cpp
@@ -2,35 +2,26 @@ @@ -2,35 +2,26 @@
2 using namespace std; 2 using namespace std;
3 #include "vector.h" 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 a.push_back(arg); 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,8 +2,8 @@
2 #define __VECTOR_H__ 2 #define __VECTOR_H__
3 #include <cstring> 3 #include <cstring>
4 #include <limits> 4 #include <limits>
5 -#include <type_traits>  
6 #include <tuple> 5 #include <tuple>
  6 +#include <type_traits>
7 7
8 template <class C> class vector { 8 template <class C> class vector {
9 C *data; 9 C *data;
@@ -25,33 +25,37 @@ private: @@ -25,33 +25,37 @@ private:
25 free(ptr); 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 void resize_before_push() { 54 void resize_before_push() {
29 if (size >= cap) { 55 if (size >= cap) {
30 if (cap > std::numeric_limits<decltype(size)>::max() / (2 * sizeof(C))) 56 if (cap > std::numeric_limits<decltype(size)>::max() / (2 * sizeof(C)))
31 throw bad_alloc(); 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,20 +154,26 @@ private:
150 } 154 }
151 155
152 public: 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 #endif /* __VECTOR_H__ */ 179 #endif /* __VECTOR_H__ */