dxx-rebirth/common/include/valptridx.h

692 lines
21 KiB
C
Raw Normal View History

2014-06-01 17:55:23 +00:00
/*
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*/
#pragma once
#include <stdexcept>
2015-05-09 17:39:02 +00:00
#include <string>
#include "fwdvalptridx.h"
#include "compiler-static_assert.h"
#include "compiler-type_traits.h"
2014-12-14 05:23:00 +00:00
#include "pack.h"
#ifdef DXX_HAVE_BUILTIN_CONSTANT_P
2015-05-09 17:39:02 +00:00
#define DXX_VALPTRIDX_STATIC_CHECK(SUCCESS_CONDITION,FAILURE_FUNCTION,FAILURE_STRING) \
( \
static_cast<void>(dxx_builtin_constant_p(!(SUCCESS_CONDITION)) && !(SUCCESS_CONDITION) && \
(DXX_ALWAYS_ERROR_FUNCTION(FAILURE_FUNCTION, FAILURE_STRING), 0) \
) \
)
#else
2014-07-31 02:47:46 +00:00
#define DXX_VALPTRIDX_STATIC_CHECK(E,F,S) \
((void)0)
#endif
#ifdef DXX_HAVE_CXX11_REF_QUALIFIER
#define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE &
#else
#define DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
#endif
2015-05-09 17:39:02 +00:00
#define DXX_VALPTRIDX_CHECK(SUCCESS_CONDITION,EXCEPTION,FAILURE_STRING,...) \
( \
2015-05-09 17:39:02 +00:00
static_cast<void>(DXX_VALPTRIDX_STATIC_CHECK((SUCCESS_CONDITION), dxx_trap_##EXCEPTION, FAILURE_STRING), \
(SUCCESS_CONDITION) || (EXCEPTION::report(__VA_ARGS__), 0) \
2015-05-09 17:39:02 +00:00
) \
)
2015-05-09 17:39:02 +00:00
class valptridxutil_untyped_base
{
public:
class index_mismatch_exception;
class index_range_exception;
class null_pointer_exception;
};
class valptridxutil_untyped_base::index_mismatch_exception
{
2015-05-09 17:39:02 +00:00
protected:
#define REPORT_STANDARD_FORMAT " base=%p size=%lu"
#define REPORT_STANDARD_ARGUMENTS array_base, array_size
#define REPORT_STANDARD_SIZE (sizeof(REPORT_FORMAT_STRING) + sizeof("0x0000000000000000") + sizeof("18446744073709551615"))
#define REPORT_FORMAT_STRING "pointer/index mismatch:" REPORT_STANDARD_FORMAT " index=%li expected=%p actual=%p"
static constexpr std::size_t report_buffer_size = REPORT_STANDARD_SIZE + (sizeof("0x0000000000000000") * 2) + sizeof("18446744073709551615");
2015-05-09 17:39:02 +00:00
__attribute_cold
static void prepare_report(char (&buf)[report_buffer_size], const void *const array_base, const std::size_t array_size, const long supplied_index, const void *const expected_pointer, const void *const actual_pointer)
2015-05-09 17:39:02 +00:00
{
snprintf(buf, sizeof(buf), REPORT_FORMAT_STRING, REPORT_STANDARD_ARGUMENTS, supplied_index, expected_pointer, actual_pointer);
}
#undef REPORT_FORMAT_STRING
};
class valptridxutil_untyped_base::index_range_exception
{
protected:
2015-05-09 17:39:02 +00:00
#define REPORT_FORMAT_STRING "invalid index used in array subscript:" REPORT_STANDARD_FORMAT " index=%li"
static constexpr std::size_t report_buffer_size = REPORT_STANDARD_SIZE + sizeof("18446744073709551615");
2015-05-09 17:39:02 +00:00
__attribute_cold
static void prepare_report(char (&buf)[report_buffer_size], const void *const array_base, const std::size_t array_size, const long supplied_index)
2015-05-09 17:39:02 +00:00
{
snprintf(buf, sizeof(buf), REPORT_FORMAT_STRING, REPORT_STANDARD_ARGUMENTS, supplied_index);
}
#undef REPORT_FORMAT_STRING
};
class valptridxutil_untyped_base::null_pointer_exception
{
protected:
2015-05-09 17:39:02 +00:00
#define REPORT_FORMAT_STRING "NULL pointer used:" REPORT_STANDARD_FORMAT
static constexpr std::size_t report_buffer_size = REPORT_STANDARD_SIZE;
2015-05-09 17:39:02 +00:00
__attribute_cold
static void prepare_report(char (&buf)[report_buffer_size], const void *const array_base, const std::size_t array_size)
2015-05-09 17:39:02 +00:00
{
snprintf(buf, sizeof(buf), REPORT_FORMAT_STRING, REPORT_STANDARD_ARGUMENTS);
}
#undef REPORT_FORMAT_STRING
#undef REPORT_STANDARD_SIZE
#undef REPORT_STANDARD_ARGUMENTS
#undef REPORT_STANDARD_FORMAT
};
template <typename P>
class valptridx<P>::index_mismatch_exception :
valptridxutil_untyped_base::index_mismatch_exception,
public std::logic_error
{
DXX_INHERIT_CONSTRUCTORS(index_mismatch_exception, logic_error);
public:
2015-05-09 17:39:02 +00:00
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t, index_type, const_pointer_type, const_pointer_type);
};
template <typename P>
class valptridx<P>::index_range_exception :
valptridxutil_untyped_base::index_range_exception,
public std::out_of_range
{
DXX_INHERIT_CONSTRUCTORS(index_range_exception, out_of_range);
public:
2015-05-09 17:39:02 +00:00
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t, long);
};
template <typename P>
class valptridx<P>::null_pointer_exception :
valptridxutil_untyped_base::null_pointer_exception,
public std::logic_error
{
DXX_INHERIT_CONSTRUCTORS(null_pointer_exception, logic_error);
public:
2015-05-09 17:39:02 +00:00
__attribute_cold
__attribute_noreturn
static void report(const_pointer_type, std::size_t);
2014-09-12 03:22:34 +00:00
};
template <typename managed_type>
void valptridx<managed_type>::index_mismatch_exception::report(const const_pointer_type array_base, const std::size_t array_size, const index_type supplied_index, const const_pointer_type expected_pointer, const const_pointer_type actual_pointer)
2015-05-09 17:39:02 +00:00
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size, supplied_index, expected_pointer, actual_pointer);
2015-05-09 17:39:02 +00:00
throw index_mismatch_exception(buf);
}
template <typename managed_type>
void valptridx<managed_type>::index_range_exception::report(const const_pointer_type array_base, const std::size_t array_size, const long supplied_index)
2015-05-09 17:39:02 +00:00
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size, supplied_index);
2015-05-09 17:39:02 +00:00
throw index_range_exception(buf);
}
template <typename managed_type>
void valptridx<managed_type>::null_pointer_exception::report(const const_pointer_type array_base, const std::size_t array_size)
2015-05-09 17:39:02 +00:00
{
char buf[report_buffer_size];
prepare_report(buf, array_base, array_size);
2015-05-09 17:39:02 +00:00
throw null_pointer_exception(buf);
}
template <typename managed_type>
void valptridx<managed_type>::check_index_match(const managed_type &r, index_type i, const array_managed_type &a)
{
const auto pi = &a[i];
DXX_VALPTRIDX_CHECK(pi == &r, index_mismatch_exception, "pointer/index mismatch", &a[0], a.size(), i, pi, &r);
}
2014-09-12 03:22:34 +00:00
template <typename managed_type>
typename valptridx<managed_type>::index_type valptridx<managed_type>::check_index_range(index_type i, const array_managed_type &a)
{
const std::size_t ss = i;
const std::size_t as = a.size();
DXX_VALPTRIDX_CHECK(ss < as, index_range_exception, "invalid index used in array subscript", &a[0], as, ss);
return i;
}
2014-09-12 03:22:34 +00:00
template <typename managed_type>
void valptridx<managed_type>::check_null_pointer(const_pointer_type p, const array_managed_type &a)
{
DXX_VALPTRIDX_CHECK(p, null_pointer_exception, "NULL pointer used", &a[0], a.size());
}
2014-10-02 03:02:34 +00:00
template <typename managed_type>
void valptridx<managed_type>::check_implicit_index_range_ref(const managed_type &r, const array_managed_type &a)
{
check_explicit_index_range_ref(r, &r - a, a);
}
2014-10-02 03:02:34 +00:00
template <typename managed_type>
void valptridx<managed_type>::check_explicit_index_range_ref(const managed_type &r, std::size_t i, const array_managed_type &a)
{
check_index_match(r, i, a);
check_index_range(i, a);
}
template <typename managed_type>
class valptridx<managed_type>::partial_policy::require_valid
2014-09-12 03:22:34 +00:00
{
2014-12-02 04:36:19 +00:00
public:
static constexpr tt::false_type allow_nullptr{};
static constexpr tt::false_type check_allowed_invalid_index(index_type) { return {}; }
};
template <typename managed_type>
class valptridx<managed_type>::partial_policy::allow_invalid
{
public:
static constexpr tt::true_type allow_nullptr{};
static constexpr bool check_allowed_invalid_index(index_type i)
2014-09-12 03:22:34 +00:00
{
return i == static_cast<index_type>(~0);
2014-09-12 03:22:34 +00:00
}
};
template <typename managed_type>
class valptridx<managed_type>::partial_policy::const_policy
{
2014-09-12 03:22:34 +00:00
protected:
template <typename T>
using apply_cv_qualifier = const T;
2014-09-12 03:22:34 +00:00
};
template <typename managed_type>
class valptridx<managed_type>::partial_policy::mutable_policy
2014-09-12 03:22:34 +00:00
{
protected:
template <typename T>
using apply_cv_qualifier = T;
};
template <typename managed_type>
template <typename policy>
class valptridx<managed_type>::partial_policy::apply_cv_policy :
policy
{
template <typename T>
using apply_cv_qualifier = typename policy::template apply_cv_qualifier<T>;
2014-09-12 03:22:34 +00:00
public:
using array_managed_type = apply_cv_qualifier<valptridx<managed_type>::array_managed_type>;
using pointer_type = apply_cv_qualifier<managed_type> *;
using reference_type = apply_cv_qualifier<managed_type> &;
};
template <typename managed_type>
class valptridx<managed_type>::vc :
public partial_policy::require_valid,
public partial_policy::template apply_cv_policy<typename partial_policy::const_policy>
{
};
template <typename managed_type>
class valptridx<managed_type>::vm :
public partial_policy::require_valid,
public partial_policy::template apply_cv_policy<typename partial_policy::mutable_policy>
{
};
template <typename managed_type>
class valptridx<managed_type>::ic :
public partial_policy::allow_invalid,
public partial_policy::template apply_cv_policy<typename partial_policy::const_policy>
{
};
template <typename managed_type>
class valptridx<managed_type>::im :
public partial_policy::allow_invalid,
public partial_policy::template apply_cv_policy<typename partial_policy::mutable_policy>
{
};
template <typename managed_type>
template <typename policy>
class valptridx<managed_type>::basic_idx :
public policy
{
using containing_type = valptridx<managed_type>;
public:
using policy::allow_nullptr;
using policy::check_allowed_invalid_index;
using index_type = typename containing_type::index_type;
using integral_type = typename containing_type::integral_type;
using typename policy::array_managed_type;
basic_idx() = delete;
basic_idx(const basic_idx &) = default;
basic_idx(basic_idx &&) = default;
basic_idx &operator=(const basic_idx &) = default;
basic_idx &operator=(basic_idx &&) = default;
index_type get_unchecked_index() const { return m_idx; }
template <typename rpolicy>
basic_idx(const basic_idx<rpolicy> &rhs, array_managed_type &a = get_array()) :
m_idx(rhs.get_unchecked_index())
{
if (!(allow_nullptr || !rhs.allow_nullptr))
check_index_range(m_idx, a);
}
template <typename rpolicy>
basic_idx(basic_idx<rpolicy> &&rhs) :
m_idx(rhs.get_unchecked_index())
2014-09-12 03:22:34 +00:00
{
/* Prevent move from allow_invalid into require_valid. The
* right hand side must be saved and checked for validity before
* being used to initialize a require_valid type.
*/
static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid");
2014-09-12 03:22:34 +00:00
}
basic_idx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated
m_idx(check_allowed_invalid_index(i) ? i : check_index_range(i, a))
2014-09-12 03:22:34 +00:00
{
}
template <integral_type v>
basic_idx(const magic_constant<v> &) :
m_idx(v)
{
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array().size(), "invalid magic index not allowed for this policy");
}
template <typename rpolicy>
bool operator==(const basic_idx<rpolicy> &rhs) const
{
return m_idx == rhs.get_unchecked_index();
}
bool operator==(const index_type &i) const
2014-09-12 03:22:34 +00:00
{
return m_idx == i;
2014-09-12 03:22:34 +00:00
}
template <integral_type v>
bool operator==(const magic_constant<v> &) const
{
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array().size(), "invalid magic index not allowed for this policy");
return m_idx == v;
}
template <typename R>
bool operator!=(const R &rhs) const
{
return !(*this == rhs);
}
operator index_type() const
2014-09-12 03:22:34 +00:00
{
return m_idx;
2014-09-12 03:22:34 +00:00
}
protected:
index_type m_idx;
2014-09-12 03:22:34 +00:00
};
template <typename managed_type>
template <typename policy>
class valptridx<managed_type>::basic_ptr :
public policy
Workaround compilers mishandling template-template arguments Visual Studio 2013 Update 4 and Clang 3.4 fail to parse valptridx_template_t related argument lists because they misinterpret the unspecialized inner template name as a reference to the current specialization. This seems to be nonconforming in C++11. All gcc versions supported by Rebirth parse this sample program correctly, but neither Visual Studio nor clang accept it. template <template <typename> class> struct A { }; template <typename> struct B { B(A<B>); }; In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer: Your code is legal. From the C++11 Standard, section 14.6.1: Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself. Looks like your version of clang is still implementing the old rule. This failure was first seen with Visual Studio 2013, but ignored because Visual Studio has so many other problems parsing Rebirth. Now that it has been reported to affect clang as well, a workaround is clearly needed. A fix was suggested by btb <https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>, but that fix breaks gcc. Rewrite the valptridx_template_t parameter passing to avoid mentioning unspecialized template names as template parameters while defining the class used as the parameter. Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
{
using containing_type = valptridx<managed_type>;
public:
using policy::allow_nullptr;
using policy::check_allowed_invalid_index;
using const_pointer_type = typename containing_type::const_pointer_type;
using mutable_pointer_type = typename containing_type::mutable_pointer_type;
using typename policy::array_managed_type;
using typename policy::pointer_type;
using typename policy::reference_type;
Workaround compilers mishandling template-template arguments Visual Studio 2013 Update 4 and Clang 3.4 fail to parse valptridx_template_t related argument lists because they misinterpret the unspecialized inner template name as a reference to the current specialization. This seems to be nonconforming in C++11. All gcc versions supported by Rebirth parse this sample program correctly, but neither Visual Studio nor clang accept it. template <template <typename> class> struct A { }; template <typename> struct B { B(A<B>); }; In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer: Your code is legal. From the C++11 Standard, section 14.6.1: Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself. Looks like your version of clang is still implementing the old rule. This failure was first seen with Visual Studio 2013, but ignored because Visual Studio has so many other problems parsing Rebirth. Now that it has been reported to affect clang as well, a workaround is clearly needed. A fix was suggested by btb <https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>, but that fix breaks gcc. Rewrite the valptridx_template_t parameter passing to avoid mentioning unspecialized template names as template parameters while defining the class used as the parameter. Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
basic_ptr() = delete;
/* Override template matches to make same-type copy/move trivial */
basic_ptr(const basic_ptr &) = default;
basic_ptr(basic_ptr &&) = default;
basic_ptr &operator=(const basic_ptr &) = default;
basic_ptr &operator=(basic_ptr &&) = default;
Workaround compilers mishandling template-template arguments Visual Studio 2013 Update 4 and Clang 3.4 fail to parse valptridx_template_t related argument lists because they misinterpret the unspecialized inner template name as a reference to the current specialization. This seems to be nonconforming in C++11. All gcc versions supported by Rebirth parse this sample program correctly, but neither Visual Studio nor clang accept it. template <template <typename> class> struct A { }; template <typename> struct B { B(A<B>); }; In <https://stackoverflow.com/questions/17687459/clang-not-accepting-use-of-template-template-parameter-when-using-crtp>, a user saw a similar failure and received the answer: Your code is legal. From the C++11 Standard, section 14.6.1: Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type- specifier of a friend class template declaration, it refers to the class template itself. Looks like your version of clang is still implementing the old rule. This failure was first seen with Visual Studio 2013, but ignored because Visual Studio has so many other problems parsing Rebirth. Now that it has been reported to affect clang as well, a workaround is clearly needed. A fix was suggested by btb <https://github.com/btb/dxx-rebirth/commit/2f9543f9812b584ecf1210dee0ac39f738ecd685>, but that fix breaks gcc. Rewrite the valptridx_template_t parameter passing to avoid mentioning unspecialized template names as template parameters while defining the class used as the parameter. Reported by btb (clang): https://github.com/dxx-rebirth/dxx-rebirth/pull/12
2014-11-30 23:44:52 +00:00
pointer_type get_unchecked_pointer() const { return m_ptr; }
basic_ptr(std::nullptr_t) :
m_ptr(nullptr)
2014-08-23 23:53:56 +00:00
{
static_assert(allow_nullptr, "nullptr construction not allowed for this policy");
2014-08-23 23:53:56 +00:00
}
2014-09-12 03:22:34 +00:00
template <integral_type v>
basic_ptr(const magic_constant<v> &) :
m_ptr(static_cast<std::size_t>(v) < get_array().size() ? &(get_array()[v]) : nullptr)
{
static_assert(allow_nullptr || static_cast<std::size_t>(v) < get_array().size(), "invalid magic index not allowed for this policy");
}
template <typename rpolicy>
basic_ptr(const basic_ptr<rpolicy> &rhs, array_managed_type &a = get_array()) :
m_ptr(rhs.get_unchecked_pointer())
{
if (!(allow_nullptr || !rhs.allow_nullptr))
check_null_pointer(m_ptr, a);
}
template <typename rpolicy>
basic_ptr(basic_ptr<rpolicy> &&rhs) :
m_ptr(rhs.get_unchecked_pointer())
{
/* Prevent move from allow_invalid into require_valid. The
* right hand side must be saved and checked for validity before
* being used to initialize a require_valid type.
*/
static_assert(allow_nullptr || !rhs.allow_nullptr, "cannot move from allow_invalid to require_valid");
}
basic_ptr(index_type i, array_managed_type &a = get_array()) :
m_ptr(check_allowed_invalid_index(i) ? nullptr : &a[check_index_range(i, a)])
{
}
basic_ptr(pointer_type p, array_managed_type &a = get_array()) :
m_ptr(p)
2014-09-12 03:22:34 +00:00
{
if (!allow_nullptr)
check_null_pointer(p, a);
2014-09-12 03:22:34 +00:00
}
basic_ptr(reference_type r, array_managed_type &a = get_array()) :
m_ptr((check_implicit_index_range_ref(r, a), &r))
{
}
basic_ptr(reference_type r, index_type i, array_managed_type &a = get_array()) :
m_ptr((check_explicit_index_range_ref(r, i, a), &r))
2014-09-12 03:22:34 +00:00
{
}
operator mutable_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated
operator const_pointer_type() const { return m_ptr; } // implicit pointer conversion deprecated
pointer_type operator->() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
{
return m_ptr;
}
operator reference_type() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
2014-10-02 03:02:34 +00:00
{
return *m_ptr;
2014-10-02 03:02:34 +00:00
}
reference_type operator*() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
{
return *this;
}
explicit operator bool() const DXX_VALPTRIDX_REF_QUALIFIER_LVALUE
2014-09-12 03:22:34 +00:00
{
return !(*this == nullptr);
2014-09-12 03:22:34 +00:00
}
#ifdef DXX_HAVE_CXX11_REF_QUALIFIER
pointer_type operator->() const &&
2014-11-23 04:58:45 +00:00
{
static_assert(!allow_nullptr, "operator-> not allowed with allow_invalid policy");
return operator->();
2014-11-23 04:58:45 +00:00
}
operator reference_type() const &&
2014-09-12 03:22:34 +00:00
{
static_assert(!allow_nullptr, "implicit reference not allowed with allow_invalid policy");
return *this;
2014-09-12 03:22:34 +00:00
}
reference_type operator*() const &&
2014-10-02 03:02:34 +00:00
{
static_assert(!allow_nullptr, "operator* not allowed with allow_invalid policy");
return *this;
2014-10-02 03:02:34 +00:00
}
explicit operator bool() const && = delete;
#endif
bool operator==(std::nullptr_t) const
2014-10-02 03:02:34 +00:00
{
static_assert(allow_nullptr, "nullptr comparison not allowed: value is never null");
return m_ptr == nullptr;
2014-10-02 03:02:34 +00:00
}
bool operator==(const_pointer_type p) const
2014-10-02 03:02:34 +00:00
{
return m_ptr == p;
2014-10-02 03:02:34 +00:00
}
bool operator==(mutable_pointer_type p) const
2014-10-02 03:02:34 +00:00
{
return m_ptr == p;
2014-10-02 03:02:34 +00:00
}
template <typename rpolicy>
bool operator==(const basic_ptr<rpolicy> &rhs) const
{
return *this == rhs.get_unchecked_pointer();
}
2014-10-02 03:02:34 +00:00
template <typename R>
bool operator!=(const R &rhs) const
{
return !(*this == rhs);
}
template <typename U>
long operator-(U) const = delete;
template <typename R>
bool operator<(R) const = delete;
template <typename R>
bool operator>(R) const = delete;
template <typename R>
bool operator<=(R) const = delete;
template <typename R>
bool operator>=(R) const = delete;
protected:
pointer_type m_ptr;
2014-09-12 03:22:34 +00:00
};
template <typename managed_type>
template <typename policy>
class valptridx<managed_type>::basic_ptridx :
public basic_ptr<policy>,
public basic_idx<policy>
2014-09-12 03:22:34 +00:00
{
using vptr_type = basic_ptr<policy>;
using vidx_type = basic_idx<policy>;
2014-09-12 03:22:34 +00:00
public:
using typename vidx_type::array_managed_type;
using typename vidx_type::index_type;
using typename vidx_type::integral_type;
using typename vptr_type::pointer_type;
using vidx_type::operator==;
using vptr_type::operator==;
basic_ptridx(const basic_ptridx &) = default;
basic_ptridx(basic_ptridx &&) = default;
basic_ptridx &operator=(const basic_ptridx &) = default;
basic_ptridx &operator=(basic_ptridx &&) = default;
basic_ptridx(std::nullptr_t) = delete;
/* Prevent implicit conversion. Require use of the factory function.
*/
basic_ptridx(pointer_type p) = delete;
template <typename rpolicy>
basic_ptridx(const basic_ptridx<rpolicy> &rhs) :
vptr_type(static_cast<const basic_ptr<rpolicy> &>(rhs)),
vidx_type(static_cast<const basic_idx<rpolicy> &>(rhs))
2014-08-23 23:53:56 +00:00
{
}
template <typename rpolicy>
basic_ptridx(basic_ptridx<rpolicy> &&rhs) :
vptr_type(static_cast<basic_ptr<rpolicy> &&>(rhs)),
vidx_type(static_cast<basic_idx<rpolicy> &&>(rhs))
{
}
template <integral_type v>
basic_ptridx(const magic_constant<v> &m, array_managed_type &a = get_array()) :
vptr_type(m, a),
vidx_type(m)
{
}
basic_ptridx(index_type i, array_managed_type &a = get_array()) : // default argument deprecated
vptr_type(i, a),
vidx_type(i, a)
{
}
basic_ptridx(pointer_type p, array_managed_type &a) :
/* Null pointer is never allowed when an index must be computed.
* Check for null, then use the reference constructor for
* vptr_type to avoid checking again.
*/
vptr_type((check_null_pointer(p, a), *p), a),
vidx_type(p - a, a)
{
}
basic_ptridx(pointer_type p, index_type i, array_managed_type &a = get_array(pointer_type())) :
vptr_type((check_null_pointer(p, a), *p), i, a),
vidx_type(i, a)
{
}
template <typename rpolicy>
bool operator==(const basic_ptridx<rpolicy> &rhs) const
{
return vptr_type::operator==(static_cast<const basic_ptr<rpolicy> &>(rhs));
}
template <typename R>
bool operator!=(const R &rhs) const
{
return !(*this == rhs);
}
};
template <typename P>
class valptridx<P>::cptr :
public prohibit_void_ptr<cptr>,
public basic_ptr<ic>
{
public:
DXX_INHERIT_CONSTRUCTORS(cptr, basic_ptr<ic>);
};
template <typename P>
class valptridx<P>::ptr :
public prohibit_void_ptr<ptr>,
public basic_ptr<im>
{
public:
DXX_INHERIT_CONSTRUCTORS(ptr, basic_ptr<im>);
};
template <typename P>
class valptridx<P>::vcptr :
public prohibit_void_ptr<vcptr>,
public basic_ptr<vc>
{
public:
DXX_INHERIT_CONSTRUCTORS(vcptr, basic_ptr<vc>);
};
template <typename P>
class valptridx<P>::vptr :
public prohibit_void_ptr<vptr>,
public basic_ptr<vm>
{
public:
DXX_INHERIT_CONSTRUCTORS(vptr, basic_ptr<vm>);
};
template <typename P>
class valptridx<P>::cptridx :
public prohibit_void_ptr<cptridx>,
public basic_ptridx<ic>
{
public:
DXX_INHERIT_CONSTRUCTORS(cptridx, basic_ptridx<ic>);
};
template <typename P>
class valptridx<P>::ptridx :
public prohibit_void_ptr<ptridx>,
public basic_ptridx<im>
{
public:
DXX_INHERIT_CONSTRUCTORS(ptridx, basic_ptridx<im>);
};
template <typename P>
class valptridx<P>::vcptridx :
public prohibit_void_ptr<vcptridx>,
public basic_ptridx<vc>
{
public:
DXX_INHERIT_CONSTRUCTORS(vcptridx, basic_ptridx<vc>);
};
template <typename P>
class valptridx<P>::vptridx :
public prohibit_void_ptr<vptridx>,
public basic_ptridx<vm>
2014-11-25 04:02:01 +00:00
{
public:
DXX_INHERIT_CONSTRUCTORS(vptridx, basic_ptridx<vm>);
};
template <typename managed_type>
template <typename vptr>
class valptridx<managed_type>::basic_vptr_global_factory
{
public:
__attribute_warn_unused_result
vptr operator()(typename vptr::const_pointer_type p) const
2015-05-09 17:38:58 +00:00
{
return vptr{p, get_array(p)};
2015-05-09 17:38:58 +00:00
}
__attribute_warn_unused_result
vptr operator()(typename vptr::mutable_pointer_type p) const
2014-11-25 04:02:01 +00:00
{
return vptr{p, get_array(p)};
2014-11-25 04:02:01 +00:00
}
__attribute_warn_unused_result
vptr operator()(typename valptridx<managed_type>::index_type i) const
2014-11-25 04:02:01 +00:00
{
return vptr{i, get_array()};
2014-11-25 04:02:01 +00:00
}
template <typename T>
vptr operator()(T) const = delete;
2015-06-13 22:42:15 +00:00
void *operator &() const = delete;
2014-11-25 04:02:01 +00:00
};
template <typename managed_type>
template <typename ptridx>
class valptridx<managed_type>::basic_ptridx_global_factory
2014-11-25 04:02:01 +00:00
{
using containing_type = valptridx<managed_type>;
public:
__attribute_warn_unused_result
2014-11-25 04:02:01 +00:00
ptridx operator()(typename ptridx::index_type i) const
{
return ptridx{i, get_array()};
2014-11-25 04:02:01 +00:00
}
template <containing_type::integral_type v>
__attribute_warn_unused_result
ptridx operator()(const containing_type::magic_constant<v> &m) const
{
return ptridx(m);
}
2014-11-25 04:02:01 +00:00
template <typename T>
ptridx operator()(T) const = delete;
2015-06-13 22:42:15 +00:00
void *operator &() const = delete;
2014-11-25 04:02:01 +00:00
};
2014-10-02 03:02:34 +00:00
#define _DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,prefix,Pconst) \
constexpr valptridx<P>::basic_vptr_global_factory<v##prefix##ptr_t> v##prefix##ptr{}; \
constexpr valptridx<P>::basic_ptridx_global_factory<prefix##ptridx_t> prefix##ptridx{}; \
constexpr valptridx<P>::basic_vptr_global_factory<v##prefix##ptridx_t> v##prefix##ptridx{}; \
2014-10-02 03:02:34 +00:00
static inline v##prefix##ptridx_t operator-(P Pconst *o, decltype(A) Pconst &O) \
{ \
return {o, static_cast<v##prefix##ptridx_t::integral_type>(const_cast<const P *>(o) - &(const_cast<const decltype(A) &>(O).front())), A}; \
} \
#define DEFINE_VALPTRIDX_SUBTYPE(N,P,I,A) \
2014-10-02 03:02:34 +00:00
static inline constexpr decltype(A) &get_global_array(P *) { return A; } \
/* "decltype(A) const &" parses correctly, but fails to match */ \
static inline constexpr typename tt::add_const<decltype(A)>::type &get_global_array(P const *) { return A; } \
\
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,N,); \
_DEFINE_VALPTRIDX_SUBTYPE_USERTYPE(N,P,I,A,c##N,const) \