Skip to content

Instantly share code, notes, and snippets.

@npetrenko
Created July 6, 2019 07:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save npetrenko/7d19ebd46a921dc91438b24d8725b08a to your computer and use it in GitHub Desktop.
Save npetrenko/7d19ebd46a921dc91438b24d8725b08a to your computer and use it in GitHub Desktop.
#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