You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					243 lines
				
				8.7 KiB
			
		
		
			
		
	
	
					243 lines
				
				8.7 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
							 | 
						||
| 
								 | 
							
								// Licensed under the MIT License:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Permission is hereby granted, free of charge, to any person obtaining a copy
							 | 
						||
| 
								 | 
							
								// of this software and associated documentation files (the "Software"), to deal
							 | 
						||
| 
								 | 
							
								// in the Software without restriction, including without limitation the rights
							 | 
						||
| 
								 | 
							
								// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
							 | 
						||
| 
								 | 
							
								// copies of the Software, and to permit persons to whom the Software is
							 | 
						||
| 
								 | 
							
								// furnished to do so, subject to the following conditions:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The above copyright notice and this permission notice shall be included in
							 | 
						||
| 
								 | 
							
								// all copies or substantial portions of the Software.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
							 | 
						||
| 
								 | 
							
								// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
							 | 
						||
| 
								 | 
							
								// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
							 | 
						||
| 
								 | 
							
								// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
							 | 
						||
| 
								 | 
							
								// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
							 | 
						||
| 
								 | 
							
								// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
							 | 
						||
| 
								 | 
							
								// THE SOFTWARE.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef CAPNP_RAW_SCHEMA_H_
							 | 
						||
| 
								 | 
							
								#define CAPNP_RAW_SCHEMA_H_
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
							 | 
						||
| 
								 | 
							
								#pragma GCC system_header
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "common.h"  // for uint and friends
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if _MSC_VER
							 | 
						||
| 
								 | 
							
								#include <atomic>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace capnp {
							 | 
						||
| 
								 | 
							
								namespace _ {  // private
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct RawSchema;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct RawBrandedSchema {
							 | 
						||
| 
								 | 
							
								  // Represents a combination of a schema and bindings for its generic parameters.
							 | 
						||
| 
								 | 
							
								  //
							 | 
						||
| 
								 | 
							
								  // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for
							 | 
						||
| 
								 | 
							
								  // every _instance_ of a generic type -- or, at least, every instance that is actually used. For
							 | 
						||
| 
								 | 
							
								  // generated-code types, we use template magic to initialize these.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const RawSchema* generic;
							 | 
						||
| 
								 | 
							
								  // Generic type which we're branding.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  struct Binding {
							 | 
						||
| 
								 | 
							
								    uint8_t which;       // Numeric value of one of schema::Type::Which.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool isImplicitParameter;
							 | 
						||
| 
								 | 
							
								    // For AnyPointer, true if it's an implicit method parameter.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    uint16_t listDepth;  // Number of times to wrap the base type in List().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    uint16_t paramIndex;
							 | 
						||
| 
								 | 
							
								    // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter
							 | 
						||
| 
								 | 
							
								    // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric
							 | 
						||
| 
								 | 
							
								    // value of one of schema::Type::AnyPointer::Unconstrained::Which.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    union {
							 | 
						||
| 
								 | 
							
								      const RawBrandedSchema* schema;  // for struct, enum, interface
							 | 
						||
| 
								 | 
							
								      uint64_t scopeId;                // for AnyPointer, if it's a type parameter
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Binding() = default;
							 | 
						||
| 
								 | 
							
								    inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema)
							 | 
						||
| 
								 | 
							
								        : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0),
							 | 
						||
| 
								 | 
							
								          schema(schema) {}
							 | 
						||
| 
								 | 
							
								    inline constexpr Binding(uint8_t which, uint16_t listDepth,
							 | 
						||
| 
								 | 
							
								                             uint64_t scopeId, uint16_t paramIndex)
							 | 
						||
| 
								 | 
							
								        : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex),
							 | 
						||
| 
								 | 
							
								          scopeId(scopeId) {}
							 | 
						||
| 
								 | 
							
								    inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex)
							 | 
						||
