Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. #pragma once
  8.  
  9. #include <stdexcept>
  10. #include <string>
  11. #include <type_traits>
  12. #include "fwd-valptridx.h"
  13. #include "pack.h"
  14. #include "compiler-poison.h"
  15. #include "selfiter.h"
  16. #include <array>
  17.  
  18. #ifdef DXX_CONSTANT_TRUE
  19. #define DXX_VALPTRIDX_STATIC_CHECK(SUCCESS_CONDITION,FAILURE_FUNCTION,FAILURE_STRING)   \
  20.                 static_cast<void>(DXX_CONSTANT_TRUE(!SUCCESS_CONDITION) &&      \
  21.                         (DXX_ALWAYS_ERROR_FUNCTION(FAILURE_FUNCTION, FAILURE_STRING), 0)        \
  22.                 )       \
  23.  
  24. #ifdef DXX_HAVE_ATTRIBUTE_WARNING
  25. /* This causes many warnings because some conversions are not checked for
  26.  * safety.  Eliminating the warnings by changing the call sites to check first
  27.  * would be a useful improvement.
  28.  */
  29. //#define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT __attribute__((__warning__("call not eliminated")))
  30. #endif
  31. #else
  32. #define DXX_VALPTRIDX_STATIC_CHECK(E,F,S)
  33. #endif
  34.  
  35. #define DXX_VALPTRIDX_CHECK(SUCCESS_CONDITION,ERROR,FAILURE_STRING,...) \
  36.         ( DXX_BEGIN_COMPOUND_STATEMENT {        \
  37.                 const bool dxx_valptridx_check_success_condition = (SUCCESS_CONDITION); \
  38.                 DXX_VALPTRIDX_STATIC_CHECK(dxx_valptridx_check_success_condition, dxx_trap_##ERROR, FAILURE_STRING);    \
  39.                 static_cast<void>(      \
  40.                         dxx_valptridx_check_success_condition || (ERROR::report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VA(__VA_ARGS__)), 0)  \
  41.                 );      \
  42.         } DXX_END_COMPOUND_STATEMENT )
  43.  
  44. #ifndef DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  45. #define DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  46. #endif
  47.  
  48. template <typename managed_type>
  49. class valptridx<managed_type>::array_base_count_type
  50. {
  51. protected:
  52.         union {
  53.                 unsigned count;
  54.                 /*
  55.                  * Use DXX_VALPTRIDX_FOR_EACH_PPI_TYPE to generate empty union
  56.                  * members based on basic_{i,v}val_member_factory
  57.                  * specializations.
  58.                  */
  59. #define DXX_VALPTRIDX_DEFINE_MEMBER_FACTORIES(MANAGED_TYPE, DERIVED_TYPE_PREFIX, CONTEXT, PISUFFIX, IVPREFIX, MCPREFIX) \
  60.                 valptridx<MANAGED_TYPE>::f ## IVPREFIX ## MCPREFIX ## PISUFFIX  \
  61.                         IVPREFIX ## MCPREFIX ## PISUFFIX
  62.                 DXX_VALPTRIDX_FOR_EACH_PPI_TYPE(DXX_VALPTRIDX_DEFINE_MEMBER_FACTORIES, managed_type,,);
  63. #undef DXX_VALPTRIDX_DEFINE_MEMBER_FACTORIES
  64.         };
  65.         constexpr array_base_count_type() :
  66.                 count(0)
  67.         {
  68.         }
  69. public:
  70.         unsigned get_count() const
  71.         {
  72.                 return count;
  73.         }
  74.         void set_count(const unsigned c)
  75.         {
  76.                 count = c;
  77.         }
  78. };
  79.  
  80. template <
  81.         typename INTEGRAL_TYPE,
  82.         std::size_t array_size_value,
  83.         valptridx_detail::untyped_utilities::report_error_style report_const_error_value,
  84.         valptridx_detail::untyped_utilities::report_error_style report_mutable_error_value
  85.         >
  86. constexpr std::integral_constant<std::size_t, array_size_value> valptridx_detail::specialized_type_parameters<INTEGRAL_TYPE, array_size_value, report_const_error_value, report_mutable_error_value>::array_size;
  87.  
  88. class valptridx_detail::untyped_utilities::report_error_undefined
  89. {
  90. public:
  91.         __attribute_cold
  92.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  93.         static void report(...)
  94.         {
  95.         }
  96. };
  97.  
  98. class valptridx_detail::untyped_utilities::report_error_trap_terse
  99. {
  100. public:
  101.         __attribute_cold
  102.         __attribute_noreturn
  103.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  104.         static void report(...)
  105.         {
  106.                 __builtin_trap();
  107.         }
  108. };
  109.  
  110. class valptridx_detail::untyped_utilities::index_mismatch_trap_verbose
  111. {
  112. public:
  113.         __attribute_cold
  114.         __attribute_noreturn
  115.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  116.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const void *const array, const unsigned long supplied_index, const void *const expected_pointer, const void *const actual_pointer)
  117.         {
  118.                 __asm__ __volatile__("" :: DXX_VALPTRIDX_REPORT_STANDARD_ASM_LOAD_COMMA_R_VARS "rm" (array), "rm" (supplied_index), "rm" (expected_pointer), "rm" (actual_pointer));
  119.                 __builtin_trap();
  120.         }
  121. };
  122.  
  123. class valptridx_detail::untyped_utilities::index_range_trap_verbose
  124. {
  125. public:
  126.         __attribute_cold
  127.         __attribute_noreturn
  128.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  129.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const void *const array, const unsigned long supplied_index)
  130.         {
  131.                 __asm__ __volatile__("" :: DXX_VALPTRIDX_REPORT_STANDARD_ASM_LOAD_COMMA_R_VARS "rm" (array), "rm" (supplied_index));
  132.                 __builtin_trap();
  133.         }
  134. };
  135.  
  136. class valptridx_detail::untyped_utilities::null_pointer_trap_verbose
  137. {
  138. public:
  139.         __attribute_cold
  140.         __attribute_noreturn
  141.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  142.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DEFN_VARS)
  143.         {
  144.                 __asm__ __volatile__("" :: DXX_VALPTRIDX_REPORT_STANDARD_ASM_LOAD_COMMA_N_VARS);
  145.                 __builtin_trap();
  146.         }
  147.         __attribute_cold
  148.         __attribute_noreturn
  149.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  150.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const void *const array)
  151.         {
  152.                 __asm__ __volatile__("" :: DXX_VALPTRIDX_REPORT_STANDARD_ASM_LOAD_COMMA_R_VARS "rm" (array));
  153.                 __builtin_trap();
  154.         }
  155. };
  156.  
  157. template <typename P>
  158. class valptridx<P>::index_mismatch_exception :
  159.         public std::logic_error
  160. {
  161.         DXX_INHERIT_CONSTRUCTORS(index_mismatch_exception, logic_error);
  162. public:
  163.         __attribute_cold
  164.         __attribute_noreturn
  165.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  166.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *, index_type, const_pointer_type, const_pointer_type);
  167. };
  168.  
  169. template <typename P>
  170. class valptridx<P>::index_range_exception :
  171.         public std::out_of_range
  172. {
  173.         DXX_INHERIT_CONSTRUCTORS(index_range_exception, out_of_range);
  174. public:
  175.         __attribute_cold
  176.         __attribute_noreturn
  177.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  178.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *, long);
  179. };
  180.  
  181. template <typename P>
  182. class valptridx<P>::null_pointer_exception :
  183.         public std::logic_error
  184. {
  185.         DXX_INHERIT_CONSTRUCTORS(null_pointer_exception, logic_error);
  186. public:
  187.         __attribute_cold
  188.         __attribute_noreturn
  189.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  190.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DEFN_VARS);
  191.         __attribute_cold
  192.         __attribute_noreturn
  193.         DXX_VALPTRIDX_WARN_CALL_NOT_OPTIMIZED_OUT
  194.         static void report(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const array_managed_type *);
  195. };
  196.  
  197. template <typename managed_type>
  198. template <typename handle_index_mismatch>
  199. void valptridx<managed_type>::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)
  200. {
  201.         const auto pi = &a[i];
  202.         DXX_VALPTRIDX_CHECK(pi == &r, handle_index_mismatch, "pointer/index mismatch", &a, i, pi, &r);
  203. }
  204.  
  205. template <typename managed_type>
  206. template <typename handle_index_range_error, template <typename> class Compare>
  207. typename valptridx<managed_type>::index_type valptridx<managed_type>::check_index_range(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const index_type i, const array_managed_type *const a)
  208. {
  209.         const std::size_t ss = i;
  210.         DXX_VALPTRIDX_CHECK(Compare<std::size_t>()(ss, array_size), handle_index_range_error, "invalid index used in array subscript", a, ss);
  211.         return i;
  212. }
  213.  
  214. template <typename managed_type>
  215. template <typename handle_null_pointer>
  216. void valptridx<managed_type>::check_null_pointer_conversion(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_pointer_type p)
  217. {
  218.         DXX_VALPTRIDX_CHECK(p, handle_null_pointer, "NULL pointer converted");
  219. }
  220.  
  221. template <typename managed_type>
  222. template <typename handle_null_pointer>
  223. void valptridx<managed_type>::check_null_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const_pointer_type p, const array_managed_type &a __attribute_unused)
  224. {
  225.         DXX_VALPTRIDX_CHECK(p, handle_null_pointer, "NULL pointer used", &a);
  226. }
  227.  
  228. template <typename managed_type>
  229. template <typename handle_index_mismatch, typename handle_index_range_error>
  230. void valptridx<managed_type>::check_implicit_index_range_ref(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const managed_type &r, const array_managed_type &a)
  231. {
  232.         check_explicit_index_range_ref<handle_index_mismatch, handle_index_range_error>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, static_cast<const_pointer_type>(&r) - static_cast<const_pointer_type>(&a.front()), a);
  233. }
  234.  
  235. template <typename managed_type>
  236. template <typename handle_index_mismatch, typename handle_index_range_error>
  237. void valptridx<managed_type>::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)
  238. {
  239.         check_index_match<handle_index_mismatch>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, i, a);
  240.         check_index_range<handle_index_range_error>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a);
  241. }
  242.  
  243. template <typename managed_type>
  244. class valptridx<managed_type>::partial_policy::require_valid
  245. {
  246. public:
  247.         static constexpr std::false_type allow_nullptr{};
  248.         static constexpr std::false_type check_allowed_invalid_index(index_type) { return {}; }
  249.         static constexpr bool check_nothrow_index(index_type i)
  250.         {
  251.                 return std::less<std::size_t>()(i, array_size);
  252.         }
  253. };
  254.  
  255. template <typename managed_type>
  256. class valptridx<managed_type>::partial_policy::allow_invalid
  257. {
  258. public:
  259.         static constexpr std::true_type allow_nullptr{};
  260.         static constexpr bool check_allowed_invalid_index(index_type i)
  261.         {
  262.                 return i == static_cast<index_type>(~0);
  263.         }
  264.         static constexpr bool check_nothrow_index(index_type i)
  265.         {
  266.                 return check_allowed_invalid_index(i) || require_valid::check_nothrow_index(i);
  267.         }
  268. };
  269.  
  270. template <typename managed_type>
  271. constexpr std::false_type valptridx<managed_type>::partial_policy::require_valid::allow_nullptr;
  272.  
  273. template <typename managed_type>
  274. constexpr std::true_type valptridx<managed_type>::partial_policy::allow_invalid::allow_nullptr;
  275.  
  276. template <typename managed_type>
  277. template <template <typename> class policy>
  278. class valptridx<managed_type>::partial_policy::apply_cv_policy
  279. {
  280.         template <typename T>
  281.                 using apply_cv_qualifier = typename policy<T>::type;
  282. public:
  283.         using array_managed_type = apply_cv_qualifier<valptridx<managed_type>::array_managed_type>;
  284.         using pointer_type = apply_cv_qualifier<managed_type> *;
  285.         using reference_type = apply_cv_qualifier<managed_type> &;
  286. };
  287.  
  288. template <typename managed_type>
  289. class valptridx<managed_type>::vc :
  290.         public partial_policy::require_valid,
  291.         public partial_policy::template apply_cv_policy<std::add_const>
  292. {
  293. };
  294.  
  295. template <typename managed_type>
  296. class valptridx<managed_type>::vm :
  297.         public partial_policy::require_valid,
  298.         public partial_policy::template apply_cv_policy<std::remove_const>
  299. {
  300. };
  301.  
  302. template <typename managed_type>
  303. class valptridx<managed_type>::ic :
  304.         public partial_policy::allow_invalid,
  305.         public partial_policy::template apply_cv_policy<std::add_const>
  306. {
  307. };
  308.  
  309. template <typename managed_type>
  310. class valptridx<managed_type>::im :
  311.         public partial_policy::allow_invalid,
  312.         public partial_policy::template apply_cv_policy<std::remove_const>
  313. {
  314. };
  315.  
  316. template <typename managed_type>
  317. template <typename policy>
  318. class valptridx<managed_type>::idx :
  319.         public policy
  320. {
  321.         using containing_type = valptridx<managed_type>;
  322. public:
  323.         using policy::allow_nullptr;
  324.         using policy::check_allowed_invalid_index;
  325.         using index_type = typename containing_type::index_type;
  326.         using integral_type = typename containing_type::integral_type;
  327.         using typename policy::array_managed_type;
  328.         idx() = delete;
  329.         idx(const idx &) = default;
  330.         idx(idx &&) = default;
  331.         idx &operator=(const idx &) & = default;
  332.         idx &operator=(idx &&) & = default;
  333.         idx &operator=(const idx &) && = delete;
  334.         idx &operator=(idx &&) && = delete;
  335.  
  336.         index_type get_unchecked_index() const { return m_idx; }
  337.  
  338.         /* If moving from allow_invalid to allow_invalid, no check is
  339.          * needed.
  340.          * If moving from require_valid to anything, no check is needed.
  341.          */
  342.         template <typename rpolicy, typename std::enable_if<policy::allow_nullptr || !rpolicy::allow_nullptr, int>::type = 0>
  343.                 idx(const idx<rpolicy> &rhs) :
  344.                         m_idx(rhs.get_unchecked_index())
  345.         {
  346.         }
  347.         template <typename rpolicy, typename std::enable_if<!(policy::allow_nullptr || !rpolicy::allow_nullptr), int>::type = 0>
  348.                 idx(const idx<rpolicy> &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
  349.                         m_idx(rhs.get_unchecked_index())
  350.         {
  351.                 /* If moving from allow_invalid to require_valid, check range.
  352.                  */
  353.                 check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_idx, nullptr);
  354.         }
  355.         template <typename rpolicy>
  356.                 idx(idx<rpolicy> &&rhs) :
  357.                         m_idx(rhs.get_unchecked_index())
  358.         {
  359.                 /* Prevent move from allow_invalid into require_valid.  The
  360.                  * right hand side must be saved and checked for validity before
  361.                  * being used to initialize a require_valid type.
  362.                  */
  363.                 static_assert(policy::allow_nullptr || !rpolicy::allow_nullptr, "cannot move from allow_invalid to require_valid");
  364.         }
  365.         idx(index_type i DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
  366.                 m_idx(check_allowed_invalid_index(i) ? i : check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, nullptr))
  367.         {
  368.         }
  369.         idx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
  370.                 m_idx(check_allowed_invalid_index(i) ? i : check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a))
  371.         {
  372.         }
  373. protected:
  374.         template <integral_type v>
  375.                 idx(const magic_constant<v> &, const allow_none_construction *) :
  376.                         m_idx(v)
  377.         {
  378.                 static_assert(!allow_nullptr, "allow_none_construction used where nullptr was already legal");
  379.                 static_assert(static_cast<std::size_t>(v) >= array_size, "allow_none_construction used with valid index");
  380.         }
  381.         idx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *) :
  382.                 m_idx(check_index_range<index_range_error_type<array_managed_type>, std::less_equal>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a))
  383.         {
  384.         }
  385.         idx(index_type i, array_managed_type &, const assume_nothrow_index *) :
  386.                 m_idx(i)
  387.         {
  388.         }
  389. public:
  390.         template <integral_type v>
  391.                 constexpr idx(const magic_constant<v> &) :
  392.                         m_idx(v)
  393.         {
  394.                 static_assert(allow_nullptr || static_cast<std::size_t>(v) < array_size, "invalid magic index not allowed for this policy");
  395.         }
  396.         template <typename rpolicy>
  397.                 bool operator==(const idx<rpolicy> &rhs) const
  398.                 {
  399.                         return m_idx == rhs.get_unchecked_index();
  400.                 }
  401.         bool operator==(const index_type &i) const
  402.         {
  403.                 return m_idx == i;
  404.         }
  405.         template <integral_type v>
  406.                 bool operator==(const magic_constant<v> &) const
  407.                 {
  408.                         static_assert(allow_nullptr || static_cast<std::size_t>(v) < array_size, "invalid magic index not allowed for this policy");
  409.                         return m_idx == v;
  410.                 }
  411.         template <typename R>
  412.                 bool operator!=(const R &rhs) const
  413.                 {
  414.                         return !(*this == rhs);
  415.                 }
  416.         operator index_type() const
  417.         {
  418.                 return m_idx;
  419.         }
  420. protected:
  421.         index_type m_idx;
  422.         idx &operator++()
  423.         {
  424.                 ++ m_idx;
  425.                 return *this;
  426.         }
  427. };
  428.  
  429. template <typename managed_type>
  430. template <typename policy>
  431. class valptridx<managed_type>::ptr :
  432.         public policy
  433. {
  434.         using containing_type = valptridx<managed_type>;
  435. public:
  436.         using policy::allow_nullptr;
  437.         using policy::check_allowed_invalid_index;
  438.         using index_type = typename containing_type::index_type;
  439.         using const_pointer_type = typename containing_type::const_pointer_type;
  440.         using mutable_pointer_type = typename containing_type::mutable_pointer_type;
  441.         using allow_none_construction = typename containing_type::allow_none_construction;
  442.         using typename policy::array_managed_type;
  443.         using typename policy::pointer_type;
  444.         using typename policy::reference_type;
  445.  
  446.         ptr() = delete;
  447.         /* Override template matches to make same-type copy/move trivial */
  448.         ptr(const ptr &) = default;
  449.         ptr(ptr &&) = default;
  450.         ptr &operator=(const ptr &) & = default;
  451.         ptr &operator=(ptr &&) & = default;
  452.         ptr &operator=(const ptr &) && = delete;
  453.         ptr &operator=(ptr &&) && = delete;
  454.  
  455.         pointer_type get_unchecked_pointer() const { return m_ptr; }
  456.         pointer_type get_nonnull_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS) const
  457.         {
  458.                 /* If !allow_nullptr, assume nullptr was caught at construction.  */
  459.                 if (allow_nullptr)
  460.                         check_null_pointer_conversion<null_pointer_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_ptr);
  461.                 return m_ptr;
  462.         }
  463.         reference_type get_checked_reference(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS) const
  464.         {
  465.                 return *get_nonnull_pointer(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VA());
  466.         }
  467.  
  468.         ptr(std::nullptr_t) :
  469.                 m_ptr(nullptr)
  470.         {
  471.                 static_assert(allow_nullptr, "nullptr construction not allowed for this policy");
  472.         }
  473.         template <integral_type v>
  474.                 ptr(const magic_constant<v> &) :
  475.                         m_ptr(nullptr)
  476.         {
  477.                 static_assert(static_cast<std::size_t>(v) >= array_size, "valid magic index requires an array");
  478.                 static_assert(allow_nullptr || static_cast<std::size_t>(v) < array_size, "invalid magic index not allowed for this policy");
  479.         }
  480.         template <integral_type v>
  481.                 ptr(const magic_constant<v> &, array_managed_type &a) :
  482.                         m_ptr(&a[v])
  483.         {
  484.                 static_assert(static_cast<std::size_t>(v) < array_size, "valid magic index required when using array");
  485.         }
  486.         template <typename rpolicy, typename std::enable_if<policy::allow_nullptr || !rpolicy::allow_nullptr, int>::type = 0>
  487.                 ptr(const ptr<rpolicy> &rhs) :
  488.                         m_ptr(rhs.get_unchecked_pointer())
  489.         {
  490.         }
  491.         template <typename rpolicy, typename std::enable_if<!(policy::allow_nullptr || !rpolicy::allow_nullptr), int>::type = 0>
  492.                 ptr(const ptr<rpolicy> &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
  493.                         m_ptr(rhs.get_unchecked_pointer())
  494.         {
  495.                 check_null_pointer_conversion<null_pointer_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS m_ptr);
  496.         }
  497.         template <typename rpolicy>
  498.                 ptr(ptr<rpolicy> &&rhs) :
  499.                         m_ptr(rhs.get_unchecked_pointer())
  500.         {
  501.                 /* Prevent move from allow_invalid into require_valid.  The
  502.                  * right hand side must be saved and checked for validity before
  503.                  * being used to initialize a require_valid type.
  504.                  */
  505.                 static_assert(policy::allow_nullptr || !rpolicy::allow_nullptr, "cannot move from allow_invalid to require_valid");
  506.         }
  507.         ptr(index_type i) = delete;
  508.         ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
  509.                 m_ptr(check_allowed_invalid_index(i) ? nullptr : &a[check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a)])
  510.         {
  511.         }
  512.         ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *) :
  513.                 m_ptr(&a[check_index_range<index_range_error_type<array_managed_type>, std::less_equal>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, &a)])
  514.         {
  515.         }
  516.         ptr(index_type i, array_managed_type &a, const assume_nothrow_index *) :
  517.                 m_ptr(&a[i])
  518.         {
  519.         }
  520.         ptr(pointer_type p) = delete;
  521.         ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS pointer_type p, array_managed_type &a) :
  522.                 /* No array consistency check here, since some code incorrectly
  523.                  * defines instances of `object` outside the Objects array, then
  524.                  * passes pointers to those instances to this function.
  525.                  */
  526.                 m_ptr(p)
  527.         {
  528.                 if (!allow_nullptr)
  529.                         check_null_pointer<null_pointer_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
  530.         }
  531.         ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS reference_type r, array_managed_type &a) :
  532.                 m_ptr((check_implicit_index_range_ref<index_mismatch_error_type<array_managed_type>, index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, a), &r))
  533.         {
  534.         }
  535.         ptr(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS reference_type r, index_type i, array_managed_type &a) :
  536.                 m_ptr((check_explicit_index_range_ref<index_mismatch_error_type<array_managed_type>, index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS r, i, a), &r))
  537.         {
  538.         }
  539.  
  540.         operator mutable_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated
  541.         operator const_pointer_type() const { return m_ptr; }   // implicit pointer conversion deprecated
  542.         template <typename rpolicy>
  543.                 typename std::enable_if<!std::is_same<policy, rpolicy>::value, ptr>::type rebind_policy(ptr<rpolicy> &&rhs) const
  544.         {
  545.                 /* This method could be marked as `static`, but is non-static so
  546.                  * that callers must possess an instance of the target type.
  547.                  * This serves as a basic check against casts that could remove
  548.                  * `const` incorrectly.
  549.                  */
  550.                 return ptr(std::move(rhs), static_cast<const typename containing_type::rebind_policy *>(nullptr));
  551.         }
  552.         pointer_type operator->() const &
  553.         {
  554.                 return get_nonnull_pointer();
  555.         }
  556.         operator reference_type() const &
  557.         {
  558.                 return get_checked_reference();
  559.         }
  560.         reference_type operator*() const &
  561.         {
  562.                 return get_checked_reference();
  563.         }
  564.         explicit operator bool() const &
  565.         {
  566.                 return !(*this == nullptr);
  567.         }
  568.         pointer_type operator->() const &&
  569.         {
  570.                 static_assert(!allow_nullptr, "operator-> not allowed with allow_invalid policy");
  571.                 return operator->();
  572.         }
  573.         operator reference_type() const &&
  574.         {
  575.                 static_assert(!allow_nullptr, "implicit reference not allowed with allow_invalid policy");
  576.                 return *this;
  577.         }
  578.         reference_type operator*() const &&
  579.         {
  580.                 static_assert(!allow_nullptr, "operator* not allowed with allow_invalid policy");
  581.                 return *this;
  582.         }
  583.         explicit operator bool() const && = delete;
  584.         bool operator==(std::nullptr_t) const
  585.         {
  586.                 static_assert(allow_nullptr, "nullptr comparison not allowed: value is never null");
  587.                 return m_ptr == nullptr;
  588.         }
  589.         bool operator==(const_pointer_type p) const
  590.         {
  591.                 return m_ptr == p;
  592.         }
  593.         bool operator==(mutable_pointer_type p) const
  594.         {
  595.                 return m_ptr == p;
  596.         }
  597.         template <typename rpolicy>
  598.                 bool operator==(const ptr<rpolicy> &rhs) const
  599.                 {
  600.                         return *this == rhs.get_unchecked_pointer();
  601.                 }
  602.         template <typename R>
  603.                 bool operator!=(const R &rhs) const
  604.                 {
  605.                         return !(*this == rhs);
  606.                 }
  607.         template <typename U>
  608.                 long operator-(U) const = delete;
  609.         template <typename R>
  610.                 bool operator<(R) const = delete;
  611.         template <typename R>
  612.                 bool operator>(R) const = delete;
  613.         template <typename R>
  614.                 bool operator<=(R) const = delete;
  615.         template <typename R>
  616.                 bool operator>=(R) const = delete;
  617. protected:
  618.         pointer_type m_ptr;
  619.         ptr &operator++()
  620.         {
  621.                 ++ m_ptr;
  622.                 return *this;
  623.         }
  624.         ptr(const allow_none_construction *) :
  625.                 m_ptr(nullptr)
  626.         {
  627.                 static_assert(!allow_nullptr, "allow_none_construction used where nullptr was already legal");
  628.         }
  629.         template <typename rpolicy>
  630.                 ptr(ptr<rpolicy> &&rhs, const typename containing_type::rebind_policy *) :
  631.                         m_ptr(const_cast<managed_type *>(rhs.get_unchecked_pointer()))
  632.         {
  633.                 static_assert(allow_nullptr || !rpolicy::allow_nullptr, "cannot rebind from allow_invalid to require_valid");
  634.         }
  635. };
  636.  
  637. #if DXX_VALPTRIDX_ENFORCE_STRICT_PI_SEPARATION
  638. template <typename T>
  639. struct strong_typedef : T
  640. {
  641.         using T::T;
  642.         template <typename O, typename std::enable_if<std::is_constructible<T, O &&>::value, int>::type = 0>
  643.                 strong_typedef(O &&o) :
  644.                         T(std::forward<O>(o))
  645.         {
  646.         }
  647.         strong_typedef() = default;
  648.         strong_typedef(const strong_typedef &) = default;
  649.         strong_typedef(strong_typedef &&) = default;
  650.         strong_typedef &operator=(const strong_typedef &) & = default;
  651.         strong_typedef &operator=(strong_typedef &&) & = default;
  652.         strong_typedef &operator=(const strong_typedef &) && = delete;
  653.         strong_typedef &operator=(strong_typedef &&) && = delete;
  654. };
  655. #endif
  656.  
  657. template <typename managed_type>
  658. template <typename policy>
  659. class valptridx<managed_type>::ptridx :
  660.         public prohibit_void_ptr<ptridx<policy>>,
  661.         public ptr<policy>,
  662.         public idx<policy>
  663. {
  664.         using containing_type = valptridx<managed_type>;
  665. public:
  666.         using vptr_type = ptr<policy>;
  667.         using vidx_type = idx<policy>;
  668.         using typename vidx_type::array_managed_type;
  669.         using index_type = typename vidx_type::index_type;
  670.         using typename vidx_type::integral_type;
  671.         using typename vptr_type::pointer_type;
  672.         using vidx_type::operator==;
  673.         using vptr_type::operator==;
  674.         ptridx(const ptridx &) = default;
  675.         ptridx(ptridx &&) = default;
  676.         ptridx &operator=(const ptridx &) & = default;
  677.         ptridx &operator=(ptridx &&) & = default;
  678.         ptridx &operator=(const ptridx &) && = delete;
  679.         ptridx &operator=(ptridx &&) && = delete;
  680.         ptridx(std::nullptr_t) = delete;
  681.         /* Prevent implicit conversion.  Require use of the factory function.
  682.          */
  683.         ptridx(pointer_type p) = delete;
  684.         template <typename rpolicy, typename std::enable_if<policy::allow_nullptr || !rpolicy::allow_nullptr, int>::type = 0>
  685.                 ptridx(const ptridx<rpolicy> &rhs) :
  686.                         vptr_type(static_cast<const typename ptridx<rpolicy>::vptr_type &>(rhs)),
  687.                         vidx_type(static_cast<const typename ptridx<rpolicy>::vidx_type &>(rhs))
  688.         {
  689.         }
  690.         template <typename rpolicy, typename std::enable_if<!(policy::allow_nullptr || !rpolicy::allow_nullptr), int>::type = 0>
  691.                 ptridx(const ptridx<rpolicy> &rhs DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) :
  692.                         vptr_type(static_cast<const typename ptridx<rpolicy>::vptr_type &>(rhs) DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_PASS_VARS),
  693.                         vidx_type(static_cast<const typename ptridx<rpolicy>::vidx_type &>(rhs) DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_PASS_VARS)
  694.         {
  695.         }
  696.         template <typename rpolicy>
  697.                 ptridx(ptridx<rpolicy> &&rhs) :
  698.                         vptr_type(static_cast<typename ptridx<rpolicy>::vptr_type &&>(rhs)),
  699.                         vidx_type(static_cast<typename ptridx<rpolicy>::vidx_type &&>(rhs))
  700.         {
  701.         }
  702.         template <integral_type v>
  703.                 ptridx(const magic_constant<v> &m) :
  704.                         vptr_type(m),
  705.                         vidx_type(m)
  706.         {
  707.         }
  708.         template <integral_type v>
  709.                 ptridx(const magic_constant<v> &m, array_managed_type &a) :
  710.                         vptr_type(m, a),
  711.                         vidx_type(m)
  712.         {
  713.         }
  714.         template <integral_type v>
  715.                 ptridx(const magic_constant<v> &m, const allow_none_construction *const n) :
  716.                         vptr_type(n),
  717.                         vidx_type(m, n)
  718.         {
  719.         }
  720.         ptridx(index_type i) = delete;
  721.         ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a) :
  722.                 vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a),
  723.                 vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a)
  724.         {
  725.         }
  726.         ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS index_type i, array_managed_type &a, const allow_end_construction *e) :
  727.                 vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a, e),
  728.                 vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a, e)
  729.         {
  730.         }
  731.         ptridx(index_type i, array_managed_type &a, const assume_nothrow_index *e) :
  732.                 vptr_type(i, a, e),
  733.                 vidx_type(i, a, e)
  734.         {
  735.         }
  736.         ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS pointer_type p, array_managed_type &a) :
  737.                 /* Null pointer is never allowed when an index must be computed.
  738.                  * Check for null, then use the reference constructor for
  739.                  * vptr_type to avoid checking again.
  740.                  */
  741.                 vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS (check_null_pointer<null_pointer_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a), *p), a),
  742.                 vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p - static_cast<pointer_type>(&a.front()), a)
  743.         {
  744.         }
  745.         ptridx(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS pointer_type p, index_type i, array_managed_type &a) :
  746.                 vptr_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS (check_null_pointer<null_pointer_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a), *p), i, a),
  747.                 vidx_type(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a)
  748.         {
  749.         }
  750.         template <typename rpolicy>
  751.                 typename std::enable_if<!std::is_same<policy, rpolicy>::value, ptridx>::type rebind_policy(ptridx<rpolicy> &&rhs) const
  752.         {
  753.                 return ptridx(std::move(rhs), static_cast<const typename containing_type::rebind_policy *>(nullptr));
  754.         }
  755.         ptridx absolute_sibling(const index_type i DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
  756.         {
  757.                 static_assert(!policy::allow_nullptr, "absolute_sibling not allowed with invalid ptridx");
  758.                 ptridx r(*this);
  759.                 r.m_ptr += check_index_range<index_range_error_type<array_managed_type>>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, nullptr) - this->m_idx;
  760.                 r.m_idx = i;
  761.                 return r;
  762.         }
  763.         template <typename rpolicy>
  764.                 bool operator==(const ptridx<rpolicy> &rhs) const
  765.                 {
  766.                         return vptr_type::operator==(static_cast<const typename ptridx<rpolicy>::vptr_type &>(rhs));
  767.                 }
  768.         template <typename R>
  769.                 bool operator!=(const R &rhs) const
  770.                 {
  771.                         return !(*this == rhs);
  772.                 }
  773. protected:
  774.         ptridx &operator++()
  775.         {
  776.                 vptr_type::operator++();
  777.                 vidx_type::operator++();
  778.                 return *this;
  779.         }
  780.         template <typename rpolicy>
  781.                 ptridx(ptridx<rpolicy> &&rhs, const typename containing_type::rebind_policy *const rebind) :
  782.                         vptr_type(static_cast<typename ptridx<rpolicy>::vptr_type &&>(rhs), rebind),
  783.                         vidx_type(static_cast<typename ptridx<rpolicy>::vidx_type &&>(rhs))
  784.         {
  785.                 /* No static_assert for policy compatibility.  Incompatible
  786.                  * policy conversions will be trapped by the static_assert in
  787.                  * `vptr_type`.
  788.                  */
  789.         }
  790. };
  791.  
  792. template <typename managed_type>
  793. template <typename guarded_type>
  794. class valptridx<managed_type>::guarded
  795. {
  796.         static_assert(std::is_trivially_destructible<guarded_type>::value, "non-trivial destructor found for guarded_type");
  797.         enum state : uint8_t
  798.         {
  799.                 /* empty - the untrusted input was invalid, so no guarded_type
  800.                  * exists
  801.                  */
  802.                 empty,
  803.                 /* initialized - the untrusted input was valid, so a
  804.                  * guarded_type type exists, but the calling code has not yet
  805.                  * tested the state of this guarded<P>
  806.                  */
  807.                 initialized,
  808.                 /* checked - the untrusted input was valid, and the calling code
  809.                  * has called operator bool()
  810.                  */
  811.                 checked,
  812.         };
  813.         union {
  814.                 state m_dummy;
  815.                 guarded_type m_value;
  816.         };
  817.         mutable state m_state;
  818. public:
  819.         __attribute_cold
  820.         guarded(std::nullptr_t) :
  821.                 m_dummy(), m_state(empty)
  822.         {
  823.         }
  824.         guarded(guarded_type &&v) :
  825.                 m_value(std::move(v)), m_state(initialized)
  826.         {
  827.         }
  828.         __attribute_warn_unused_result
  829.         explicit operator bool() const
  830.         {
  831.                 /*
  832.                  * If no contained guarded_type exists, return false.
  833.                  * Otherwise, record that the result has been tested and then
  834.                  * return true.  operator*() uses m_state to enforce that the
  835.                  * result is tested.
  836.                  */
  837.                 if (unlikely(m_state == empty))
  838.                         return false;
  839.                 m_state = checked;
  840.                 return true;
  841.         }
  842.         __attribute_warn_unused_result
  843.         guarded_type operator*() const &
  844.         {
  845.                 /*
  846.                  * Correct code will always execute as if this method was just
  847.                  * the return statement, with none of the sanity checks.  The
  848.                  * checks are present to catch misuse of this type, preferably
  849.                  * at compile-time, but at least at runtime.
  850.                  */
  851. #define DXX_VALPTRIDX_GUARDED_OBJECT_NO "access to guarded object that does not exist"
  852. #define DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE      "access to guarded object that may not exist"
  853. #ifdef DXX_CONSTANT_TRUE
  854.                 {
  855.                         /*
  856.                          * If the validity has not been verified by the caller, then
  857.                          * fail.  Choose an error message and function name
  858.                          * based on whether the contained type provably does not
  859.                          * exist.  It provably does not exist if this call is on a
  860.                          * path where operator bool() returned false.  It
  861.                          * conditionally might not exist if this call is on a path
  862.                          * where operator bool() has not been called.
  863.                          */
  864.                         if (DXX_CONSTANT_TRUE(m_state == empty))
  865.                                 DXX_ALWAYS_ERROR_FUNCTION(guarded_accessed_empty, DXX_VALPTRIDX_GUARDED_OBJECT_NO);
  866.                         /* If the contained object might not exist: */
  867.                         if (DXX_CONSTANT_TRUE(m_state == initialized))
  868.                                 DXX_ALWAYS_ERROR_FUNCTION(guarded_accessed_unchecked, DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE);
  869.                 }
  870. #endif
  871.                 /*
  872.                  * If the compiler does not offer constant truth analysis
  873.                  * (perhaps because of insufficient optimization), then emit a
  874.                  * runtime check for whether the guarded_type exists.
  875.                  *
  876.                  * This test can throw even if the contained object is valid, if
  877.                  * the caller did not first validate that the contained object
  878.                  * is valid.  This restriction is necessary since inputs are
  879.                  * usually valid even when untested, so throwing only on state
  880.                  * `empty` would allow incorrect usage to persist in the code
  881.                  * until someone happened to receive an invalid input from an
  882.                  * untrusted source.
  883.                  */
  884.                 if (m_state != checked)
  885.                         throw std::logic_error(m_state == empty ? DXX_VALPTRIDX_GUARDED_OBJECT_NO : DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE);
  886. #undef DXX_VALPTRIDX_GUARDED_OBJECT_MAYBE
  887. #undef DXX_VALPTRIDX_GUARDED_OBJECT_NO
  888.                 return m_value;
  889.         }
  890.         guarded_type operator*() const && = delete;
  891. };
  892.  
  893. template <typename managed_type>
  894. class valptridx<managed_type>::array_managed_type :
  895.         public array_base_count_type,
  896.         public array_base_storage_type
  897. {
  898. public:
  899.         /*
  900.          * Expose the union members that act as factory methods.  Leave the
  901.          * `count` union member protected.
  902.          */
  903. #define DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES(MANAGED_TYPE, DERIVED_TYPE_PREFIX, CONTEXT, PISUFFIX, IVPREFIX, MCPREFIX) \
  904.         using array_base_count_type::IVPREFIX ## MCPREFIX ## PISUFFIX
  905.         DXX_VALPTRIDX_FOR_EACH_PPI_TYPE(DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES,,,);
  906. #undef DXX_VALPTRIDX_ACCESS_SUBTYPE_MEMBER_FACTORIES
  907.         using typename array_base_storage_type::reference;
  908.         using typename array_base_storage_type::const_reference;
  909.         reference operator[](const integral_type &n)
  910.                 {
  911.                         return array_base_storage_type::operator[](n);
  912.                 }
  913.         const_reference operator[](const integral_type &n) const
  914.                 {
  915.                         return array_base_storage_type::operator[](n);
  916.                 }
  917.         template <typename T>
  918.                 reference operator[](const T &) const = delete;
  919. #if DXX_HAVE_POISON_UNDEFINED
  920.         array_managed_type();
  921. #else
  922.         array_managed_type() = default;
  923. #endif
  924.         array_managed_type(const array_managed_type &) = delete;
  925.         array_managed_type &operator=(const array_managed_type &) = delete;
  926. };
  927.  
  928. template <typename managed_type>
  929. template <typename Pc, typename Pm>
  930. class valptridx<managed_type>::basic_ival_member_factory
  931. {
  932.         using containing_type = valptridx<managed_type>;
  933. protected:
  934.         /*
  935.          * These casts are well-defined:
  936.          * - The reinterpret_cast is defined because
  937.          *   `basic_ival_member_factory` is a base of a member of the
  938.          *   anonymous union in `array_base_count_type`.
  939.          * - The anonymous union in `array_base_count_type` is the only
  940.          *   member of that type, so its storage must be aligned to the
  941.          *   beginning of the object.
  942.          * - `basic_ival_member_factory` and its derivatives are not used
  943.          *   anywhere other than `array_base_count_type`, so any call to
  944.          *   these methods must be on an instance used in
  945.          *   `array_base_count_type`.
  946.          *
  947.          * - The static_cast is defined because `array_base_count_type` is a
  948.          *   non-virtual base of `array_managed_type`.
  949.          * - `array_base_count_type` is not used as a base for any class
  950.          *   other than `array_managed_type`, nor used freestanding, so any
  951.          *   instance of `array_base_count_type` must be safe to downcast to
  952.          *   `array_managed_type`.
  953.          */
  954.         constexpr const array_managed_type &get_array() const
  955.         {
  956.                 return static_cast<const array_managed_type &>(reinterpret_cast<const array_base_count_type &>(*this));
  957.         }
  958.         array_managed_type &get_array()
  959.         {
  960.                 return static_cast<array_managed_type &>(reinterpret_cast<array_base_count_type &>(*this));
  961.         }
  962.         template <typename P, typename A>
  963.                 static guarded<P> check_untrusted_internal(const index_type i, A &a)
  964.                 {
  965.                         if (P::check_nothrow_index(i))
  966.                                 return P(i, a, static_cast<const assume_nothrow_index *>(nullptr));
  967.                         else
  968.                                 return nullptr;
  969.                 }
  970.         template <typename P, typename T, typename A>
  971.                 static guarded<P> check_untrusted_internal(T &&, A &) = delete;
  972.         template <typename P, typename A>
  973.                 __attribute_warn_unused_result
  974.                 /* C++ does not allow `static operator()()`, so name it
  975.                  * `call_operator` instead.
  976.                  */
  977.                 static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename P::index_type i, A &a)
  978.                 {
  979.                         return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a);
  980.                 }
  981.         template <typename P, containing_type::integral_type v, typename A>
  982.                 __attribute_warn_unused_result
  983.                 static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const containing_type::magic_constant<v> &m, A &a)
  984.                 {
  985.                         /*
  986.                          * All call_operator definitions must have the macro which
  987.                          * defines filename/lineno, but the magic_constant overload
  988.                          * has no need for them.
  989.                          *
  990.                          * Cast them to void to silence the warning about unused
  991.                          * parameters.
  992.                          */
  993.                         DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_VOID_VARS();
  994.                         return P(m, a);
  995.                 }
  996.         template <typename P, typename T, typename A>
  997.                 static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS T &&, A &a) = delete;
  998.         basic_ival_member_factory() = default;
  999. public:
  1000.         basic_ival_member_factory(const basic_ival_member_factory &) = delete;
  1001.         basic_ival_member_factory &operator=(const basic_ival_member_factory &) = delete;
  1002.         void *operator &() const = delete;
  1003.         template <typename T>
  1004.                 __attribute_warn_unused_result
  1005.                 guarded<Pc> check_untrusted(T &&t) const
  1006.                 {
  1007.                         return this->template check_untrusted_internal<Pc>(static_cast<T &&>(t), get_array());
  1008.                 }
  1009.         template <typename T>
  1010.                 __attribute_warn_unused_result
  1011.                 guarded<Pm> check_untrusted(T &&t)
  1012.                 {
  1013.                         return this->template check_untrusted_internal<Pm>(static_cast<T &&>(t), get_array());
  1014.                 }
  1015.         template <typename T>
  1016.                 __attribute_warn_unused_result
  1017.                 Pc operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
  1018.                 {
  1019.                         return this->template call_operator<Pc>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast<T &&>(t), get_array());
  1020.                 }
  1021.         template <typename T>
  1022.                 __attribute_warn_unused_result
  1023.                 Pm operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS)
  1024.                 {
  1025.                         return this->template call_operator<Pm>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast<T &&>(t), get_array());
  1026.                 }
  1027. };
  1028.  
  1029. template <typename managed_type>
  1030. template <typename Pc, typename Pm>
  1031. class valptridx<managed_type>::basic_vval_member_factory :
  1032.         public basic_ival_member_factory<Pc, Pm>
  1033. {
  1034. protected:
  1035.         using basic_ival_member_factory<Pc, Pm>::get_array;
  1036.         using basic_ival_member_factory<Pc, Pm>::call_operator;
  1037.         template <typename P>
  1038.                 using iterator = self_return_iterator<P>;
  1039.         template <typename P, typename policy, typename A>
  1040.                 static P call_operator(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS const typename valptridx<managed_type>::template wrapper<valptridx<managed_type>::idx<policy>> i, A &a)
  1041.                 {
  1042.                         return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS i, a);
  1043.                 }
  1044.         template <typename P>
  1045.                 __attribute_warn_unused_result
  1046.                 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)
  1047.                 {
  1048.                         return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
  1049.                 }
  1050.         /*
  1051.          * When P is a const type, enable an overload that takes a const
  1052.          * array.  Otherwise, enable a deleted overload that takes a mutable
  1053.          * array.  This provides a slightly clearer error when trying to
  1054.          * pass a const pointer to a mutable factory.
  1055.          */
  1056.         template <typename P>
  1057.                 __attribute_warn_unused_result
  1058.                 static typename std::enable_if<std::is_same<const array_managed_type, typename P::array_managed_type>::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)
  1059.                 {
  1060.                         return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS p, a);
  1061.                 }
  1062.         template <typename P>
  1063.                 static typename std::enable_if<!std::is_same<const array_managed_type, typename P::array_managed_type>::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;
  1064.         template <typename P, typename A>
  1065.                 static iterator<P> end_internal(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_DEFN_VARS A &a)
  1066.                 {
  1067.                         return P(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast<index_type>(a.get_count()), a, static_cast<const allow_end_construction *>(nullptr));
  1068.                 }
  1069. public:
  1070.         __attribute_warn_unused_result
  1071.         typename array_base_storage_type::size_type count() const
  1072.         {
  1073.                 return get_array().get_count();
  1074.         }
  1075.         __attribute_warn_unused_result
  1076.         typename array_base_storage_type::size_type size() const
  1077.         {
  1078.                 return get_array().size();
  1079.         }
  1080.         template <typename T>
  1081.                 __attribute_warn_unused_result
  1082.                 Pc operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS) const
  1083.                 {
  1084.                         return this->template call_operator<Pc>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast<T &&>(t), get_array());
  1085.                 }
  1086.         template <typename T>
  1087.                 __attribute_warn_unused_result
  1088.                 Pm operator()(T &&t DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_L_DECL_VARS)
  1089.                 {
  1090.                         return this->template call_operator<Pm>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS static_cast<T &&>(t), get_array());
  1091.                 }
  1092.         __attribute_warn_unused_result
  1093.         iterator<Pc> begin() const
  1094.         {
  1095.                 return Pc(valptridx<managed_type>::magic_constant<0>(), get_array());
  1096.         }
  1097.         __attribute_warn_unused_result
  1098.         iterator<Pm> begin()
  1099.         {
  1100.                 return Pm(valptridx<managed_type>::magic_constant<0>(), get_array());
  1101.         }
  1102.         __attribute_warn_unused_result
  1103.         iterator<Pc> end(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS) const
  1104.         {
  1105.                 return this->template end_internal<Pc>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS get_array());
  1106.         }
  1107.         __attribute_warn_unused_result
  1108.         iterator<Pm> end(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_N_DECL_VARS)
  1109.         {
  1110.                 return this->template end_internal<Pm>(DXX_VALPTRIDX_REPORT_STANDARD_LEADER_COMMA_R_PASS_VARS get_array());
  1111.         }
  1112. };
  1113.  
  1114. #define DXX_VALPTRIDX_DEFINE_FACTORY(MANAGED_TYPE, GLOBAL_FACTORY, GLOBAL_ARRAY, MEMBER_FACTORY)        \
  1115.         __attribute_unused static auto &GLOBAL_FACTORY = GLOBAL_ARRAY.MEMBER_FACTORY
  1116.  
  1117. #define DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORY(MANAGED_TYPE, DERIVED_TYPE_PREFIX, GLOBAL_ARRAY, PISUFFIX, IVPREFIX, MCPREFIX)      \
  1118.         DXX_VALPTRIDX_DEFINE_FACTORY(MANAGED_TYPE, IVPREFIX ## MCPREFIX ## DERIVED_TYPE_PREFIX ## PISUFFIX, GLOBAL_ARRAY, IVPREFIX ## MCPREFIX ## PISUFFIX)
  1119.  
  1120. #define DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORIES(MANAGED_TYPE,DERIVED_TYPE_PREFIX,GLOBAL_ARRAY)    \
  1121.         extern MANAGED_TYPE ## _array GLOBAL_ARRAY;     \
  1122.         namespace { namespace { \
  1123.         DXX_VALPTRIDX_FOR_EACH_PPI_TYPE(DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORY, MANAGED_TYPE, DERIVED_TYPE_PREFIX, GLOBAL_ARRAY);  \
  1124.         } }
  1125.  
  1126.