Files
test/cpp/cpp11/trnx_vector_impl.h
2021-03-25 08:17:48 -04:00

107 lines
3.5 KiB
C++

#ifndef INCLUDED_TRNX_VECTOR_IMPL
#define INCLUDED_TRNX_VECTOR_IMPL
#include <cstddef>
#include <exception>
#include <iterator>
#include <type_traits>
namespace trnx {
namespace detail {
// This union is not meant to be shown/completely understood from the students.
//
// They should know that `uninitialized<T>` 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 <typename T>
union uninitialized
{
private:
T d_datum;
public:
using inner_type = T;
uninitialized() { }
~uninitialized() { }
template <typename... Ts>
void construct(Ts&&... xs)
{
new (&d_datum) T(std::forward<Ts>(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<T>` upon dereference, behaving as any
// other normal random access iterator, transparently to the user.
//
template <typename T>
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