/* * This file is part of the DXX-Rebirth project . * It is copyright by its individual contributors, as recorded in the * project's Git history. See COPYING.txt at the top level for license * terms and a link to the Git history. */ #pragma once #include #include #include "fwd-valptridx.h" #include "compiler-array.h" #include "compiler-static_assert.h" #include "compiler-type_traits.h" #include "pack.h" #include "poison.h" #ifdef DXX_CONSTANT_TRUE #define DXX_VALPTRIDX_STATIC_CHECK(SUCCESS_CONDITION,FAILURE_FUNCTION,FAILURE_STRING) \ ( \ static_cast(DXX_CONSTANT_TRUE(!(SUCCESS_CONDITION)) && \ (DXX_ALWAYS_ERROR_FUNCTION(FAILURE_FUNCTION, FAILURE_STRING), 0) \ ) \ ) #ifdef DXX_HAVE_ATTRIBUTE_WARNING /* This causes many warnings because some conversions are not checked for * safety. Eliminating the warnings by changing the call sites to check first * would be a useful improvement. */ //#define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT __attribute__((__warning__("call not eliminated"))) #endif #else #define DXX_VALPTRIDX_STATIC_CHECK(E,F,S) \ ((void)0) #endif #ifdef DXX_HAVE_CXX11_REF_QUALIFIER #define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE & #else #define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE #endif #define DXX_VALPTRIDX_CHECK(SUCCESS_CONDITION,EXCEPTION,FAILURE_STRING,...) \ ( \ static_cast(DXX_VALPTRIDX_STATIC_CHECK((SUCCESS_CONDITION), dxx_trap_##EXCEPTION, FAILURE_STRING), \ (SUCCESS_CONDITION) || (EXCEPTION::report(__VA_ARGS__), 0) \ ) \ ) #ifndef DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT #define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT #endif template class valptridx

::index_mismatch_exception : public std::logic_error { DXX_INHERIT_CONSTRUCTORS(index_mismatch_exception, logic_error); public: __attribute_cold __attribute_noreturn DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT static void report(const array_managed_type &, index_type, const_pointer_type, const_pointer_type); }; template class valptridx

::index_range_exception : public std::out_of_range { DXX_INHERIT_CONSTRUCTORS(index_range_exception, out_of_range); public: __attribute_cold __attribute_noreturn DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT static void report(const array_managed_type &, long); }; template class valptridx

