Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -----------------------------------------------------------------------
- vector.h
- -----------------------------------------------------------------------
- #pragma once
- #include <cassert>
- #include <memory>
- #include <cstdlib>
- #include <new>
- #include <utility>
- template <typename T>
- class RawMemory {
- public:
- RawMemory() = default;
- explicit RawMemory(size_t capacity) : buffer_(Allocate(capacity))
- , capacity_(capacity) {}
- ~RawMemory() {Deallocate(buffer_);}
- T* operator+(size_t offset) noexcept {assert(offset <= capacity_); return buffer_ + offset;}
- const T* operator+(size_t offset) const noexcept {return const_cast<RawMemory&>(*this) + offset;}
- const T& operator[](size_t index) const noexcept {return const_cast<RawMemory&>(*this)[index];}
- T& operator[](size_t index) noexcept {assert(index < capacity_); return buffer_[index];}
- void Swap(RawMemory& other) noexcept {std::swap(buffer_, other.buffer_); std::swap(capacity_, other.capacity_);}
- const T* GetAddress() const noexcept {return buffer_;}
- T* GetAddress() noexcept {return buffer_;}
- size_t Capacity() const {return capacity_;}
- private:
- T* buffer_ = nullptr;
- size_t capacity_ = 0;
- static T* Allocate(size_t n) {return n != 0 ? static_cast<T*>(operator new(n * sizeof(T))) : nullptr;}
- static void Deallocate(T* buf) noexcept {operator delete(buf);}
- };
- template <typename T>
- class Vector {
- public:
- Vector() = default;
- explicit Vector(size_t size) : data_(size)
- , size_(size) {std::uninitialized_value_construct_n(data_.GetAddress(), size);}
- Vector(const Vector& other) : data_(other.size_)
- , size_(other.size_) {std::uninitialized_copy_n(other.data_.GetAddress(), size_, data_.GetAddress());}
- ~Vector() {std::destroy_n(data_.GetAddress(), size_);}
- size_t Size() const noexcept {return size_;}
- size_t Capacity() const noexcept {return data_.Capacity();}
- void Reserve(size_t new_capacity) {
- if (new_capacity <= data_.Capacity()) {
- return;
- }
- RawMemory<T> new_data(new_capacity);
- if constexpr (std::is_nothrow_move_constructible_v<T> || !std::is_copy_constructible_v<T>) {
- std::uninitialized_move_n(data_.GetAddress(), size_, new_data.GetAddress());
- } else {
- std::uninitialized_copy_n(data_.GetAddress(), size_, new_data.GetAddress());
- }
- std::destroy_n(data_.GetAddress(), size_);
- data_.Swap(new_data);
- }
- const T& operator[](size_t index) const noexcept {return const_cast<Vector&>(*this)[index];}
- T& operator[](size_t index) noexcept {assert(index < size_); return data_[index];}
- private:
- RawMemory<T> data_;
- size_t size_ = 0;
- };
- -----------------------------------------------------------------------
- main.cpp
- -----------------------------------------------------------------------
- #include "vector.h"
- #include <stdexcept>
- namespace {
- struct Obj {
- Obj() {
- if (default_construction_throw_countdown > 0) {
- if (--default_construction_throw_countdown == 0) {
- throw std::runtime_error("Oops");
- }
- }
- ++num_default_constructed;
- }
- Obj(const Obj& other) {
- if (other.throw_on_copy) {
- throw std::runtime_error("Oops");
- }
- ++num_copied;
- }
- Obj(Obj&& /*other*/) noexcept {++num_moved;}
- Obj& operator=(const Obj& other) = default;
- Obj& operator=(Obj&& other) = default;
- ~Obj() {++num_destroyed;}
- static int GetAliveObjectCount() {return num_default_constructed + num_copied + num_moved - num_destroyed;}
- static void ResetCounters() {
- default_construction_throw_countdown = 0;
- num_default_constructed = 0;
- num_copied = 0;
- num_moved = 0;
- num_destroyed = 0;
- }
- bool throw_on_copy = false;
- static inline int default_construction_throw_countdown = 0;
- static inline int num_default_constructed = 0;
- static inline int num_copied = 0;
- static inline int num_moved = 0;
- static inline int num_destroyed = 0;
- };
- }//end namespace
- void Test1() {
- Obj::ResetCounters();
- const size_t SIZE = 100500;
- const size_t INDEX = 10;
- const int MAGIC = 42;
- {
- Vector<int> v;
- assert(v.Capacity() == 0);
- assert(v.Size() == 0);
- v.Reserve(SIZE);
- assert(v.Capacity() == SIZE);
- assert(v.Size() == 0);
- }
- {
- Vector<int> v(SIZE);
- const auto& cv(v);
- assert(v.Capacity() == SIZE);
- assert(v.Size() == SIZE);
- assert(v[0] == 0);
- assert(&v[0] == &cv[0]);
- v[INDEX] = MAGIC;
- assert(v[INDEX] == MAGIC);
- assert(&v[100] - &v[0] == 100);
- v.Reserve(SIZE * 2);
- assert(v.Size() == SIZE);
- assert(v.Capacity() == SIZE * 2);
- assert(v[INDEX] == MAGIC);
- }
- {
- Vector<int> v(SIZE);
- v[INDEX] = MAGIC;
- const auto v_copy(v);
- assert(&v[INDEX] != &v_copy[INDEX]);
- assert(v[INDEX] == v_copy[INDEX]);
- }
- {
- Vector<Obj> v;
- v.Reserve(SIZE);
- assert(Obj::GetAliveObjectCount() == 0);
- }
- {
- Vector<Obj> v(SIZE);
- assert(Obj::GetAliveObjectCount() == SIZE);
- const int old_copy_count = Obj::num_copied;
- const int old_move_count = Obj::num_moved;
- v.Reserve(SIZE * 2);
- assert(Obj::GetAliveObjectCount() == SIZE);
- assert(Obj::num_copied == old_copy_count);
- assert(Obj::num_moved == old_move_count + static_cast<int>(SIZE));
- }
- assert(Obj::GetAliveObjectCount() == 0);
- }
- void Test2() {
- const size_t SIZE = 100;
- Obj::ResetCounters();
- {
- Obj::default_construction_throw_countdown = SIZE / 2;
- try {
- Vector<Obj> v(SIZE);
- assert(false && "Exception is expected");
- } catch (const std::runtime_error&) {
- } catch (...) {
- assert(false && "Unexpected exception");
- }
- assert(Obj::num_default_constructed == SIZE / 2 - 1);
- assert(Obj::GetAliveObjectCount() == 0);
- }
- Obj::ResetCounters();
- {
- Vector<Obj> v(SIZE);
- try {
- v[SIZE / 2].throw_on_copy = true;
- Vector<Obj> v_copy(v);
- assert(false && "Exception is expected");
- } catch (const std::runtime_error&) {
- assert(Obj::num_copied == SIZE / 2);
- } catch (...) {
- assert(false && "Unexpected exception");
- }
- assert(Obj::GetAliveObjectCount() == SIZE);
- }
- Obj::ResetCounters();
- {
- Vector<Obj> v(SIZE);
- try {
- v[SIZE - 1].throw_on_copy = true;
- v.Reserve(SIZE * 2);
- } catch (...) {
- assert(false && "Unexpected exception");
- }
- assert(v.Capacity() == SIZE * 2);
- assert(v.Size() == SIZE);
- assert(Obj::GetAliveObjectCount() == SIZE);
- }
- }
- int main() {
- Test1();
- Test2();
- }
Advertisement
Add Comment
Please, Sign In to add comment