vector.h 3.27 KB
#ifndef __VECTOR_H__
#define __VECTOR_H__
#include <cstring>
#include <limits>
#include <type_traits>

template <class C> class vector {
  C *data;
  unsigned int size;
  unsigned int cap;

private:
  static unsigned int round_up_to_power_of_2(unsigned w) {
    const auto bits = std::numeric_limits<unsigned>::digits;
    --w;
    for (unsigned s = 1; s < bits; s *= 2)
      w |= w >> s;
    return ++w;
  };

public:
  class index_out_of_range {};
  explicit vector(unsigned s) {

    cap = round_up_to_power_of_2(s);

    data = static_cast<C *>(std::aligned_alloc(alignof(C), cap * sizeof(C)));
    if (!data)
      throw bad_alloc();
    size = s;

    unsigned i;
    try {
      for (i = 0; i < size; i++)
        new (data + i) C();
    } catch (...) {
      for (unsigned j = 0; j < i; ++j)
        (data + j)->~C();
      free(data);
      throw;
    }
  }

  ~vector() {
    for (unsigned j = 0; j < size; ++j)
      (data + j)->~C();
    free(data);
  }
  C &operator[](unsigned int pos) {
    if (pos >= size)
      throw index_out_of_range();
    return data[pos];
  }
  C operator[](unsigned int pos) const {
    if (pos >= size)
      throw index_out_of_range();
    return data[pos];
  }

  vector(const vector<C> &s) {
    cap = s.cap;
    data = static_cast<C *>(std::aligned_alloc(alignof(C), cap * sizeof(C)));
    if (!data)
      throw bad_alloc();
    size = s.size;
    unsigned i;
    try {
      for (i = 0; i < size; i++)
        new (data + i) C(s.data[i]);
    } catch (...) {
      for (unsigned j = 0; j < i; ++j)
        (data + j)->~C();
      free(data);
      throw;
    }
  }

  void swap(vector<C> &s) {
    C *t1 = s.data;
    unsigned int t2 = s.size;
    unsigned int t3 = s.cap;
    s.data = data;
    s.size = size;
    data = t1;
    size = t2;
    cap = t3;
  }

  vector<C> &operator=(const vector<C> &s) {
    if (this == &s)
      return *this;
    vector<C> n(s);
    swap(n);
    return *this;
  }
  friend ostream &operator<<(ostream &o, const vector<C> &v) {
    o << '[';
    for (unsigned i = 0; i < v.size; i++) {
      o << v[i];
      if (i != v.size - 1)
        o << ',';
    };
    o << ']';
    return o;
  }

  void push_back(const C &s) {
    if (size < cap) {
      new (data + size) C(s);
      ++size;
    } else {
      if (cap > std::numeric_limits<decltype(size)>::max() / (2*sizeof(C)))
        throw bad_alloc();
      unsigned int newcap = (cap == 0) ? 1 : 2 * cap;
      C *newdata;
      if constexpr (!std::is_trivially_copyable<C>()) {
        newdata = static_cast<C *>(
            std::aligned_alloc(alignof(C), newcap * sizeof(C)));
        if (!newdata)
          throw bad_alloc();
        unsigned i;
        try {
          for (i = 0; i < size; i++)
            new (newdata + i) C(std::move(data[i]));
        } catch (...) {
          for (unsigned j = 0; j < i; ++j)
            (newdata + j)->~C();
          free(newdata);
          throw;
        }
        new (newdata + size) C(s);
        for (unsigned j = 0; j < size; ++j)
          (data + j)->~C();
        free(data);
      } else {
        newdata = static_cast<C *>(std::realloc(data, newcap * sizeof(C)));
        if (!newdata)
          throw bad_alloc();
        new (newdata + size) C(s);
      }

      ++size;
      data = newdata;
      cap = newcap;
    }
  }
};
#endif /* __VECTOR_H__ */