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

raw-schema.h (8851B)


      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"  // for uint and friends
     25 
     26 #if _MSC_VER && !defined(__clang__)
     27 #include <atomic>
     28 #endif
     29 
     30 CAPNP_BEGIN_HEADER
     31 
     32 namespace capnp {
     33 namespace _ {  // private
     34 
     35 struct RawSchema;
     36 
     37 struct RawBrandedSchema {
     38   // Represents a combination of a schema and bindings for its generic parameters.
     39   //
     40   // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for
     41   // every _instance_ of a generic type -- or, at least, every instance that is actually used. For
     42   // generated-code types, we use template magic to initialize these.
     43 
     44   const RawSchema* generic;
     45   // Generic type which we're branding.
     46 
     47   struct Binding {
     48     uint8_t which;       // Numeric value of one of schema::Type::Which.
     49 
     50     bool isImplicitParameter;
     51     // For AnyPointer, true if it's an implicit method parameter.
     52 
     53     uint16_t listDepth;  // Number of times to wrap the base type in List().
     54 
     55     uint16_t paramIndex;
     56     // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter
     57     // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric
     58     // value of one of schema::Type::AnyPointer::Unconstrained::Which.
     59 
     60     union {
     61       const RawBrandedSchema* schema;  // for struct, enum, interface
     62       uint64_t scopeId;                // for AnyPointer, if it's a type parameter
     63     };
     64 
     65     Binding() = default;
     66     inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
     67         : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0),
     68           schema(schema) {}
     69     inline constexpr Binding(uint8_t which, uint16_t listDepth,
     70                              uint64_t scopeId, uint16_t paramIndex)
     71         : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex),
     72           scopeId(scopeId) {}
     73     inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex)
     74         : which(which), isImplicitParameter(true), listDepth(listDepth),
     75           paramIndex(implicitParamIndex), scopeId(0) {}
     76   };
     77 
     78   struct Scope {
     79     uint64_t typeId;
     80     // Type ID whose parameters are being bound.
     81 
     82     const Binding* bindings;
     83     uint bindingCount;
     84     // Bindings for those parameters.
     85 
     86     bool isUnbound;
     87     // This scope is unbound, in the sense of SchemaLoader::getUnbound().
     88   };
     89 
     90   const Scope* scopes;
     91   // Array of enclosing scopes for which generic variables have been bound, sorted by type ID.
     92 
     93   struct Dependency {
     94     uint location;
     95     const RawBrandedSchema* schema;
     96   };
     97 
     98   const Dependency* dependencies;
     99   // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that
    100   // are branded are included in this map; if a dependency is missing, use its `defaultBrand`.
    101 
    102   uint32_t scopeCount;
    103   uint32_t dependencyCount;
    104 
    105   enum class DepKind {
    106     // Component of a Dependency::location. Specifies what sort of dependency this is.
    107 
    108     INVALID,
    109     // Mostly defined to ensure that zero is not a valid location.
    110 
    111     FIELD,
    112     // Binding needed for a field's type. The index is the field index (NOT ordinal!).
    113 
    114     METHOD_PARAMS,
    115     // Bindings needed for a method's params type. The index is the method number.
    116 
    117     METHOD_RESULTS,
    118     // Bindings needed for a method's results type. The index is the method ordinal.
    119 
    120     SUPERCLASS,
    121     // Bindings needed for a superclass type. The index is the superclass's index in the
    122     // "extends" list.
    123 
    124     CONST_TYPE
    125     // Bindings needed for the type of a constant. The index is zero.
    126   };
    127 
    128   static inline uint makeDepLocation(DepKind kind, uint index) {
    129     // Make a number representing the location of a particular dependency within its parent
    130     // schema.
    131 
    132     return (static_cast<uint>(kind) << 24) | index;
    133   }
    134 
    135   class Initializer {
    136   public:
    137     virtual void init(const RawBrandedSchema* generic) const = 0;
    138   };
    139 
    140   const Initializer* lazyInitializer;
    141   // Lazy initializer, invoked by ensureInitialized().
    142 
    143   inline void ensureInitialized() const {
    144     // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
    145     // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
    146     // types are always initialized; only dynamically-loaded schemas may be lazy.
    147 
    148 #if __GNUC__ || defined(__clang__)
    149     const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
    150 #elif _MSC_VER
    151     const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
    152     std::atomic_thread_fence(std::memory_order_acquire);
    153 #else
    154 #error "Platform not supported"
    155 #endif
    156     if (i != nullptr) i->init(this);
    157   }
    158 
    159   inline bool isUnbound() const;
    160   // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case
    161   // binding lookups need to be handled specially.
    162 };
    163 
    164 struct RawSchema {
    165   // The generated code defines a constant RawSchema for every compiled declaration.
    166   //
    167   // This is an internal structure which could change in the future.
    168 
    169   uint64_t id;
    170 
    171   const word* encodedNode;
    172   // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode).
    173 
    174   uint32_t encodedSize;
    175   // Size of encodedNode, in words.
    176 
    177   const RawSchema* const* dependencies;
    178   // Pointers to other types on which this one depends, sorted by ID.  The schemas in this table
    179   // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before
    180   // using it.
    181   //
    182   // TODO(someday):  Make this a hashtable.
    183 
    184   const uint16_t* membersByName;
    185   // Indexes of members sorted by name.  Used to implement name lookup.
    186   // TODO(someday):  Make this a hashtable.
    187 
    188   uint32_t dependencyCount;
    189   uint32_t memberCount;
    190   // Sizes of above tables.
    191 
    192   const uint16_t* membersByDiscriminant;
    193   // List of all member indexes ordered by discriminant value.  Those which don't have a
    194   // discriminant value are listed at the end, in order by ordinal.
    195 
    196   const RawSchema* canCastTo;
    197   // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue
    198   // with this schema.  This is null for all compiled-in types; it is only set by SchemaLoader on
    199   // dynamically-loaded types.
    200 
    201   class Initializer {
    202   public:
    203     virtual void init(const RawSchema* schema) const = 0;
    204   };
    205 
    206   const Initializer* lazyInitializer;
    207   // Lazy initializer, invoked by ensureInitialized().
    208 
    209   inline void ensureInitialized() const {
    210     // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
    211     // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
    212     // types are always initialized; only dynamically-loaded schemas may be lazy.
    213 
    214 #if __GNUC__ || defined(__clang__)
    215     const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
    216 #elif _MSC_VER
    217     const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
    218     std::atomic_thread_fence(std::memory_order_acquire);
    219 #else
    220 #error "Platform not supported"
    221 #endif
    222     if (i != nullptr) i->init(this);
    223   }
    224 
    225   RawBrandedSchema defaultBrand;
    226   // Specifies the brand to use for this schema if no generic parameters have been bound to
    227   // anything. Generally, in the default brand, all generic parameters are treated as if they were
    228   // bound to `AnyPointer`.
    229 };
    230 
    231 inline bool RawBrandedSchema::isUnbound() const {
    232   // The unbound schema is the only one that has no scopes but is not the default schema.
    233   return scopeCount == 0 && this != &generic->defaultBrand;
    234 }
    235 
    236 }  // namespace _ (private)
    237 }  // namespace capnp
    238 
    239 CAPNP_END_HEADER