| 
								 | 
							
								        : which(which), isImplicitParameter(true), listDepth(listDepth),
							 | 
						||
| 
								 | 
							
								          paramIndex(implicitParamIndex), scopeId(0) {}
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  struct Scope {
							 | 
						||
| 
								 | 
							
								    uint64_t typeId;
							 | 
						||
| 
								 | 
							
								    // Type ID whose parameters are being bound.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const Binding* bindings;
							 | 
						||
| 
								 | 
							
								    uint bindingCount;
							 | 
						||
| 
								 | 
							
								    // Bindings for those parameters.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool isUnbound;
							 | 
						||
| 
								 | 
							
								    // This scope is unbound, in the sense of SchemaLoader::getUnbound().
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const Scope* scopes;
							 | 
						||
| 
								 | 
							
								  // Array of enclosing scopes for which generic variables have been bound, sorted by type ID.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  struct Dependency {
							 | 
						||
| 
								 | 
							
								    uint location;
							 | 
						||
| 
								 | 
							
								    const RawBrandedSchema* schema;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const Dependency* dependencies;
							 | 
						||
| 
								 | 
							
								  // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that
							 | 
						||
| 
								 | 
							
								  // are branded are included in this map; if a dependency is missing, use its `defaultBrand`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint32_t scopeCount;
							 | 
						||
| 
								 | 
							
								  uint32_t dependencyCount;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  enum class DepKind {
							 | 
						||
| 
								 | 
							
								    // Component of a Dependency::location. Specifies what sort of dependency this is.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    INVALID,
							 | 
						||
| 
								 | 
							
								    // Mostly defined to ensure that zero is not a valid location.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    FIELD,
							 | 
						||
| 
								 | 
							
								    // Binding needed for a field's type. The index is the field index (NOT ordinal!).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    METHOD_PARAMS,
							 | 
						||
| 
								 | 
							
								    // Bindings needed for a method's params type. The index is the method number.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    METHOD_RESULTS,
							 | 
						||
| 
								 | 
							
								    // Bindings needed for a method's results type. The index is the method ordinal.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    SUPERCLASS,
							 | 
						||
| 
								 | 
							
								    // Bindings needed for a superclass type. The index is the superclass's index in the
							 | 
						||
| 
								 | 
							
								    // "extends" list.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CONST_TYPE
							 | 
						||
| 
								 | 
							
								    // Bindings needed for the type of a constant. The index is zero.
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  static inline uint makeDepLocation(DepKind kind, uint index) {
							 | 
						||
| 
								 | 
							
								    // Make a number representing the location of a particular dependency within its parent
							 | 
						||
| 
								 | 
							
								    // schema.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return (static_cast<uint>(kind) << 24) | index;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  class Initializer {
							 | 
						||
| 
								 | 
							
								  public:
							 | 
						||
| 
								 | 
							
								    virtual void init(const RawBrandedSchema* generic) const = 0;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const Initializer* lazyInitializer;
							 | 
						||
| 
								 | 
							
								  // Lazy initializer, invoked by ensureInitialized().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  inline void ensureInitialized() const {
							 | 
						||
| 
								 | 
							
								    // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
							 | 
						||
| 
								 | 
							
								    // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
							 | 
						||
| 
								 | 
							
								    // types are always initialized; only dynamically-loaded schemas may be lazy.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if __GNUC__
							 | 
						||
| 
								 | 
							
								    const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
							 | 
						||
| 
								 | 
							
								#elif _MSC_VER
							 | 
						||
| 
								 | 
							
								    const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
							 | 
						||
| 
								 | 
							
								    std::atomic_thread_fence(std::memory_order_acquire);
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#error "Platform not supported"
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    if (i != nullptr) i->init(this);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  inline bool isUnbound() const;
							 | 
						||
| 
								 | 
							
								  // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case
							 | 
						||
| 
								 | 
							
								  // binding lookups need to be handled specially.
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct RawSchema {
							 | 
						||
| 
								 | 
							
								  // The generated code defines a constant RawSchema for every compiled declaration.
							 | 
						||
| 
								 | 
							
								  //
							 | 
						||
| 
								 | 
							
								  // This is an internal structure which could change in the future.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint64_t id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const word* encodedNode;
							 | 
						||
| 
								 | 
							
								  // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint32_t encodedSize;
							 | 
						||
| 
								 | 
							
								  // Size of encodedNode, in words.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const RawSchema* const* dependencies;
							 | 
						||
| 
								 | 
							
								  // Pointers to other types on which this one depends, sorted by ID.  The schemas in this table
							 | 
						||
| 
								 | 
							
								  // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before
							 | 
						||
| 
								 | 
							
								  // using it.
							 | 
						||
| 
								 | 
							
								  //
							 | 
						||
| 
								 | 
							
								  // TODO(someday):  Make this a hashtable.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const uint16_t* membersByName;
							 | 
						||
| 
								 | 
							
								  // Indexes of members sorted by name.  Used to implement name lookup.
							 | 
						||
| 
								 | 
							
								  // TODO(someday):  Make this a hashtable.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint32_t dependencyCount;
							 | 
						||
| 
								 | 
							
								  uint32_t memberCount;
							 | 
						||
| 
								 | 
							
								  // Sizes of above tables.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const uint16_t* membersByDiscriminant;
							 | 
						||
| 
								 | 
							
								  // List of all member indexes ordered by discriminant value.  Those which don't have a
							 | 
						||
| 
								 | 
							
								  // discriminant value are listed at the end, in order by ordinal.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const RawSchema* canCastTo;
							 | 
						||
| 
								 | 
							
								  // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue
							 | 
						||
| 
								 | 
							
								  // with this schema.  This is null for all compiled-in types; it is only set by SchemaLoader on
							 | 
						||
| 
								 | 
							
								  // dynamically-loaded types.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  class Initializer {
							 | 
						||
| 
								 | 
							
								  public:
							 | 
						||
| 
								 | 
							
								    virtual void init(const RawSchema* schema) const = 0;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const Initializer* lazyInitializer;
							 | 
						||
| 
								 | 
							
								  // Lazy initializer, invoked by ensureInitialized().
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  inline void ensureInitialized() const {
							 | 
						||
| 
								 | 
							
								    // Lazy initialization support.  Invoke to ensure that initialization has taken place.  This
							 | 
						||
| 
								 | 
							
								    // is required in particular when traversing the dependency list.  RawSchemas for compiled-in
							 | 
						||
| 
								 | 
							
								    // types are always initialized; only dynamically-loaded schemas may be lazy.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if __GNUC__
							 | 
						||
| 
								 | 
							
								    const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE);
							 | 
						||
| 
								 | 
							
								#elif _MSC_VER
							 | 
						||
| 
								 | 
							
								    const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer);
							 | 
						||
| 
								 | 
							
								    std::atomic_thread_fence(std::memory_order_acquire);
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#error "Platform not supported"
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								    if (i != nullptr) i->init(this);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  RawBrandedSchema defaultBrand;
							 | 
						||
| 
								 | 
							
								  // Specifies the brand to use for this schema if no generic parameters have been bound to
							 | 
						||
| 
								 | 
							
								  // anything. Generally, in the default brand, all generic parameters are treated as if they were
							 | 
						||
| 
								 | 
							
								  // bound to `AnyPointer`.
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								inline bool RawBrandedSchema::isUnbound() const {
							 | 
						||
| 
								 | 
							
								  // The unbound schema is the only one that has no scopes but is not the default schema.
							 | 
						||
| 
								 | 
							
								  return scopeCount == 0 && this != &generic->defaultBrand;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}  // namespace _ (private)
							 | 
						||
| 
								 | 
							
								}  // namespace capnp
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif  // CAPNP_RAW_SCHEMA_H_
							 |