class valptridx::index_mismatch_exception :
public std::logic_error
{
using std::logic_error::logic_error;
public:
[[noreturn]]
__attribute_cold
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *, index_type, const_pointer_type, const_pointer_type);
};
template
class valptridx::index_range_exception :
public std::out_of_range
{
using std::out_of_range::out_of_range;
public:
[[noreturn]]
__attribute_cold
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *, long);
};
template
class valptridx::null_pointer_exception :
public std::logic_error
{
using std::logic_error::logic_error;
public:
[[noreturn]]
__attribute_cold
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DEFN_VARS);
[[noreturn]]
__attribute_cold
DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *);
};
template
template
void valptridx::check_index_match(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type r, index_type i, const array_managed_type &a __attribute_unused)
{
const auto pi = &a[i];
DXX_VALPTRIDX_CHECK(pi == &r, handle_index_mismatch, "pointer/index mismatch", &a, i, pi, &r);
}
template
template class Compare>
typename valptridx::index_type valptridx::check_index_range(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const index_type i, const array_managed_type *const a)
{
std::size_t si;
if constexpr (std::is_enum::value)
si = static_cast(i);
else
si = i;
const std::size_t ss = si;
DXX_VALPTRIDX_CHECK(Compare()(ss, array_size), handle_index_range_error, "invalid index used in array subscript", a, ss);
return i;
}
template
template
void valptridx::check_null_pointer_conversion(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_pointer_type p)
{
DXX_VALPTRIDX_CHECK(p, handle_null_pointer, "NULL pointer converted");
}
template
template
void valptridx::check_null_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_pointer_type p, const array_managed_type &a __attribute_unused)
{
DXX_VALPTRIDX_CHECK(p, handle_null_pointer, "NULL pointer used", &a);
}
template
template
void valptridx::check_implicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const managed_type &r, const array_managed_type &a)
{
check_explicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, static_cast(&r) - static_cast(&a.front()), a);
}
template
template
void valptridx::check_explicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_reference_type &r, std::size_t i, const array_managed_type &a)
{
check_index_match(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, i, a);
check_index_range(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a);
}
template
class valptridx::partial_policy::require_valid
{
public:
static constexpr std::false_type allow_nullptr{};
static constexpr std::false_type check_allowed_invalid_index(index_type) { return {}; }
static constexpr bool check_nothrow_index(index_type i)
{
return std::less()(static_cast(i), array_size);
}
};
template
class valptridx::partial_policy::allow_invalid
{
public:
static constexpr std::true_type allow_nullptr{};
static constexpr bool check_allowed_invalid_index(index_type i)
{
return i == static_cast(~0);
}
static constexpr bool check_nothrow_index(index_type i)
{
return check_allowed_invalid_index(i) || require_valid::check_nothrow_index(i);
}
};
template
constexpr std::false_type valptridx::partial_policy::require_valid::allow_nullptr;
template
constexpr std::true_type valptridx::partial_policy::allow_invalid::allow_nullptr;
template
template class policy>
class valptridx::partial_policy::apply_cv_policy
{
template
using apply_cv_qualifier = typename policy::type;
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::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;
idx() = delete;
idx(const idx &) = default;
idx(idx &&) = default;
idx &operator=(const idx &) & = default;
idx &operator=(idx &&) & = default;
idx &operator=(const idx &) && = delete;
idx &operator=(idx &&) && = delete;
index_type get_unchecked_index() const { return m_idx; }
/* If moving from allow_invalid to allow_invalid, no check is
* needed.
* If moving from require_valid to anything, no check is needed.
*/
template ::type = 0>
idx(const idx &rhs) :
m_idx(rhs.get_unchecked_index())
{
}
template ::type = 0>
idx(const idx &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
m_idx(rhs.get_unchecked_index())
{
/* If moving from allow_invalid to require_valid, check range.
*/
check_index_range>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_idx, nullptr);
}
template
idx(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(policy::allow_nullptr || !rpolicy::allow_nullptr, "cannot move from allow_invalid to require_valid");
}
idx(index_type i DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
m_idx(check_allowed_invalid_index(i) ? i : check_index_range>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, nullptr))
{
}
idx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
m_idx(check_allowed_invalid_index(i) ? i : check_index_range>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a))
{
}
protected:
template
idx(const magic_constant &, const allow_none_construction *) :
m_idx(v)
{
static_assert(!allow_nullptr, "allow_none_construction used where nullptr was already legal");
static_assert(static_cast(v) >= array_size, "allow_none_construction used with valid index");
}
idx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *) :
m_idx(check_index_range, std::less_equal>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a))
{
}
idx(index_type i, array_managed_type &, const assume_nothrow_index *) :
m_idx(i)
{
}
public:
template
constexpr 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 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;
idx &operator++()
{
if constexpr (std::is_enum::value)
m_idx = static_cast(1u + static_cast::type>(m_idx));
else
++ m_idx;
return *this;
}
};
template
template
class valptridx::ptr :
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 const_pointer_type = typename containing_type::const_pointer_type;
using mutable_pointer_type = typename containing_type::mutable_pointer_type;
using allow_none_construction = typename containing_type::allow_none_construction;
using typename policy::array_managed_type;
using typename policy::pointer_type;
using typename policy::reference_type;
ptr() = delete;
/* Override template matches to make same-type copy/move trivial */
ptr(const ptr &) = default;
ptr(ptr &&) = default;
ptr &operator=(const ptr &) & = default;
ptr &operator=(ptr &&) & = default;
ptr &operator=(const ptr &) && = delete;
ptr &operator=(ptr &&) && = delete;
pointer_type get_unchecked_pointer() const { return m_ptr; }
pointer_type get_nonnull_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS) const
{
/* If !allow_nullptr, assume nullptr was caught at construction. */
const auto p = m_ptr;
if constexpr (allow_nullptr)
check_null_pointer_conversion>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p);
else
DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_VOID_VARS();
return p;
}
reference_type get_checked_reference(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS) const
{
return *get_nonnull_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VA());
}
ptr(std::nullptr_t) :
m_ptr(nullptr)
{
static_assert(allow_nullptr, "nullptr construction not allowed for this policy");
}
template
ptr(const magic_constant &) :
m_ptr(nullptr)
{
static_assert(static_cast(v) >= array_size, "valid magic index requires an array");
if constexpr (!allow_nullptr)
static_assert(static_cast(v) < array_size, "invalid magic index not allowed for this policy");
}
template
ptr(const magic_constant &, array_managed_type &a) :
m_ptr(&a[v])
{
static_assert(static_cast(v) < array_size, "valid magic index required when using array");
}
template ::type = 0>
ptr(const ptr &rhs) :
m_ptr(rhs.get_unchecked_pointer())
{
}
template ::type = 0>
ptr(const ptr &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
m_ptr(rhs.get_unchecked_pointer())
{
check_null_pointer_conversion>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_ptr);
}
template
ptr(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(policy::allow_nullptr || !rpolicy::allow_nullptr, "cannot move from allow_invalid to require_valid");
}
ptr(index_type i) = delete;
ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
m_ptr(check_allowed_invalid_index(i) ? nullptr : &a[check_index_range>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a)])
{
}
ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *) :
m_ptr(&a[check_index_range, std::less_equal>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a)])
{
}
ptr(index_type i, array_managed_type &a, const assume_nothrow_index *) :
m_ptr(&a[i])
{
}
ptr(pointer_type p) = delete;
ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS pointer_type p, array_managed_type &a) :
/* No array consistency check here, since some code incorrectly
* defines instances of `object` outside the Objects array, then
* passes pointers to those instances to this function.
*/
m_ptr(p)
{
if constexpr (!allow_nullptr)
check_null_pointer>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
}
ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS reference_type r, array_managed_type &a) :
m_ptr((check_implicit_index_range_ref, index_range_error_type>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, a), &r))
{
}
ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS reference_type r, index_type i, array_managed_type &a) :
m_ptr((check_explicit_index_range_ref, index_range_error_type>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS 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
template
typename std::enable_if::value, ptr>::type rebind_policy(ptr &&rhs) const
{
/* This method could be marked as `static`, but is non-static so
* that callers must possess an instance of the target type.
* This serves as a basic check against casts that could remove
* `const` incorrectly.
*/
return ptr(std::move(rhs), static_cast(nullptr));
}
pointer_type operator->() const &
{
return get_nonnull_pointer();
}
operator reference_type() const &
{
return get_checked_reference();
}
reference_type operator*() const &
{
return get_checked_reference();
}
explicit operator bool() const &
{
return !(*this == nullptr);
}
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;
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 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;
ptr &operator++()
{
++ m_ptr;
return *this;
}
ptr(const allow_none_construction *) :
m_ptr(nullptr)
{
static_assert(!allow_nullptr, "allow_none_construction used where nullptr was already legal");
}
template
ptr(ptr &&rhs, const typename containing_type::rebind_policy *) :
m_ptr(const_cast(rhs.get_unchecked_pointer()))
{
static_assert(allow_nullptr || !rpolicy::allow_nullptr, "cannot rebind from allow_invalid to require_valid");
}
};
#if DXX_VALPTRIDX_ENFORCE_STRICT_PI_SEPARATION
template
struct strong_typedef : T
{
using T::T;
template ::value, int>::type = 0>
strong_typedef(O &&o) :
T(std::forward(o))
{
}
strong_typedef() = default;
strong_typedef(const strong_typedef &) = default;
strong_typedef(strong_typedef &&) = default;
strong_typedef &operator=(const strong_typedef &) & = default;
strong_typedef &operator=(strong_typedef &&) & = default;
strong_typedef &operator=(const strong_typedef &) && = delete;
strong_typedef &operator=(strong_typedef &&) && = delete;
};
#endif
template
template
class valptridx::ptridx :
public prohibit_void_ptr>,
public ptr,
public idx
{
using containing_type = valptridx;
public:
using vptr_type = ptr;
using vidx_type = idx;
using typename vidx_type::array_managed_type;
using index_type = 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==;
ptridx(const ptridx &) = default;
ptridx(ptridx &&) = default;
ptridx &operator=(const ptridx &) & = default;
ptridx &operator=(ptridx &&) & = default;
ptridx &operator=(const ptridx &) && = delete;
ptridx &operator=(ptridx &&) && = delete;
ptridx(std::nullptr_t) = delete;
/* Prevent implicit conversion. Require use of the factory function.
*/
ptridx(pointer_type p) = delete;
template ::type = 0>
ptridx(const ptridx &rhs) :
vptr_type(static_cast::vptr_type &>(rhs)),
vidx_type(static_cast::vidx_type &>(rhs))
{
}
template ::type = 0>
ptridx(const ptridx &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
vptr_type(static_cast::vptr_type &>(rhs) DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_PASS_VARS),
vidx_type(static_cast::vidx_type &>(rhs) DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_PASS_VARS)
{
}
template
ptridx(ptridx &&rhs) :
vptr_type(static_cast::vptr_type &&>(rhs)),
vidx_type(static_cast::vidx_type &&>(rhs))
{
}
template
ptridx(const magic_constant &m) :
vptr_type(m),
vidx_type(m)
{
}
template
ptridx(const magic_constant &m, array_managed_type &a) :
vptr_type(m, a),
vidx_type(m)
{
}
template
ptridx(const magic_constant &m, const allow_none_construction *const n) :
vptr_type(n),
vidx_type(m, n)
{
}
ptridx(index_type i) = delete;
ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a),
vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a)
{
}
ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *e) :
vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a, e),
vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a, e)
{
}
ptridx(index_type i, array_managed_type &a, const assume_nothrow_index *e) :
vptr_type(i, a, e),
vidx_type(i, a, e)
{
}
ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS 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(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS (check_null_pointer>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a), *p), a),
vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p - static_cast(&a.front()), a)
{
}
ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS pointer_type p, index_type i, array_managed_type &a) :
vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS (check_null_pointer>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a), *p), i, a),
vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a)
{
}
template
typename std::enable_if::value, ptridx>::type rebind_policy(ptridx &&rhs) const
{
return ptridx(std::move(rhs), static_cast(nullptr));
}
ptridx absolute_sibling(const index_type i DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
{
static_assert(!policy::allow_nullptr, "absolute_sibling not allowed with invalid ptridx");
ptridx r(*this);
r.m_ptr += check_index_range>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, nullptr) - this->m_idx;
r.m_idx = i;
return r;
}
template
bool operator==(const ptridx &rhs) const
{
return vptr_type::operator==(static_cast::vptr_type &>(rhs));
}
template
bool operator!=(const R &rhs) const
{
return !(*this == rhs);
}
protected:
ptridx &operator++()
{
vptr_type::operator++();
vidx_type::operator++();
return *this;
}
template
ptridx(ptridx &&rhs, const typename containing_type::rebind_policy *const rebind) :
vptr_type(static_cast::vptr_type &&>(rhs), rebind),
vidx_type(static_cast::vidx_type &&>(rhs))
{
/* No static_assert for policy compatibility. Incompatible
* policy conversions will be trapped by the static_assert in
* `vptr_type`.
*/
}
};
template
template
class valptridx::guarded
{
static_assert(std::is_trivially_destructible::value, "non-trivial destructor found for guarded_type");
enum state : uint8_t
{
/* empty - the untrusted input was invalid, so no guarded_type
* exists
*/
empty,
/* initialized - the untrusted input was valid, so a
* guarded_type type exists, but the calling code has not yet
* tested the state of this guarded
*/
initialized,
/* checked - the untrusted input was valid, and the calling code
* has called operator bool()
*/
checked,
};
union {
state m_dummy;
guarded_type m_value;
};
mutable state m_state;
public:
__attribute_cold
guarded(std::nullptr_t) :
m_dummy(), m_state(empty)
{
}
guarded(guarded_type &&v) :
m_value(std::move(v)), m_state(initialized)
{
}
[[nodiscard]]
explicit operator bool() const
{
/*
* If no contained guarded_type exists, return false.
* Otherwise, record that the result has been tested and then
* return true. operator*() uses m_state to enforce that the
* result is tested.
*/
if (unlikely(m_state == empty))
return false;
m_state = checked;
return true;
}
[[nodiscard]]
guarded_type operator*() const &
{
/*
* Correct code will always execute as if this method was just
* the return statement, with none of the sanity checks. The
* checks are present to catch misuse of this type, preferably
* at compile-time, but at least at runtime.
*/
#define DXX_VALPTRIDX_GUARDED_OBJECT_NO "access to guarded object that does not exist"
#define DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE "access to guarded object that may not exist"
#ifdef DXX_CONSTANT_TRUE
{
/*
* If the validity has not been verified by the caller, then
* fail. Choose an error message and function name
* based on whether the contained type provably does not
* exist. It provably does not exist if this call is on a
* path where operator bool() returned false. It
* conditionally might not exist if this call is on a path
* where operator bool() has not been called.
*/
if (DXX_CONSTANT_TRUE(m_state == empty))
DXX_ALWAYS_ERROR_FUNCTION(guarded_accessed_empty, DXX_VALPTRIDX_GUARDED_OBJECT_NO);
/* If the contained object might not exist: */
if (DXX_CONSTANT_TRUE(m_state == initialized))
DXX_ALWAYS_ERROR_FUNCTION(guarded_accessed_unchecked, DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE);
}
#endif
/*
* If the compiler does not offer constant truth analysis
* (perhaps because of insufficient optimization), then emit a
* runtime check for whether the guarded_type exists.
*
* This test can throw even if the contained object is valid, if
* the caller did not first validate that the contained object
* is valid. This restriction is necessary since inputs are
* usually valid even when untested, so throwing only on state
* `empty` would allow incorrect usage to persist in the code
* until someone happened to receive an invalid input from an
* untrusted source.
*/
if (m_state != checked)
throw std::logic_error(m_state == empty ? DXX_VALPTRIDX_GUARDED_OBJECT_NO : DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE);
#undef DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE
#undef DXX_VALPTRIDX_GUARDED_OBJECT_NO
return m_value;
}
guarded_type operator*() const && = delete;
};
template
class valptridx::array_managed_type :
public array_base_count_type,
public array_base_storage_type
{
public:
/*
* Expose the union members that act as factory methods. Leave the
* `count` union member protected.
*/
#define DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES(MANAGED_TYPE, DERIVED_TYPE_PREFIX, CONTEXT, PISUFFIX, IVPREFIX, MCPREFIX) \
using array_base_count_type::IVPREFIX ## MCPREFIX ## PISUFFIX
DXX_VALPTRIDX_FOR_EACH_PPI_TYPE(DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES,,,);
#undef DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES
using typename array_base_storage_type::reference;
using typename array_base_storage_type::const_reference;
reference operator[](const integral_type &n)
{
return array_base_storage_type::operator[](n);
}
const_reference operator[](const integral_type &n) const
{
return array_base_storage_type::operator[](n);
}
template
reference operator[](const 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_ival_member_factory
{
using containing_type = valptridx;
protected:
/*
* These casts are well-defined:
* - The reinterpret_cast is defined because
* `basic_ival_member_factory` is a base of a member of the
* anonymous union in `array_base_count_type`.
* - The anonymous union in `array_base_count_type` is the only
* member of that type, so its storage must be aligned to the
* beginning of the object.
* - `basic_ival_member_factory` and its derivatives are not used
* anywhere other than `array_base_count_type`, so any call to
* these methods must be on an instance used in
* `array_base_count_type`.
*
* - The static_cast is defined because `array_base_count_type` is a
* non-virtual base of `array_managed_type`.
* - `array_base_count_type` is not used as a base for any class
* other than `array_managed_type`, nor used freestanding, so any
* instance of `array_base_count_type` must be safe to downcast to
* `array_managed_type`.
*/
constexpr const array_managed_type &get_array() const
{
return static_cast(reinterpret_cast(*this));
}
array_managed_type &get_array()
{
return static_cast(reinterpret_cast(*this));
}
template
static guarded check_untrusted_internal(const index_type i, A &a)
{
if (P::check_nothrow_index(i))
return P(i, a, static_cast(nullptr));
else
return nullptr;
}
template
static guarded check_untrusted_internal(T &&, A &) = delete;
template
[[nodiscard]]
/* C++ does not allow `static operator()()`, so name it
* `call_operator` instead.
*/
static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename P::index_type i, A &a)
{
return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a);
}
template
[[nodiscard]]
static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const containing_type::magic_constant &m, A &a)
{
/*
* All call_operator definitions must have the macro which
* defines filename/lineno, but the magic_constant overload
* has no need for them.
*
* Cast them to void to silence the warning about unused
* parameters.
*/
DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_VOID_VARS();
return P(m, a);
}
template
static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS T &&, A &a) = delete;
basic_ival_member_factory() = default;
public:
basic_ival_member_factory(const basic_ival_member_factory &) = delete;
basic_ival_member_factory &operator=(const basic_ival_member_factory &) = delete;
void *operator &() const = delete;
template
[[nodiscard]]
guarded check_untrusted(T &&t) const
{
return this->template check_untrusted_internal(static_cast(t), get_array());
}
template
[[nodiscard]]
guarded check_untrusted(T &&t)
{
return this->template check_untrusted_internal(static_cast(t), get_array());
}
template
[[nodiscard]]
Pc operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
{
return this->template call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast(t), get_array());
}
template
[[nodiscard]]
Pm operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS)
{
return this->template call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast(t), get_array());
}
};
template
template
class valptridx::basic_vval_member_factory :
public basic_ival_member_factory
{
protected:
using basic_ival_member_factory::get_array;
using basic_ival_member_factory::call_operator;
template
using iterator = self_return_iterator;
template
static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename valptridx::template wrapper::idx> i, A &a)
{
return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a);
}
template
[[nodiscard]]
static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename P::mutable_pointer_type p, typename P::array_managed_type &a)
{
return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
}
/*
* When P is a const type, enable an overload that takes a const
* array. Otherwise, enable a deleted overload that takes a mutable
* array. This provides a slightly clearer error when trying to
* pass a const pointer to a mutable factory.
*/
template
[[nodiscard]]
static typename std::enable_if::value, P>::type call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename P::const_pointer_type p, const array_managed_type &a)
{
return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
}
template
static typename std::enable_if::value, P>::type call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename P::const_pointer_type p, array_managed_type &a) = delete;
template
static iterator end_internal(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS A &a)
{
return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast(a.get_count()), a, static_cast(nullptr));
}
public:
[[nodiscard]]
typename array_base_storage_type::size_type count() const
{
return get_array().get_count();
}
[[nodiscard]]
typename array_base_storage_type::size_type size() const
{
return get_array().size();
}
template
[[nodiscard]]
Pc operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
{
return this->template call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast(t), get_array());
}
template
[[nodiscard]]
Pm operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS)
{
return this->template call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast(t), get_array());
}
[[nodiscard]]
iterator begin() const
{
return Pc(valptridx