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