class valptridx::index_mismatch_exception :
valptridxutil_untyped_base::index_mismatch_exception,
public std::logic_error
{
DXX_INHERIT_CONSTRUCTORS(index_mismatch_exception, logic_error);
public:
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t, index_type, const_pointer_type, const_pointer_type);
};
template
class valptridx::index_range_exception :
valptridxutil_untyped_base::index_range_exception,
public std::out_of_range
{
DXX_INHERIT_CONSTRUCTORS(index_range_exception, out_of_range);
public:
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t, long);
};
template
class valptridx::null_pointer_exception :
valptridxutil_untyped_base::null_pointer_exception,
public std::logic_error
{
DXX_INHERIT_CONSTRUCTORS(null_pointer_exception, logic_error);
public:
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t);
};
template
void valptridx::index_mismatch_exception::report(const const_pointer_type array_base, const std::size_t array_size, const index_type supplied_index, const const_pointer_type expected_pointer, const const_pointer_type actual_pointer)
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size, supplied_index, expected_pointer, actual_pointer);
throw index_mismatch_exception(buf);
}
template
void valptridx::index_range_exception::report(const const_pointer_type array_base, const std::size_t array_size, const long supplied_index)
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size, supplied_index);
throw index_range_exception(buf);
}
template
void valptridx::null_pointer_exception::report(const const_pointer_type array_base, const std::size_t array_size)
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size);
throw null_pointer_exception(buf);
}
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[0], a.size(), 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;
const std::size_t as = a.size();
DXX_VALPTRIDX_CHECK(ss < as, index_range_exception, "invalid index used in array subscript", &a[0], as, ss);
return i;
}
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[0], a.size());
}
template
void valptridx::check_implicit_index_range_ref(const managed_type &r, const array_managed_type &a)
{
check_explicit_index_range_ref(r, &r - a, 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
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) < get_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) < get_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(static_cast(v) < get_array().size() ? &(get_array()[v]) : nullptr)
{
static_assert(allow_nullptr || static_cast(v) < get_array().size(), "invalid magic index not allowed for this policy");
}
template
basic_ptr(const basic_ptr &rhs, array_managed_type &a = get_array()) :
m_ptr(rhs.get_unchecked_pointer())
{
if (!(allow_nullptr || !rhs.allow_nullptr))
check_null_pointer(m_ptr, a);
}
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 = get_array()) :
m_ptr((check_implicit_index_range_ref(r, a), &r))
{
}
basic_ptr(reference_type r, index_type i, array_managed_type &a = get_array()) :
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 basic_ptr,
public basic_idx
{
using vptr_type = basic_ptr;
using vidx_type = basic_idx;
public:
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;
template
basic_ptridx(const basic_ptridx &rhs) :
vptr_type(static_cast &>(rhs)),
vidx_type(static_cast &>(rhs))
{
}
template
basic_ptridx(basic_ptridx &&rhs) :
vptr_type(static_cast &&>(rhs)),
vidx_type(static_cast &&>(rhs))
{
}
template
basic_ptridx(const magic_constant &m) :
vptr_type(m),
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 = get_array(pointer_type())) : // default argument deprecated
/* 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 - a, a)
{
}
basic_ptridx(pointer_type p, index_type i, array_managed_type &a = get_array(pointer_type())) :
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 &>(rhs));
}
template
bool operator!=(const R &rhs) const
{
return !(*this == rhs);
}
};
template
class valptridx::cptr :
public prohibit_void_ptr,
public basic_ptr
{
public:
DXX_INHERIT_CONSTRUCTORS(cptr, basic_ptr);
};
template
class valptridx::ptr :
public prohibit_void_ptr,
public basic_ptr
{
public:
DXX_INHERIT_CONSTRUCTORS(ptr, basic_ptr);
};
template
class valptridx::vcptr :
public prohibit_void_ptr,
public basic_ptr
{
public:
DXX_INHERIT_CONSTRUCTORS(vcptr, basic_ptr);
};
template
class valptridx::vptr :
public prohibit_void_ptr,
public basic_ptr
{
public:
DXX_INHERIT_CONSTRUCTORS(vptr, basic_ptr);
};
template
class valptridx::cptridx :
public prohibit_void_ptr,
public basic_ptridx
{
public:
DXX_INHERIT_CONSTRUCTORS(cptridx, basic_ptridx);
};
template
class valptridx::ptridx :
public prohibit_void_ptr,
public basic_ptridx
{
public:
DXX_INHERIT_CONSTRUCTORS(ptridx, basic_ptridx);
};
template
class valptridx::vcptridx :
public prohibit_void_ptr,
public basic_ptridx
{
public:
DXX_INHERIT_CONSTRUCTORS(vcptridx, basic_ptridx);
};
template
class valptridx::vptridx :
public prohibit_void_ptr,
public basic_ptridx
{
public:
DXX_INHERIT_CONSTRUCTORS(vptridx, basic_ptridx);
};
template
template
class valptridx::basic_vptr_global_factory
{
public:
__attribute_warn_unused_result
vptr operator()(typename vptr::const_pointer_type p) const
{
return vptr{p, get_array(p)};
}
__attribute_warn_unused_result
vptr operator()(typename vptr::mutable_pointer_type p) const
{
return vptr{p, get_array(p)};
}
__attribute_warn_unused_result
vptr operator()(typename valptridx::index_type i) const
{
return vptr{i, get_array()};
}
template
vptr operator()(T) const = delete;
void *operator &() const = delete;
};
template
template
class valptridx::basic_ptridx_global_factory
{
public:
__attribute_warn_unused_result
ptridx operator()(typename ptridx::index_type i) const
{
return ptridx{i, get_array()};
}
template
ptridx operator()(T) const = delete;
void *operator &() const = delete;
};
#define _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,prefix,Pconst) \
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-(P Pconst *o, decltype(A) Pconst &O) \
{ \
return {o, static_cast(const_cast(o) - &(const_cast(O).front())), A}; \
} \
#define DEFINE_VALPTRIDX_SUBTYPE(N,P,I,A) \
static inline constexpr decltype(A) &get_global_array(P *) { return A; } \
/* "decltype(A) const &" parses correctly, but fails to match */ \
static inline constexpr typename tt::add_const::type &get_global_array(P const *) { return A; } \
\
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,N,); \
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,c##N,const) \