capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

one-of.h (18467B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #pragma once
     23 
     24 #include "common.h"
     25 
     26 KJ_BEGIN_HEADER
     27 
     28 namespace kj {
     29 
     30 namespace _ {  // private
     31 
     32 template <uint i, template<uint> class Fail, typename Key, typename... Variants>
     33 struct TypeIndex_;
     34 template <uint i, template<uint> class Fail, typename Key, typename First, typename... Rest>
     35 struct TypeIndex_<i, Fail, Key, First, Rest...> {
     36   static constexpr uint value = TypeIndex_<i + 1, Fail, Key, Rest...>::value;
     37 };
     38 template <uint i, template<uint> class Fail, typename Key, typename... Rest>
     39 struct TypeIndex_<i, Fail, Key, Key, Rest...> { static constexpr uint value = i; };
     40 template <uint i, template<uint> class Fail, typename Key>
     41 struct TypeIndex_<i, Fail, Key>: public Fail<i> {};
     42 
     43 template <uint i>
     44 struct OneOfFailError_ {
     45   static_assert(i == -1, "type does not match any in OneOf");
     46 };
     47 template <uint i>
     48 struct OneOfFailZero_ {
     49   static constexpr int value = 0;
     50 };
     51 
     52 template <uint i>
     53 struct SuccessIfNotZero {
     54   typedef int Success;
     55 };
     56 template <>
     57 struct SuccessIfNotZero<0> {};
     58 
     59 enum class Variants0 {};
     60 enum class Variants1 { _variant0 };
     61 enum class Variants2 { _variant0, _variant1 };
     62 enum class Variants3 { _variant0, _variant1, _variant2 };
     63 enum class Variants4 { _variant0, _variant1, _variant2, _variant3 };
     64 enum class Variants5 { _variant0, _variant1, _variant2, _variant3, _variant4 };
     65 enum class Variants6 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5 };
     66 enum class Variants7 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6 };
     67 enum class Variants8 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     68                        _variant7 };
     69 enum class Variants9 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     70                        _variant7, _variant8 };
     71 enum class Variants10 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     72                         _variant7, _variant8, _variant9 };
     73 enum class Variants11 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     74                         _variant7, _variant8, _variant9, _variant10 };
     75 enum class Variants12 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     76                         _variant7, _variant8, _variant9, _variant10, _variant11 };
     77 enum class Variants13 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     78                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12 };
     79 enum class Variants14 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     80                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     81                         _variant13 };
     82 enum class Variants15 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     83                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     84                         _variant13, _variant14 };
     85 enum class Variants16 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     86                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     87                         _variant13, _variant14, _variant15 };
     88 enum class Variants17 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     89                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     90                         _variant13, _variant14, _variant15, _variant16 };
     91 enum class Variants18 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     92                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     93                         _variant13, _variant14, _variant15, _variant16, _variant17 };
     94 enum class Variants19 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     95                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     96                         _variant13, _variant14, _variant15, _variant16, _variant17, _variant18 };
     97 enum class Variants20 { _variant0, _variant1, _variant2, _variant3, _variant4, _variant5, _variant6,
     98                         _variant7, _variant8, _variant9, _variant10, _variant11, _variant12,
     99                         _variant13, _variant14, _variant15, _variant16, _variant17, _variant18,
    100                         _variant19 };
    101 
    102 template <uint i> struct Variants_;
    103 template <> struct Variants_<0> { typedef Variants0 Type; };
    104 template <> struct Variants_<1> { typedef Variants1 Type; };
    105 template <> struct Variants_<2> { typedef Variants2 Type; };
    106 template <> struct Variants_<3> { typedef Variants3 Type; };
    107 template <> struct Variants_<4> { typedef Variants4 Type; };
    108 template <> struct Variants_<5> { typedef Variants5 Type; };
    109 template <> struct Variants_<6> { typedef Variants6 Type; };
    110 template <> struct Variants_<7> { typedef Variants7 Type; };
    111 template <> struct Variants_<8> { typedef Variants8 Type; };
    112 template <> struct Variants_<9> { typedef Variants9 Type; };
    113 template <> struct Variants_<10> { typedef Variants10 Type; };
    114 template <> struct Variants_<11> { typedef Variants11 Type; };
    115 template <> struct Variants_<12> { typedef Variants12 Type; };
    116 template <> struct Variants_<13> { typedef Variants13 Type; };
    117 template <> struct Variants_<14> { typedef Variants14 Type; };
    118 template <> struct Variants_<15> { typedef Variants15 Type; };
    119 template <> struct Variants_<16> { typedef Variants16 Type; };
    120 template <> struct Variants_<17> { typedef Variants17 Type; };
    121 template <> struct Variants_<18> { typedef Variants18 Type; };
    122 template <> struct Variants_<19> { typedef Variants19 Type; };
    123 template <> struct Variants_<20> { typedef Variants20 Type; };
    124 
    125 template <uint i>
    126 using Variants = typename Variants_<i>::Type;
    127 
    128 }  // namespace _ (private)
    129 
    130 template <typename... Variants>
    131 class OneOf {
    132   template <typename Key>
    133   static inline constexpr uint typeIndex() {
    134     return _::TypeIndex_<1, _::OneOfFailError_, Key, Variants...>::value;
    135   }
    136   // Get the 1-based index of Key within the type list Types, or static_assert with a nice error.
    137 
    138   template <typename Key>
    139   static inline constexpr uint typeIndexOrZero() {
    140     return _::TypeIndex_<1, _::OneOfFailZero_, Key, Variants...>::value;
    141   }
    142 
    143   template <uint i, typename... OtherVariants>
    144   struct HasAll;
    145   // Has a member type called "Success" if and only if all of `OtherVariants` are types that
    146   // appear in `Variants`. Used with SFINAE to enable subset constructors.
    147 
    148 public:
    149   inline OneOf(): tag(0) {}
    150 
    151   OneOf(const OneOf& other) { copyFrom(other); }
    152   OneOf(OneOf& other) { copyFrom(other); }
    153   OneOf(OneOf&& other) { moveFrom(other); }
    154   // Copy/move from same OneOf type.
    155 
    156   template <typename... OtherVariants, typename = typename HasAll<1, OtherVariants...>::Success>
    157   OneOf(const OneOf<OtherVariants...>& other) { copyFromSubset(other); }
    158   template <typename... OtherVariants, typename = typename HasAll<1, OtherVariants...>::Success>
    159   OneOf(OneOf<OtherVariants...>& other) { copyFromSubset(other); }
    160   template <typename... OtherVariants, typename = typename HasAll<1, OtherVariants...>::Success>
    161   OneOf(OneOf<OtherVariants...>&& other) { moveFromSubset(other); }
    162   // Copy/move from OneOf that contains a subset of the types we do.
    163 
    164   template <typename T, typename = typename HasAll<0, Decay<T>>::Success>
    165   OneOf(T&& other): tag(typeIndex<Decay<T>>()) {
    166     ctor(*reinterpret_cast<Decay<T>*>(space), kj::fwd<T>(other));
    167   }
    168   // Copy/move from a value that matches one of the individual types in the OneOf.
    169 
    170   ~OneOf() { destroy(); }
    171 
    172   OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; }
    173   OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; }
    174 
    175   inline bool operator==(decltype(nullptr)) const { return tag == 0; }
    176   inline bool operator!=(decltype(nullptr)) const { return tag != 0; }
    177 
    178   template <typename T>
    179   bool is() const {
    180     return tag == typeIndex<T>();
    181   }
    182 
    183   template <typename T>
    184   T& get() & {
    185     KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
    186     return *reinterpret_cast<T*>(space);
    187   }
    188   template <typename T>
    189   T&& get() && {
    190     KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
    191     return kj::mv(*reinterpret_cast<T*>(space));
    192   }
    193   template <typename T>
    194   const T& get() const& {
    195     KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
    196     return *reinterpret_cast<const T*>(space);
    197   }
    198   template <typename T>
    199   const T&& get() const&& {
    200     KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
    201     return kj::mv(*reinterpret_cast<const T*>(space));
    202   }
    203 
    204   template <typename T, typename... Params>
    205   T& init(Params&&... params) {
    206     if (tag != 0) destroy();
    207     ctor(*reinterpret_cast<T*>(space), kj::fwd<Params>(params)...);
    208     tag = typeIndex<T>();
    209     return *reinterpret_cast<T*>(space);
    210   }
    211 
    212   template <typename T>
    213   Maybe<T&> tryGet() {
    214     if (is<T>()) {
    215       return *reinterpret_cast<T*>(space);
    216     } else {
    217       return nullptr;
    218     }
    219   }
    220   template <typename T>
    221   Maybe<const T&> tryGet() const {
    222     if (is<T>()) {
    223       return *reinterpret_cast<const T*>(space);
    224     } else {
    225       return nullptr;
    226     }
    227   }
    228 
    229   template <uint i>
    230   KJ_NORETURN(void allHandled());
    231   // After a series of if/else blocks handling each variant of the OneOf, have the final else
    232   // block call allHandled<n>() where n is the number of variants. This will fail to compile
    233   // if new variants are added in the future.
    234 
    235   typedef _::Variants<sizeof...(Variants)> Tag;
    236 
    237   Tag which() const {
    238     KJ_IREQUIRE(tag != 0, "Can't KJ_SWITCH_ONEOF() on uninitialized value.");
    239     return static_cast<Tag>(tag - 1);
    240   }
    241 
    242   template <typename T>
    243   static constexpr Tag tagFor() {
    244     return static_cast<Tag>(typeIndex<T>() - 1);
    245   }
    246 
    247   OneOf* _switchSubject() & { return this; }
    248   const OneOf* _switchSubject() const& { return this; }
    249   _::NullableValue<OneOf> _switchSubject() && { return kj::mv(*this); }
    250 
    251 private:
    252   uint tag;
    253 
    254   static inline constexpr size_t maxSize(size_t a) {
    255     return a;
    256   }
    257   template <typename... Rest>
    258   static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) {
    259     return maxSize(kj::max(a, b), rest...);
    260   }
    261   // Returns the maximum of all the parameters.
    262   // TODO(someday):  Generalize the above template and make it common.  I tried, but C++ decided to
    263   //   be difficult so I cut my losses.
    264 
    265   static constexpr auto spaceSize = maxSize(sizeof(Variants)...);
    266   // TODO(msvc):  This constant could just as well go directly inside space's bracket's, where it's
    267   // used, but MSVC suffers a parse error on `...`.
    268 
    269   union {
    270     byte space[spaceSize];
    271 
    272     void* forceAligned;
    273     // TODO(someday):  Use C++11 alignas() once we require GCC 4.8 / Clang 3.3.
    274   };
    275 
    276   template <typename... T>
    277   inline void doAll(T... t) {}
    278 
    279   template <typename T>
    280   inline bool destroyVariant() {
    281     if (tag == typeIndex<T>()) {
    282       tag = 0;
    283       dtor(*reinterpret_cast<T*>(space));
    284     }
    285     return false;
    286   }
    287   void destroy() {
    288     doAll(destroyVariant<Variants>()...);
    289   }
    290 
    291   template <typename T>
    292   inline bool copyVariantFrom(const OneOf& other) {
    293     if (other.is<T>()) {
    294       ctor(*reinterpret_cast<T*>(space), other.get<T>());
    295     }
    296     return false;
    297   }
    298   void copyFrom(const OneOf& other) {
    299     // Initialize as a copy of `other`.  Expects that `this` starts out uninitialized, so the tag
    300     // is invalid.
    301     tag = other.tag;
    302     doAll(copyVariantFrom<Variants>(other)...);
    303   }
    304 
    305   template <typename T>
    306   inline bool copyVariantFrom(OneOf& other) {
    307     if (other.is<T>()) {
    308       ctor(*reinterpret_cast<T*>(space), other.get<T>());
    309     }
    310     return false;
    311   }
    312   void copyFrom(OneOf& other) {
    313     // Initialize as a copy of `other`.  Expects that `this` starts out uninitialized, so the tag
    314     // is invalid.
    315     tag = other.tag;
    316     doAll(copyVariantFrom<Variants>(other)...);
    317   }
    318 
    319   template <typename T>
    320   inline bool moveVariantFrom(OneOf& other) {
    321     if (other.is<T>()) {
    322       ctor(*reinterpret_cast<T*>(space), kj::mv(other.get<T>()));
    323     }
    324     return false;
    325   }
    326   void moveFrom(OneOf& other) {
    327     // Initialize as a copy of `other`.  Expects that `this` starts out uninitialized, so the tag
    328     // is invalid.
    329     tag = other.tag;
    330     doAll(moveVariantFrom<Variants>(other)...);
    331   }
    332 
    333   template <typename T, typename... OtherVariants>
    334   inline bool copySubsetVariantFrom(const OneOf<OtherVariants...>& other) {
    335     if (other.template is<T>()) {
    336       tag = typeIndex<Decay<T>>();
    337       ctor(*reinterpret_cast<T*>(space), other.template get<T>());
    338     }
    339     return false;
    340   }
    341   template <typename... OtherVariants>
    342   void copyFromSubset(const OneOf<OtherVariants...>& other) {
    343     doAll(copySubsetVariantFrom<OtherVariants>(other)...);
    344   }
    345 
    346   template <typename T, typename... OtherVariants>
    347   inline bool copySubsetVariantFrom(OneOf<OtherVariants...>& other) {
    348     if (other.template is<T>()) {
    349       tag = typeIndex<Decay<T>>();
    350       ctor(*reinterpret_cast<T*>(space), other.template get<T>());
    351     }
    352     return false;
    353   }
    354   template <typename... OtherVariants>
    355   void copyFromSubset(OneOf<OtherVariants...>& other) {
    356     doAll(copySubsetVariantFrom<OtherVariants>(other)...);
    357   }
    358 
    359   template <typename T, typename... OtherVariants>
    360   inline bool moveSubsetVariantFrom(OneOf<OtherVariants...>& other) {
    361     if (other.template is<T>()) {
    362       tag = typeIndex<Decay<T>>();
    363       ctor(*reinterpret_cast<T*>(space), kj::mv(other.template get<T>()));
    364     }
    365     return false;
    366   }
    367   template <typename... OtherVariants>
    368   void moveFromSubset(OneOf<OtherVariants...>& other) {
    369     doAll(moveSubsetVariantFrom<OtherVariants>(other)...);
    370   }
    371 };
    372 
    373 template <typename... Variants>
    374 template <uint i, typename First, typename... Rest>
    375 struct OneOf<Variants...>::HasAll<i, First, Rest...>
    376     : public HasAll<typeIndexOrZero<First>(), Rest...> {};
    377 template <typename... Variants>
    378 template <uint i>
    379 struct OneOf<Variants...>::HasAll<i>: public _::SuccessIfNotZero<i> {};
    380 
    381 template <typename... Variants>
    382 template <uint i>
    383 void OneOf<Variants...>::allHandled() {
    384   // After a series of if/else blocks handling each variant of the OneOf, have the final else
    385   // block call allHandled<n>() where n is the number of variants. This will fail to compile
    386   // if new variants are added in the future.
    387 
    388   static_assert(i == sizeof...(Variants), "new OneOf variants need to be handled here");
    389   KJ_UNREACHABLE;
    390 }
    391 
    392 #if __cplusplus > 201402L
    393 #define KJ_SWITCH_ONEOF(value) \
    394   switch (auto _kj_switch_subject = (value)._switchSubject(); _kj_switch_subject->which())
    395 #else
    396 #define KJ_SWITCH_ONEOF(value) \
    397   /* Without C++17, we can only support one switch per containing block. Deal with it. */ \
    398   auto _kj_switch_subject = (value)._switchSubject(); \
    399   switch (_kj_switch_subject->which())
    400 #endif
    401 #if !_MSC_VER || defined(__clang__)
    402 #define KJ_CASE_ONEOF(name, ...) \
    403     break; \
    404   case ::kj::Decay<decltype(*_kj_switch_subject)>::template tagFor<__VA_ARGS__>(): \
    405     for (auto& name = _kj_switch_subject->template get<__VA_ARGS__>(), *_kj_switch_done = &name; \
    406          _kj_switch_done; _kj_switch_done = nullptr)
    407 #else
    408 // TODO(msvc): The latest MSVC which ships with VS2019 now ICEs on the implementation above. It
    409 //   appears we can hack around the problem by moving the `->template get<>()` syntax to an outer
    410 //   `if`. (This unfortunately allows wonky syntax like `KJ_CASE_ONEOF(a, B) { } else { }`.)
    411 //   https://developercommunity.visualstudio.com/content/problem/1143733/internal-compiler-error-on-v1670.html
    412 #define KJ_CASE_ONEOF(name, ...) \
    413     break; \
    414   case ::kj::Decay<decltype(*_kj_switch_subject)>::template tagFor<__VA_ARGS__>(): \
    415     if (auto* _kj_switch_done = &_kj_switch_subject->template get<__VA_ARGS__>()) \
    416       for (auto& name = *_kj_switch_done; _kj_switch_done; _kj_switch_done = nullptr)
    417 #endif
    418 #define KJ_CASE_ONEOF_DEFAULT break; default:
    419 // Allows switching over a OneOf.
    420 //
    421 // Example:
    422 //
    423 //     kj::OneOf<int, float, const char*> variant;
    424 //     KJ_SWITCH_ONEOF(variant) {
    425 //       KJ_CASE_ONEOF(i, int) {
    426 //         doSomethingWithInt(i);
    427 //       }
    428 //       KJ_CASE_ONEOF(s, const char*) {
    429 //         doSomethingWithString(s);
    430 //       }
    431 //       KJ_CASE_ONEOF_DEFAULT {
    432 //         doSomethingElse();
    433 //       }
    434 //     }
    435 //
    436 // Notes:
    437 // - If you don't handle all possible types and don't include a default branch, you'll get a
    438 //   compiler warning, just like a regular switch() over an enum where one of the enum values is
    439 //   missing.
    440 // - There's no need for a `break` statement in a KJ_CASE_ONEOF; it is implied.
    441 // - Under C++11 and C++14, only one KJ_SWITCH_ONEOF() can appear in a block. Wrap the switch in
    442 //   a pair of braces if you need a second switch in the same block. If C++17 is enabled, this is
    443 //   not an issue.
    444 //
    445 // Implementation notes:
    446 // - The use of __VA_ARGS__ is to account for template types that have commas separating type
    447 //   parameters, since macros don't recognize <> as grouping.
    448 // - _kj_switch_done is really used as a boolean flag to prevent the for() loop from actually
    449 //   looping, but it's defined as a pointer since that's all we can define in this context.
    450 
    451 }  // namespace kj
    452 
    453 KJ_END_HEADER