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 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__ */
... ...