::null_pointer_exception : public std::logic_error { DXX_INHERIT_CONSTRUCTORS(null_pointer_exception, logic_error); public: __attribute_cold __attribute_noreturn DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT static void report(); __attribute_cold __attribute_noreturn DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT static void report(const array_managed_type &); }; template void valptridx::check_index_match(const managed_type &r, index_type i, const array_managed_type &a) { const auto pi = &a[i]; DXX_VALPTRIDX_CHECK(pi == &r, index_mismatch_exception, "pointer/index mismatch", a, i, pi, &r); } template typename valptridx::index_type valptridx::check_index_range(index_type i, const array_managed_type &a) { const std::size_t ss = i; DXX_VALPTRIDX_CHECK(ss < a.size(), index_range_exception, "invalid index used in array subscript", a, ss); return i; } template void valptridx::check_null_pointer_conversion(const_pointer_type p) { DXX_VALPTRIDX_CHECK(p, null_pointer_exception, "NULL pointer converted"); } template void valptridx::check_null_pointer(const_pointer_type p, const array_managed_type &a) { DXX_VALPTRIDX_CHECK(p, null_pointer_exception, "NULL pointer used", a); } template void valptridx::check_implicit_index_range_ref(const managed_type &r, const array_managed_type &a) { check_explicit_index_range_ref(r, static_cast(&r) - static_cast(&a.front()), a); } template void valptridx::check_explicit_index_range_ref(const managed_type &r, std::size_t i, const array_managed_type &a) { check_index_match(r, i, a); check_index_range(i, a); } template class valptridx::partial_policy::require_valid { public: static constexpr tt::false_type allow_nullptr{}; static constexpr tt::false_type check_allowed_invalid_index(index_type) { return {}; } }; template class valptridx::partial_policy::allow_invalid { public: static constexpr tt::true_type allow_nullptr{}; static constexpr bool check_allowed_invalid_index(index_type i) { return i == static_cast(~0); } }; template constexpr tt::false_type valptridx::partial_policy::require_valid::allow_nullptr; template constexpr tt::true_type valptridx::partial_policy::allow_invalid::allow_nullptr; template class valptridx::partial_policy::const_policy { protected: template using apply_cv_qualifier = const T; }; template class valptridx::partial_policy::mutable_policy { protected: template using apply_cv_qualifier = T; }; template template class valptridx::partial_policy::apply_cv_policy : policy { template using apply_cv_qualifier = typename policy::template apply_cv_qualifier; public: using array_managed_type = apply_cv_qualifier::array_managed_type>; using pointer_type = apply_cv_qualifier *; using reference_type = apply_cv_qualifier &; }; template class valptridx::vc : public partial_policy::require_valid, public partial_policy::template apply_cv_policy { }; template class valptridx::vm : public partial_policy::require_valid, public partial_policy::template apply_cv_policy { }; template class valptridx::ic : public partial_policy::allow_invalid, public partial_policy::template apply_cv_policy { }; template class valptridx::im : public partial_policy::allow_invalid, public partial_policy::template apply_cv_policy { }; template template class valptridx::basic_idx : public policy { using containing_type = valptridx; public: using policy::allow_nullptr; using policy::check_allowed_invalid_index; using index_type = typename containing_type::index_type; using integral_type = typename containing_type::integral_type; using typename policy::array_managed_type; basic_idx() = delete; basic_idx(const basic_idx &) = default; basic_idx(basic_idx &&) = default; basic_idx &operator=(const basic_idx &) = default; basic_idx &operator=(basic_idx &&) = default; index_type get_unchecked_index() const { return m_idx; } template basic_idx(const basic_idx &rhs, array_managed_type &a = get_array()) : m_idx(rhs.get_unchecked_index()) { if (!(allow_nullptr || !rhs.allow_nullptr)) check_index_range(m_idx, a); } template basic_idx(basic_idx &&rhs) : m_idx(rhs.get_unchecked_index()) { /* Prevent move from allow_invalid into require_valid. The * right hand side must be saved and checked for validity before * being used to initialize a require_valid type. */ static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid"); } basic_idx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated m_idx(check_allowed_invalid_index(i) ? i : check_index_range(i, a)) { } template basic_idx(const magic_constant &) : m_idx(v) { static_assert(allow_nullptr || static_cast(v) < array_size, "invalid magic index not allowed for this policy"); } template bool operator==(const basic_idx &rhs) const { return m_idx == rhs.get_unchecked_index(); } bool operator==(const index_type &i) const { return m_idx == i; } template bool operator==(const magic_constant &) const { static_assert(allow_nullptr || static_cast(v) < array_size, "invalid magic index not allowed for this policy"); return m_idx == v; } template bool operator!=(const R &rhs) const { return !(*this == rhs); } operator index_type() const { return m_idx; } protected: index_type m_idx; }; template template class valptridx::basic_ptr : public policy { using containing_type = valptridx; public: using policy::allow_nullptr; using policy::check_allowed_invalid_index; using const_pointer_type = typename containing_type::const_pointer_type; using mutable_pointer_type = typename containing_type::mutable_pointer_type; using typename policy::array_managed_type; using typename policy::pointer_type; using typename policy::reference_type; basic_ptr() = delete; /* Override template matches to make same-type copy/move trivial */ basic_ptr(const basic_ptr &) = default; basic_ptr(basic_ptr &&) = default; basic_ptr &operator=(const basic_ptr &) = default; basic_ptr &operator=(basic_ptr &&) = default; pointer_type get_unchecked_pointer() const { return m_ptr; } basic_ptr(std::nullptr_t) : m_ptr(nullptr) { static_assert(allow_nullptr, "nullptr construction not allowed for this policy"); } template basic_ptr(const magic_constant &) : m_ptr(nullptr) { static_assert(static_cast(v) >= array_size, "valid magic index requires an array"); static_assert(allow_nullptr || static_cast(v) < array_size, "invalid magic index not allowed for this policy"); } template basic_ptr(const magic_constant &, array_managed_type &a) : m_ptr(static_cast(v) < array_size ? &(a[v]) : nullptr) { static_assert(allow_nullptr || static_cast(v) < array_size, "invalid magic index not allowed for this policy"); } template basic_ptr(const basic_ptr &rhs) : m_ptr(rhs.get_unchecked_pointer()) { if (!(allow_nullptr || !rhs.allow_nullptr)) check_null_pointer_conversion(m_ptr); } template basic_ptr(basic_ptr &&rhs) : m_ptr(rhs.get_unchecked_pointer()) { /* Prevent move from allow_invalid into require_valid. The * right hand side must be saved and checked for validity before * being used to initialize a require_valid type. */ static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid"); } basic_ptr(index_type i, array_managed_type &a = get_array()) : m_ptr(check_allowed_invalid_index(i) ? nullptr : &a[check_index_range(i, a)]) { } basic_ptr(pointer_type p, array_managed_type &a = get_array()) : m_ptr(p) { if (!allow_nullptr) check_null_pointer(p, a); } basic_ptr(reference_type r, array_managed_type &a) : m_ptr((check_implicit_index_range_ref(r, a), &r)) { } basic_ptr(reference_type r, index_type i, array_managed_type &a) : m_ptr((check_explicit_index_range_ref(r, i, a), &r)) { } operator mutable_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated operator const_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated pointer_type operator->() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE { return m_ptr; } operator reference_type() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE { return *m_ptr; } reference_type operator*() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE { return *this; } explicit operator bool() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE { return !(*this == nullptr); } #ifdef DXX_HAVE_CXX11_REF_QUALIFIER pointer_type operator->() const && { static_assert(!allow_nullptr, "operator-> not allowed with allow_invalid policy"); return operator->(); } operator reference_type() const && { static_assert(!allow_nullptr, "implicit reference not allowed with allow_invalid policy"); return *this; } reference_type operator*() const && { static_assert(!allow_nullptr, "operator* not allowed with allow_invalid policy"); return *this; } explicit operator bool() const && = delete; #endif bool operator==(std::nullptr_t) const { static_assert(allow_nullptr, "nullptr comparison not allowed: value is never null"); return m_ptr == nullptr; } bool operator==(const_pointer_type p) const { return m_ptr == p; } bool operator==(mutable_pointer_type p) const { return m_ptr == p; } template bool operator==(const basic_ptr &rhs) const { return *this == rhs.get_unchecked_pointer(); } template bool operator!=(const R &rhs) const { return !(*this == rhs); } template long operator-(U) const = delete; template bool operator<(R) const = delete; template bool operator>(R) const = delete; template bool operator<=(R) const = delete; template bool operator>=(R) const = delete; protected: pointer_type m_ptr; }; template template class valptridx::basic_ptridx : public prohibit_void_ptr>, public basic_ptr, public basic_idx { public: typedef basic_ptr vptr_type; typedef basic_idx vidx_type; using typename vidx_type::array_managed_type; using typename vidx_type::index_type; using typename vidx_type::integral_type; using typename vptr_type::pointer_type; using vidx_type::operator==; using vptr_type::operator==; basic_ptridx(const basic_ptridx &) = default; basic_ptridx(basic_ptridx &&) = default; basic_ptridx &operator=(const basic_ptridx &) = default; basic_ptridx &operator=(basic_ptridx &&) = default; basic_ptridx(std::nullptr_t) = delete; /* Prevent implicit conversion. Require use of the factory function. */ basic_ptridx(pointer_type p) = delete; template basic_ptridx(const basic_ptridx &rhs) : vptr_type(static_cast::vptr_type &>(rhs)), vidx_type(static_cast::vidx_type &>(rhs)) { } template basic_ptridx(basic_ptridx &&rhs) : vptr_type(static_cast::vptr_type &&>(rhs)), vidx_type(static_cast::vidx_type &&>(rhs)) { } template basic_ptridx(const magic_constant &m) : vptr_type(m), vidx_type(m) { } template basic_ptridx(const magic_constant &m, array_managed_type &a) : vptr_type(m, a), vidx_type(m) { } basic_ptridx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated vptr_type(i, a), vidx_type(i, a) { } basic_ptridx(pointer_type p, array_managed_type &a) : /* Null pointer is never allowed when an index must be computed. * Check for null, then use the reference constructor for * vptr_type to avoid checking again. */ vptr_type((check_null_pointer(p, a), *p), a), vidx_type(p - static_cast(&a.front()), a) { } basic_ptridx(pointer_type p, index_type i, array_managed_type &a) : vptr_type((check_null_pointer(p, a), *p), i, a), vidx_type(i, a) { } template bool operator==(const basic_ptridx &rhs) const { return vptr_type::operator==(static_cast::vptr_type &>(rhs)); } template bool operator!=(const R &rhs) const { return !(*this == rhs); } }; template class valptridx::array_managed_type : public array { using containing_type = valptridx; using array_type = array; public: using typename array_type::reference; using typename array_type::const_reference; using index_type = typename containing_type::index_type; unsigned highest; template typename tt::enable_if::value, reference>::type operator[](T n) { return array_type::operator[](n); } template typename tt::enable_if::value, const_reference>::type operator[](T n) const { return array_type::operator[](n); } template typename tt::enable_if::value, reference>::type operator[](T) const = delete; #if DXX_HAVE_POISON_UNDEFINED array_managed_type(); #else array_managed_type() = default; #endif array_managed_type(const array_managed_type &) = delete; array_managed_type &operator=(const array_managed_type &) = delete; }; template template class valptridx::basic_vptr_global_factory { using containing_type = valptridx; public: basic_vptr_global_factory() = default; basic_vptr_global_factory(const basic_vptr_global_factory &) = delete; basic_vptr_global_factory &operator=(const basic_vptr_global_factory &) = delete; __attribute_warn_unused_result P operator()(typename P::const_pointer_type p) const { return P(p, get_array(p)); } __attribute_warn_unused_result P operator()(typename P::mutable_pointer_type p) const { return P(p, get_array(p)); } __attribute_warn_unused_result P operator()(typename containing_type::index_type i) const { return P(i, get_array()); } template __attribute_warn_unused_result P operator()(const containing_type::magic_constant &m) const { return P(m, get_array()); } template P operator()(containing_type::basic_idx i) const { return P(i, get_array()); } template P operator()(T &&) const = delete; void *operator &() const = delete; }; template template class valptridx::basic_ptridx_global_factory { using containing_type = valptridx; public: basic_ptridx_global_factory() = default; basic_ptridx_global_factory(const basic_ptridx_global_factory &) = delete; basic_ptridx_global_factory &operator=(const basic_ptridx_global_factory &) = delete; __attribute_warn_unused_result PI operator()(typename PI::index_type i) const { return PI(i, get_array()); } template __attribute_warn_unused_result PI operator()(const containing_type::magic_constant &m) const { return PI(m, get_array()); } template PI operator()(T &&) const = delete; void *operator &() const = delete; }; #define _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,prefix,Pconst) \ static constexpr Pconst valptridx

::array_managed_type &get_global_array(P Pconst *) { return A; } \ constexpr valptridx

::basic_vptr_global_factory v##prefix##ptr{}; \ constexpr valptridx

::basic_ptridx_global_factory prefix##ptridx{}; \ constexpr valptridx

::basic_vptr_global_factory v##prefix##ptridx{}; \ static inline v##prefix##ptridx_t operator-(Pconst P *o, Pconst valptridx

::array_managed_type &O) \ { \ return {o, static_cast(const_cast(o) - static_cast(&(const_cast::array_managed_type &>(O).front()))), O}; \ } \ #define DEFINE_VALPTRIDX_SUBTYPE(N,P,I,A) \ _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,N,); \ _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,c##N,const) \