File indexing completed on 2025-10-24 09:01:49
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <cstddef>
0010 #include <functional>
0011 #include <type_traits>
0012
0013 #include "Assert.hh"
0014 #include "Macros.hh"
0015 #include "Types.hh"
0016
0017 namespace celeritas
0018 {
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template<class ValueT, class SizeT = ::celeritas::size_type>
0042 class OpaqueId
0043 {
0044 static_assert(std::is_unsigned_v<SizeT> && !std::is_same_v<SizeT, bool>,
0045 "SizeT must be unsigned.");
0046
0047 public:
0048
0049
0050 using value_type = ValueT;
0051 using size_type = SizeT;
0052
0053
0054 public:
0055
0056 CELER_CONSTEXPR_FUNCTION OpaqueId() : value_(OpaqueId::invalid_value()) {}
0057
0058
0059 explicit CELER_CONSTEXPR_FUNCTION OpaqueId(size_type index) : value_(index)
0060 {
0061 }
0062
0063
0064 explicit CELER_CONSTEXPR_FUNCTION operator bool() const
0065 {
0066 return value_ != invalid_value();
0067 }
0068
0069
0070 CELER_FUNCTION OpaqueId& operator++()
0071 {
0072 CELER_EXPECT(*this);
0073 value_ += 1;
0074 return *this;
0075 }
0076
0077
0078 CELER_FUNCTION OpaqueId operator++(int)
0079 {
0080 OpaqueId old{*this};
0081 ++*this;
0082 return old;
0083 }
0084
0085
0086 CELER_FUNCTION OpaqueId& operator--()
0087 {
0088 CELER_EXPECT(*this && value_ > 0);
0089 value_ -= 1;
0090 return *this;
0091 }
0092
0093
0094 CELER_FUNCTION OpaqueId operator--(int)
0095 {
0096 OpaqueId old{*this};
0097 --*this;
0098 return old;
0099 }
0100
0101
0102 CELER_FORCEINLINE_FUNCTION size_type get() const
0103 {
0104 CELER_EXPECT(*this);
0105 return value_;
0106 }
0107
0108
0109 CELER_CONSTEXPR_FUNCTION size_type unchecked_get() const { return value_; }
0110
0111
0112 CELER_CONSTEXPR_FUNCTION size_type const* data() const { return &value_; }
0113
0114 private:
0115 size_type value_;
0116
0117
0118
0119
0120 static CELER_CONSTEXPR_FUNCTION size_type invalid_value()
0121 {
0122 return static_cast<size_type>(-1);
0123 }
0124 };
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 template<class IdT, class T>
0139 inline CELER_FUNCTION IdT id_cast(T value) noexcept(!CELERITAS_DEBUG)
0140 {
0141 static_assert(std::is_integral_v<T>);
0142 if constexpr (!std::is_unsigned_v<T>)
0143 {
0144 CELER_EXPECT(value >= 0);
0145 }
0146
0147 using IdSize = typename IdT::size_type;
0148 if constexpr (!std::is_same_v<T, IdSize>)
0149 {
0150
0151 using U = std::common_type_t<IdSize, std::make_unsigned_t<T>>;
0152 CELER_EXPECT(static_cast<U>(value)
0153 < static_cast<U>(IdT{}.unchecked_get()));
0154 }
0155 else
0156 {
0157
0158 CELER_EXPECT(value != IdT{}.unchecked_get());
0159 }
0160
0161 return IdT{static_cast<IdSize>(value)};
0162 }
0163
0164
0165 #define CELER_DEFINE_OPAQUEID_CMP(TOKEN) \
0166 template<class V, class S> \
0167 CELER_CONSTEXPR_FUNCTION bool operator TOKEN(OpaqueId<V, S> lhs, \
0168 OpaqueId<V, S> rhs) \
0169 { \
0170 return lhs.unchecked_get() TOKEN rhs.unchecked_get(); \
0171 }
0172
0173
0174
0175 CELER_DEFINE_OPAQUEID_CMP(==)
0176 CELER_DEFINE_OPAQUEID_CMP(!=)
0177 CELER_DEFINE_OPAQUEID_CMP(<)
0178 CELER_DEFINE_OPAQUEID_CMP(>)
0179 CELER_DEFINE_OPAQUEID_CMP(<=)
0180 CELER_DEFINE_OPAQUEID_CMP(>=)
0181
0182
0183 #undef CELER_DEFINE_OPAQUEID_CMP
0184
0185
0186
0187 template<class V, class S, class U>
0188 CELER_CONSTEXPR_FUNCTION bool operator<(OpaqueId<V, S> lhs, U rhs)
0189 {
0190
0191 return lhs && (U(lhs.unchecked_get()) < rhs);
0192 }
0193
0194
0195
0196 template<class V, class S, class U>
0197 CELER_CONSTEXPR_FUNCTION bool operator<=(OpaqueId<V, S> lhs, U rhs)
0198 {
0199
0200 return lhs && (U(lhs.unchecked_get()) <= rhs);
0201 }
0202
0203
0204
0205 template<class V, class S>
0206 inline CELER_FUNCTION S operator-(OpaqueId<V, S> self, OpaqueId<V, S> other)
0207 {
0208 CELER_EXPECT(self);
0209 CELER_EXPECT(other);
0210 return self.unchecked_get() - other.unchecked_get();
0211 }
0212
0213
0214
0215 template<class V, class S>
0216 inline CELER_FUNCTION OpaqueId<V, S>
0217 operator+(OpaqueId<V, S> id, std::make_signed_t<S> offset)
0218 {
0219 CELER_EXPECT(id);
0220 CELER_EXPECT(offset >= 0 || static_cast<S>(-offset) <= id.unchecked_get());
0221 return OpaqueId<V, S>{id.unchecked_get() + static_cast<S>(offset)};
0222 }
0223
0224
0225
0226 template<class V, class S>
0227 inline CELER_FUNCTION OpaqueId<V, S>
0228 operator-(OpaqueId<V, S> id, std::make_signed_t<S> offset)
0229 {
0230 CELER_EXPECT(id);
0231 CELER_EXPECT(offset <= 0 || static_cast<S>(offset) <= id.unchecked_get());
0232 return OpaqueId<V, S>{id.unchecked_get() - static_cast<S>(offset)};
0233 }
0234
0235
0236 }
0237
0238
0239
0240 namespace std
0241 {
0242
0243 template<class V, class S>
0244 struct hash<celeritas::OpaqueId<V, S>>
0245 {
0246 std::size_t operator()(celeritas::OpaqueId<V, S> const& id) const noexcept
0247 {
0248 return std::hash<S>()(id.unchecked_get());
0249 }
0250 };
0251 }
0252