/*
* This file is part of the DXX-Rebirth project .
* 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 "dxxsconf.h"
#include
#include "fwd-d_array.h"
namespace dcx {
/* Wrap a std::array and override the normal indexing operations to take
* an instance of type `E`. This is intended for use where `E` is an
* instance of `enum class`. When `E` is an `enum class`, instances of
* `E` cannot implicitly convert to `std::array::size_type`, and so
* would require a cast in the caller if this wrapper were not used.
* Using this wrapper moves the casts into the wrapper, after the
* compiler has checked that the argument is the right type of `enum
* class`. This prevents accidentally using an incorrect `enum class`.
*
* Other types for E are not likely to be useful, but are not blocked.
*/
template
/* `std::size_t` is `unsigned` on i686-w64-mingw32, and `unsigned long` on
* x86_64-pc-linux-gnu.
*
* As a result, if `E` is `unsigned`, then i686-w64-mingw32 breaks due to
* `operator[](E)` and `operator[](std::size_t)` being the same signature. If
* `E` is `unsigned long`, then x86_64-pc-linux-gnu breaks for the same reason.
* Disallow both `unsigned` and `unsigned long`, so that any attempt to use
* either for `E` will break everywhere, rather than breaking only some
* platforms.
*/
requires(!std::is_same::value && !std::is_same::value)
struct enumerated_array : std::array
{
using base_type = std::array;
using index_type = E;
using typename base_type::reference;
using typename base_type::const_reference;
constexpr reference at(E position)
{
return this->base_type::at(static_cast(position));
}
constexpr const_reference at(E position) const
{
return this->base_type::at(static_cast(position));
}
constexpr reference operator[](E position)
{
return this->base_type::operator[](static_cast(position));
}
constexpr const_reference operator[](E position) const
{
return this->base_type::operator[](static_cast(position));
}
template
requires(std::is_integral_v)
const_reference operator[](I) const = delete;
[[nodiscard]]
static constexpr bool valid_index(std::size_t s)
{
return s < N;
}
[[nodiscard]]
static constexpr bool valid_index(E e)
{
return valid_index(static_cast(e));
}
};
}