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.
242 lines
8.7 KiB
242 lines
8.7 KiB
// 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_
|
|
|