#ifndef INCLUDED_TRNX_VECTOR_IMPL #define INCLUDED_TRNX_VECTOR_IMPL #include #include #include #include namespace trnx { namespace detail { // This union is not meant to be shown/completely understood from the students. // // They should know that `uninitialized` means "enough storage for a `T` // instance, and that they can manually control the lifetime of that instance // through the `.construct` and `.destroy` member functions. // // It is undefined behavior to: // * Call `construct` on an already-initialized instance. // * Call `destroy` on a non-initialized instance. // * Access the reference returned by `get` on a non-initialized instance. // template union uninitialized { private: T d_datum; public: using inner_type = T; uninitialized() { } ~uninitialized() { } template void construct(Ts&&... xs) { new (&d_datum) T(std::forward(xs)...); } void destroy() { d_datum.~T(); } T& get() { return d_datum; } const T& get() const { return d_datum; } }; // This class is not meant to be shown/completely understood from the students. // // It basically unwraps `uninitialized` upon dereference, behaving as any // other normal random access iterator, transparently to the user. // template class iter_impl { private: T* d_ptr; using inner_type = typename T::inner_type; public: using difference_type = std::ptrdiff_t; using value_type = inner_type; using pointer = inner_type*; using reference = inner_type&; using iterator_category = std::random_access_iterator_tag; iter_impl() : d_ptr(nullptr) { } iter_impl(T* rhs) : d_ptr(rhs) { } iter_impl(const iter_impl& rhs) : d_ptr(rhs.d_ptr) { } iter_impl& operator=(const iter_impl &rhs) { d_ptr = rhs.d_ptr; return *this; } iter_impl& operator+=(difference_type rhs) { d_ptr += rhs; return *this; } iter_impl& operator-=(difference_type rhs) { d_ptr -= rhs; return *this; } inner_type& operator*() const { return d_ptr->get(); } inner_type* operator->() const { return &d_ptr->get(); } inner_type& operator[](difference_type rhs) const { return d_ptr[rhs]; } iter_impl& operator++() { ++d_ptr; return *this; } iter_impl& operator--() { --d_ptr; return *this; } iter_impl operator++(int) { iter_impl tmp(*this); ++d_ptr; return tmp; } iter_impl operator--(int) { iter_impl tmp(*this); --d_ptr; return tmp; } difference_type operator-(const iter_impl& rhs) const { return iter_impl(d_ptr - rhs.ptr); } iter_impl operator+(difference_type rhs) const { return iter_impl(d_ptr + rhs); } iter_impl operator-(difference_type rhs) const { return iter_impl(d_ptr - rhs); } friend iter_impl operator+(difference_type lhs, const iter_impl& rhs) { return iter_impl(lhs + rhs.d_ptr); } friend iter_impl operator-(difference_type lhs, const iter_impl& rhs) { return iter_impl(lhs - rhs.d_ptr); } bool operator==(const iter_impl& rhs) const { return d_ptr == rhs.d_ptr; } bool operator!=(const iter_impl& rhs) const { return d_ptr != rhs.d_ptr; } bool operator>(const iter_impl& rhs) const { return d_ptr > rhs.d_ptr; } bool operator<(const iter_impl& rhs) const { return d_ptr < rhs.d_ptr; } bool operator>=(const iter_impl& rhs) const { return d_ptr >= rhs.d_ptr; } bool operator<=(const iter_impl& rhs) const { return d_ptr <= rhs.d_ptr; } }; } // close namespace detail } // close namespace trnx #endif