Created
July 6, 2019 07:09
-
-
Save npetrenko/7d19ebd46a921dc91438b24d8725b08a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <type_traits> | |
#include <cstddef> | |
template <class ValueType, bool is_const> | |
class ContiguousContainerView { | |
using CQualValueType = std::conditional_t<is_const, const ValueType, ValueType>; | |
public: | |
using DerefT = CQualValueType&; | |
using PointerT = CQualValueType*; | |
// ContainerT is either const T& or T& | |
template <class ContainerT> | |
ContiguousContainerView(ContainerT&& container, size_t begin_ix, size_t end_ix) { | |
char* ptr = GetImplbasePtr(); | |
implbase_ptr_ = new (ptr) Impl<ContainerT>(&container, begin_ix, end_ix); | |
} | |
template <class ContainerT> | |
ContiguousContainerView(ContainerT&& container) : | |
ContiguousContainerView(std::forward<ContainerT>(container), 0, container.size()) { | |
} | |
ContiguousContainerView(const ContiguousContainerView& other) { | |
std::copy(other.data_, other.data_ + sizeof(data_), data_); | |
implbase_ptr_ = GetImplbasePtr(); | |
} | |
ContiguousContainerView(ContiguousContainerView&&) = delete; | |
ContiguousContainerView& operator=(const ContiguousContainerView& other) { | |
std::copy(other.data_, other.data_ + sizeof(data_), data_); | |
implbase_ptr_ = GetImplbasePtr(); | |
} | |
ContiguousContainerView& operator=(ContiguousContainerView&&) = delete; | |
PointerT begin() const { | |
return implbase_ptr_->begin(); | |
} | |
PointerT end() const { | |
return implbase_ptr_->end(); | |
} | |
DerefT operator[](size_t ix) const { | |
return *(begin() + ix); | |
} | |
size_t size() const { | |
return implbase_ptr_->size(); | |
} | |
protected: | |
char* GetImplbasePtr() { | |
char* ptr = data_; | |
ptr += ((size_t)ptr) % alignof(ImplBase); | |
return ptr; | |
} | |
struct ImplBase { | |
using CQualT = std::conditional_t<is_const, const void, void>; | |
ImplBase(CQualT* ptr, size_t bi, size_t ei) | |
: container_ptr(ptr), begin_ix(bi), end_ix(ei) { | |
} | |
CQualT* container_ptr; | |
size_t begin_ix, end_ix; | |
virtual PointerT begin() const = 0; | |
virtual PointerT end() const = 0; | |
virtual size_t size() const = 0; | |
}; | |
template <class ContainerT> | |
struct Impl final : public ImplBase { | |
using PureContainerT = std::remove_reference_t<ContainerT>; | |
using ImplBase::ImplBase; | |
PointerT begin() const override { | |
return &*(this->begin_ix + static_cast<PureContainerT*>(this->container_ptr)->begin()); | |
} | |
PointerT end() const override { | |
return &*(this->end_ix + static_cast<PureContainerT*>(this->container_ptr)->begin()); | |
} | |
size_t size() const override { | |
return static_cast<PureContainerT*>(this->container_ptr)->size(); | |
} | |
}; | |
// it is an overkill, actually. | |
char data_[2*sizeof(ImplBase)]; | |
ImplBase* implbase_ptr_; | |
}; | |
// two deduction guides | |
template <class ContainerT> | |
ContiguousContainerView(ContainerT&&) | |
-> ContiguousContainerView<typename std::remove_reference_t<ContainerT>::value_type, std::is_const_v<std::remove_reference_t<ContainerT>>>; | |
template <class ContainerT> | |
ContiguousContainerView(ContainerT&&, size_t, size_t) | |
-> ContiguousContainerView<typename std::remove_reference_t<ContainerT>::value_type, std::is_const_v<std::remove_reference_t<ContainerT>>>; | |
int main () { | |
std::array vec{1,2,3,4,5}; | |
ContiguousContainerView view(vec); | |
static_assert(std::is_same_v<decltype(view), ContiguousContainerView<int, false>>, "Fail"); | |
// ok, is a non-const view | |
view[0] = 0; | |
const std::array const_vec{0,2,3,4,5}; | |
ContiguousContainerView const_view(const_vec); | |
static_assert(std::is_same_v<decltype(const_view), ContiguousContainerView<int, true>>, "Fail"); | |
// compilation error -- deduced to be a const view | |
// const_view[0] = 0; | |
return view[0] + const_view[0]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment