Commit cac6c6677319dba695cd15aa028b16e3748d8e78

Authored by Grzegorz Jabłoński
1 parent c0f6f5fa

Added template metaprogramming example for vector

examples11/06-template_metaprogramming/makefile 0 → 100644
  1 +all: testvector
  2 +
  3 +testvector: testvector.cpp vector.h
  4 + g++ -std=c++17 -g -Wall -pedantic $< -o $@
  5 +
  6 +.PHONY: clean
  7 +
  8 +clean:
  9 + -rm testvector
0 10 \ No newline at end of file
... ...
examples11/06-template_metaprogramming/testvector.cpp 0 → 100644
  1 +#include <iostream>
  2 +using namespace std;
  3 +#include "vector.h"
  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;
  30 +
  31 + int arg = 15;
  32 + a.push_back(arg);
  33 + b=a;
  34 + printvector (b);
  35 +
  36 +}
... ...
examples11/06-template_metaprogramming/vector.h 0 → 100644
  1 +#ifndef __VECTOR_H__
  2 +#define __VECTOR_H__
  3 +#include <cstring>
  4 +#include <limits>
  5 +#include <type_traits>
  6 +#include <tuple>
  7 +
  8 +template <class C> class vector {
  9 + C *data;
  10 + unsigned int size;
  11 + unsigned int cap;
  12 +
  13 +private:
  14 + static unsigned int round_up_to_power_of_2(unsigned w) {
  15 + const auto bits = std::numeric_limits<unsigned>::digits;
  16 + --w;
  17 + for (unsigned s = 1; s < bits; s *= 2)
  18 + w |= w >> s;
  19 + return ++w;
  20 + };
  21 +
  22 + void destroy_array(C *ptr, unsigned int s) {
  23 + for (unsigned j = 0; j < s; ++j)
  24 + (ptr + j)->~C();
  25 + free(ptr);
  26 + }
  27 +
  28 + void resize_before_push() {
  29 + if (size >= cap) {
  30 + if (cap > std::numeric_limits<decltype(size)>::max() / (2 * sizeof(C)))
  31 + 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;
  55 + }
  56 + }
  57 +
  58 +public:
  59 + class index_out_of_range {};
  60 + explicit vector(unsigned s) {
  61 +
  62 + cap = round_up_to_power_of_2(s);
  63 +
  64 + data = static_cast<C *>(std::aligned_alloc(alignof(C), cap * sizeof(C)));
  65 + if (!data)
  66 + throw bad_alloc();
  67 + size = s;
  68 +
  69 + unsigned i;
  70 + try {
  71 + for (i = 0; i < size; i++)
  72 + new (data + i) C();
  73 + } catch (...) {
  74 + destroy_array(data, i);
  75 + throw;
  76 + }
  77 + }
  78 +
  79 + ~vector() { destroy_array(data, size); }
  80 +
  81 + C &operator[](unsigned int pos) {
  82 + if (pos >= size)
  83 + throw index_out_of_range();
  84 + return data[pos];
  85 + }
  86 +
  87 + C operator[](unsigned int pos) const {
  88 + if (pos >= size)
  89 + throw index_out_of_range();
  90 + return data[pos];
  91 + }
  92 +
  93 + vector(const vector<C> &s) {
  94 + cap = s.cap;
  95 + data = static_cast<C *>(std::aligned_alloc(alignof(C), cap * sizeof(C)));
  96 + if (!data)
  97 + throw bad_alloc();
  98 + size = s.size;
  99 + unsigned i;
  100 + try {
  101 + for (i = 0; i < size; i++)
  102 + new (data + i) C(s.data[i]);
  103 + } catch (...) {
  104 + destroy_array(data, i);
  105 + throw;
  106 + }
  107 + }
  108 +
  109 + void swap(vector<C> &s) {
  110 + C *t1 = s.data;
  111 + unsigned int t2 = s.size;
  112 + unsigned int t3 = s.cap;
  113 + s.data = data;
  114 + s.size = size;
  115 + data = t1;
  116 + size = t2;
  117 + cap = t3;
  118 + }
  119 +
  120 + vector<C> &operator=(const vector<C> &s) {
  121 + if (this == &s)
  122 + return *this;
  123 + vector<C> n(s);
  124 + swap(n);
  125 + return *this;
  126 + }
  127 + friend ostream &operator<<(ostream &o, const vector<C> &v) {
  128 + o << '[';
  129 + for (unsigned i = 0; i < v.size; i++) {
  130 + o << v[i];
  131 + if (i != v.size - 1)
  132 + o << ',';
  133 + };
  134 + o << ']';
  135 + return o;
  136 + }
  137 +
  138 + template <class... Args> C &emplace_back(Args &&... args) {
  139 + // cout << "emplace_back" << endl;
  140 + resize_before_push();
  141 + new (data + size) C(std::forward<Args>(args)...);
  142 + return *(data + size++);
  143 + }
  144 +
  145 +private:
  146 + template <class T> C &push_back_single(T &&s) {
  147 + resize_before_push();
  148 + new (data + size) C(std::forward<T>(s));
  149 + return *(data + size++);
  150 + }
  151 +
  152 +public:
  153 +
  154 + C& push_back(C&& s)
  155 + {
  156 + return push_back_single(std::forward<C>(s));
  157 + }
  158 +
  159 + std::tuple<> push_back()
  160 + {
  161 + return std::tuple<>{};
  162 + }
  163 +
  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 + }
  167 +
  168 +};
  169 +#endif /* __VECTOR_H__ */
... ...