Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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