mirror of https://github.com/KLayout/klayout.git
Integration of LStream sources
This commit is contained in:
parent
7d0912db17
commit
d2e5393d0c
|
|
@ -74,3 +74,6 @@ py.typed
|
|||
*.dmg.md5
|
||||
.DS_Store
|
||||
|
||||
# temp files
|
||||
.tmp*
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
# LStream plugin sources
|
||||
|
||||
This plugin employs Cap'n'Proto (https://capnproto.org/) to implement
|
||||
the serialization layer.
|
||||
|
||||
The schema files are provided in an already compiled form.
|
||||
The provided sources use Cap'n'Proto compiler version 1.0.1.
|
||||
|
||||
Use the `capnp_compile.sh` script to compile the schema files
|
||||
into C++. It requires "capnp" version 1.0.1.
|
||||
|
||||
The original LStream sources are kept somewhere else.
|
||||
Use `fetch.sh` to sync these external sources with the local
|
||||
ones.
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
HEADERS=\
|
||||
capnp/cell.capnp.h \
|
||||
capnp/geometry.capnp.h \
|
||||
capnp/header.capnp.h \
|
||||
capnp/layoutView.capnp.h \
|
||||
capnp/library.capnp.h \
|
||||
capnp/metaData.capnp.h \
|
||||
capnp/metaDataView.capnp.h \
|
||||
capnp/propertySet.capnp.h \
|
||||
capnp/repetition.capnp.h \
|
||||
capnp/variant.capnp.h \
|
||||
|
||||
SOURCES=\
|
||||
capnp/cell.capnp.c++ \
|
||||
capnp/geometry.capnp.c++ \
|
||||
capnp/header.capnp.c++ \
|
||||
capnp/layoutView.capnp.c++ \
|
||||
capnp/library.capnp.c++ \
|
||||
capnp/metaData.capnp.c++ \
|
||||
capnp/metaDataView.capnp.c++ \
|
||||
capnp/propertySet.capnp.c++ \
|
||||
capnp/repetition.capnp.c++ \
|
||||
capnp/variant.capnp.c++ \
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: cell.capnp
|
||||
|
||||
#include "cell.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<35> b_f29d05b618de9054 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
84, 144, 222, 24, 182, 5, 157, 242,
|
||||
11, 0, 0, 0, 1, 0, 0, 0,
|
||||
239, 93, 77, 24, 100, 238, 216, 191,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 130, 0, 0, 0,
|
||||
25, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 101, 108, 108, 46, 99, 97, 112,
|
||||
110, 112, 58, 67, 101, 108, 108, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 0, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 0, 0, 0, 3, 0, 1, 0,
|
||||
36, 0, 0, 0, 2, 0, 1, 0,
|
||||
118, 105, 101, 119, 73, 100, 115, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
7, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_f29d05b618de9054 = b_f29d05b618de9054.words;
|
||||
#if !CAPNP_LITE
|
||||
static const uint16_t m_f29d05b618de9054[] = {0};
|
||||
static const uint16_t i_f29d05b618de9054[] = {0};
|
||||
const ::capnp::_::RawSchema s_f29d05b618de9054 = {
|
||||
0xf29d05b618de9054, b_f29d05b618de9054.words, 35, nullptr, m_f29d05b618de9054,
|
||||
0, 1, i_f29d05b618de9054, nullptr, nullptr, { &s_f29d05b618de9054, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace cell {
|
||||
|
||||
// Cell
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Cell::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Cell::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Cell::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Cell::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: cell.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(f29d05b618de9054);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace cell {
|
||||
|
||||
struct Cell {
|
||||
Cell() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(f29d05b618de9054, 0, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class Cell::Reader {
|
||||
public:
|
||||
typedef Cell Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasViewIds() const;
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Reader getViewIds() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class Cell::Builder {
|
||||
public:
|
||||
typedef Cell Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasViewIds();
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Builder getViewIds();
|
||||
inline void setViewIds( ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Reader value);
|
||||
inline void setViewIds(::kj::ArrayPtr<const ::uint16_t> value);
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Builder initViewIds(unsigned int size);
|
||||
inline void adoptViewIds(::capnp::Orphan< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>> disownViewIds();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class Cell::Pipeline {
|
||||
public:
|
||||
typedef Cell Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline bool Cell::Reader::hasViewIds() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Cell::Builder::hasViewIds() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Reader Cell::Reader::getViewIds() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Builder Cell::Builder::getViewIds() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Cell::Builder::setViewIds( ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline void Cell::Builder::setViewIds(::kj::ArrayPtr<const ::uint16_t> value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>::Builder Cell::Builder::initViewIds(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Cell::Builder::adoptViewIds(
|
||||
::capnp::Orphan< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>> Cell::Builder::disownViewIds() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::uint16_t, ::capnp::Kind::PRIMITIVE>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,202 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: header.capnp
|
||||
|
||||
#include "header.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<48> b_ca6137cc23ea16e8 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
232, 22, 234, 35, 204, 55, 97, 202,
|
||||
13, 0, 0, 0, 1, 0, 0, 0,
|
||||
36, 255, 84, 206, 94, 231, 245, 197,
|
||||
2, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 202, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 119, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 101, 97, 100, 101, 114, 46, 99,
|
||||
97, 112, 110, 112, 58, 76, 105, 98,
|
||||
114, 97, 114, 121, 83, 112, 101, 99,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
8, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 0, 0, 3, 0, 1, 0,
|
||||
48, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 0, 0, 0, 3, 0, 1, 0,
|
||||
52, 0, 0, 0, 2, 0, 1, 0,
|
||||
110, 97, 109, 101, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 121, 112, 101, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_ca6137cc23ea16e8 = b_ca6137cc23ea16e8.words;
|
||||
#if !CAPNP_LITE
|
||||
static const uint16_t m_ca6137cc23ea16e8[] = {0, 1};
|
||||
static const uint16_t i_ca6137cc23ea16e8[] = {0, 1};
|
||||
const ::capnp::_::RawSchema s_ca6137cc23ea16e8 = {
|
||||
0xca6137cc23ea16e8, b_ca6137cc23ea16e8.words, 48, nullptr, m_ca6137cc23ea16e8,
|
||||
0, 2, i_ca6137cc23ea16e8, nullptr, nullptr, { &s_ca6137cc23ea16e8, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<85> b_a72897b14bf79c6b = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
107, 156, 247, 75, 177, 151, 40, 167,
|
||||
13, 0, 0, 0, 1, 0, 0, 0,
|
||||
36, 255, 84, 206, 94, 231, 245, 197,
|
||||
4, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 162, 0, 0, 0,
|
||||
29, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 0, 0, 0, 231, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 101, 97, 100, 101, 114, 46, 99,
|
||||
97, 112, 110, 112, 58, 72, 101, 97,
|
||||
100, 101, 114, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
16, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
97, 0, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 0, 0, 0, 3, 0, 1, 0,
|
||||
108, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 0, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 0, 0, 0, 3, 0, 1, 0,
|
||||
116, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 2, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
113, 0, 0, 0, 90, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 0, 0, 0, 3, 0, 1, 0,
|
||||
124, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
121, 0, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
120, 0, 0, 0, 3, 0, 1, 0,
|
||||
148, 0, 0, 0, 2, 0, 1, 0,
|
||||
109, 101, 116, 97, 68, 97, 116, 97,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
56, 212, 213, 232, 233, 209, 66, 147,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
103, 101, 110, 101, 114, 97, 116, 111,
|
||||
114, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 101, 99, 104, 110, 111, 108, 111,
|
||||
103, 121, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 105, 98, 114, 97, 114, 105, 101,
|
||||
115, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
232, 22, 234, 35, 204, 55, 97, 202,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_a72897b14bf79c6b = b_a72897b14bf79c6b.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_a72897b14bf79c6b[] = {
|
||||
&s_9342d1e9e8d5d438,
|
||||
&s_ca6137cc23ea16e8,
|
||||
};
|
||||
static const uint16_t m_a72897b14bf79c6b[] = {1, 3, 0, 2};
|
||||
static const uint16_t i_a72897b14bf79c6b[] = {0, 1, 2, 3};
|
||||
const ::capnp::_::RawSchema s_a72897b14bf79c6b = {
|
||||
0xa72897b14bf79c6b, b_a72897b14bf79c6b.words, 85, d_a72897b14bf79c6b, m_a72897b14bf79c6b,
|
||||
2, 4, i_a72897b14bf79c6b, nullptr, nullptr, { &s_a72897b14bf79c6b, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace header {
|
||||
|
||||
// LibrarySpec
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t LibrarySpec::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t LibrarySpec::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind LibrarySpec::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* LibrarySpec::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// Header
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Header::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Header::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Header::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Header::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,481 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: header.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
#include "metaData.capnp.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(ca6137cc23ea16e8);
|
||||
CAPNP_DECLARE_SCHEMA(a72897b14bf79c6b);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace header {
|
||||
|
||||
struct LibrarySpec {
|
||||
LibrarySpec() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(ca6137cc23ea16e8, 0, 2)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct Header {
|
||||
Header() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(a72897b14bf79c6b, 0, 4)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class LibrarySpec::Reader {
|
||||
public:
|
||||
typedef LibrarySpec Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasName() const;
|
||||
inline ::capnp::Text::Reader getName() const;
|
||||
|
||||
inline bool hasType() const;
|
||||
inline ::capnp::Text::Reader getType() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class LibrarySpec::Builder {
|
||||
public:
|
||||
typedef LibrarySpec Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasName();
|
||||
inline ::capnp::Text::Builder getName();
|
||||
inline void setName( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initName(unsigned int size);
|
||||
inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownName();
|
||||
|
||||
inline bool hasType();
|
||||
inline ::capnp::Text::Builder getType();
|
||||
inline void setType( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initType(unsigned int size);
|
||||
inline void adoptType(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownType();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class LibrarySpec::Pipeline {
|
||||
public:
|
||||
typedef LibrarySpec Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class Header::Reader {
|
||||
public:
|
||||
typedef Header Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasMetaData() const;
|
||||
inline ::stream::metaData::MetaData::Reader getMetaData() const;
|
||||
|
||||
inline bool hasGenerator() const;
|
||||
inline ::capnp::Text::Reader getGenerator() const;
|
||||
|
||||
inline bool hasTechnology() const;
|
||||
inline ::capnp::Text::Reader getTechnology() const;
|
||||
|
||||
inline bool hasLibraries() const;
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Reader getLibraries() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class Header::Builder {
|
||||
public:
|
||||
typedef Header Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasMetaData();
|
||||
inline ::stream::metaData::MetaData::Builder getMetaData();
|
||||
inline void setMetaData( ::stream::metaData::MetaData::Reader value);
|
||||
inline ::stream::metaData::MetaData::Builder initMetaData();
|
||||
inline void adoptMetaData(::capnp::Orphan< ::stream::metaData::MetaData>&& value);
|
||||
inline ::capnp::Orphan< ::stream::metaData::MetaData> disownMetaData();
|
||||
|
||||
inline bool hasGenerator();
|
||||
inline ::capnp::Text::Builder getGenerator();
|
||||
inline void setGenerator( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initGenerator(unsigned int size);
|
||||
inline void adoptGenerator(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownGenerator();
|
||||
|
||||
inline bool hasTechnology();
|
||||
inline ::capnp::Text::Builder getTechnology();
|
||||
inline void setTechnology( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initTechnology(unsigned int size);
|
||||
inline void adoptTechnology(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownTechnology();
|
||||
|
||||
inline bool hasLibraries();
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Builder getLibraries();
|
||||
inline void setLibraries( ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Reader value);
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Builder initLibraries(unsigned int size);
|
||||
inline void adoptLibraries(::capnp::Orphan< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>> disownLibraries();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class Header::Pipeline {
|
||||
public:
|
||||
typedef Header Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::metaData::MetaData::Pipeline getMetaData();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline bool LibrarySpec::Reader::hasName() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool LibrarySpec::Builder::hasName() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader LibrarySpec::Reader::getName() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder LibrarySpec::Builder::getName() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void LibrarySpec::Builder::setName( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder LibrarySpec::Builder::initName(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void LibrarySpec::Builder::adoptName(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> LibrarySpec::Builder::disownName() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool LibrarySpec::Reader::hasType() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool LibrarySpec::Builder::hasType() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader LibrarySpec::Reader::getType() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder LibrarySpec::Builder::getType() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void LibrarySpec::Builder::setType( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder LibrarySpec::Builder::initType(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void LibrarySpec::Builder::adoptType(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> LibrarySpec::Builder::disownType() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Header::Reader::hasMetaData() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Header::Builder::hasMetaData() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Reader Header::Reader::getMetaData() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Builder Header::Builder::getMetaData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::metaData::MetaData::Pipeline Header::Pipeline::getMetaData() {
|
||||
return ::stream::metaData::MetaData::Pipeline(_typeless.getPointerField(0));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void Header::Builder::setMetaData( ::stream::metaData::MetaData::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Builder Header::Builder::initMetaData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Header::Builder::adoptMetaData(
|
||||
::capnp::Orphan< ::stream::metaData::MetaData>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::metaData::MetaData> Header::Builder::disownMetaData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Header::Reader::hasGenerator() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Header::Builder::hasGenerator() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader Header::Reader::getGenerator() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder Header::Builder::getGenerator() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Header::Builder::setGenerator( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder Header::Builder::initGenerator(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Header::Builder::adoptGenerator(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> Header::Builder::disownGenerator() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Header::Reader::hasTechnology() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Header::Builder::hasTechnology() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader Header::Reader::getTechnology() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder Header::Builder::getTechnology() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Header::Builder::setTechnology( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder Header::Builder::initTechnology(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Header::Builder::adoptTechnology(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> Header::Builder::disownTechnology() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Header::Reader::hasLibraries() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Header::Builder::hasLibraries() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Reader Header::Reader::getLibraries() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Builder Header::Builder::getLibraries() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Header::Builder::setLibraries( ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>::Builder Header::Builder::initLibraries(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Header::Builder::adoptLibraries(
|
||||
::capnp::Orphan< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>> Header::Builder::disownLibraries() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::header::LibrarySpec, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<3>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,171 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: metaData.capnp
|
||||
|
||||
#include "metaData.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<64> b_cf35f955a29422a3 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
163, 34, 148, 162, 85, 249, 53, 207,
|
||||
15, 0, 0, 0, 1, 0, 0, 0,
|
||||
162, 141, 82, 244, 3, 18, 213, 145,
|
||||
3, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 234, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 175, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 101, 116, 97, 68, 97, 116, 97,
|
||||
46, 99, 97, 112, 110, 112, 58, 77,
|
||||
101, 116, 97, 68, 97, 116, 97, 69,
|
||||
110, 116, 114, 121, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
12, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
69, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
64, 0, 0, 0, 3, 0, 1, 0,
|
||||
76, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
73, 0, 0, 0, 98, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
72, 0, 0, 0, 3, 0, 1, 0,
|
||||
84, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 2, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
81, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
76, 0, 0, 0, 3, 0, 1, 0,
|
||||
88, 0, 0, 0, 2, 0, 1, 0,
|
||||
110, 97, 109, 101, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 101, 115, 99, 114, 105, 112, 116,
|
||||
105, 111, 110, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 108, 117, 101, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_cf35f955a29422a3 = b_cf35f955a29422a3.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_cf35f955a29422a3[] = {
|
||||
&s_f96a70ebaebd19c6,
|
||||
};
|
||||
static const uint16_t m_cf35f955a29422a3[] = {1, 0, 2};
|
||||
static const uint16_t i_cf35f955a29422a3[] = {0, 1, 2};
|
||||
const ::capnp::_::RawSchema s_cf35f955a29422a3 = {
|
||||
0xcf35f955a29422a3, b_cf35f955a29422a3.words, 64, d_cf35f955a29422a3, m_cf35f955a29422a3,
|
||||
1, 3, i_cf35f955a29422a3, nullptr, nullptr, { &s_cf35f955a29422a3, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<36> b_9342d1e9e8d5d438 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
56, 212, 213, 232, 233, 209, 66, 147,
|
||||
15, 0, 0, 0, 1, 0, 0, 0,
|
||||
162, 141, 82, 244, 3, 18, 213, 145,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 194, 0, 0, 0,
|
||||
29, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 101, 116, 97, 68, 97, 116, 97,
|
||||
46, 99, 97, 112, 110, 112, 58, 77,
|
||||
101, 116, 97, 68, 97, 116, 97, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 0, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 0, 0, 0, 3, 0, 1, 0,
|
||||
36, 0, 0, 0, 2, 0, 1, 0,
|
||||
101, 110, 116, 114, 105, 101, 115, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
163, 34, 148, 162, 85, 249, 53, 207,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_9342d1e9e8d5d438 = b_9342d1e9e8d5d438.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_9342d1e9e8d5d438[] = {
|
||||
&s_cf35f955a29422a3,
|
||||
};
|
||||
static const uint16_t m_9342d1e9e8d5d438[] = {0};
|
||||
static const uint16_t i_9342d1e9e8d5d438[] = {0};
|
||||
const ::capnp::_::RawSchema s_9342d1e9e8d5d438 = {
|
||||
0x9342d1e9e8d5d438, b_9342d1e9e8d5d438.words, 36, d_9342d1e9e8d5d438, m_9342d1e9e8d5d438,
|
||||
1, 1, i_9342d1e9e8d5d438, nullptr, nullptr, { &s_9342d1e9e8d5d438, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace metaData {
|
||||
|
||||
// MetaDataEntry
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t MetaDataEntry::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t MetaDataEntry::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind MetaDataEntry::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* MetaDataEntry::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// MetaData
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t MetaData::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t MetaData::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind MetaData::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* MetaData::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,393 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: metaData.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
#include "variant.capnp.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(cf35f955a29422a3);
|
||||
CAPNP_DECLARE_SCHEMA(9342d1e9e8d5d438);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace metaData {
|
||||
|
||||
struct MetaDataEntry {
|
||||
MetaDataEntry() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(cf35f955a29422a3, 0, 3)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct MetaData {
|
||||
MetaData() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(9342d1e9e8d5d438, 0, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class MetaDataEntry::Reader {
|
||||
public:
|
||||
typedef MetaDataEntry Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasName() const;
|
||||
inline ::capnp::Text::Reader getName() const;
|
||||
|
||||
inline bool hasDescription() const;
|
||||
inline ::capnp::Text::Reader getDescription() const;
|
||||
|
||||
inline bool hasValue() const;
|
||||
inline ::stream::variant::Variant::Reader getValue() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class MetaDataEntry::Builder {
|
||||
public:
|
||||
typedef MetaDataEntry Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasName();
|
||||
inline ::capnp::Text::Builder getName();
|
||||
inline void setName( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initName(unsigned int size);
|
||||
inline void adoptName(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownName();
|
||||
|
||||
inline bool hasDescription();
|
||||
inline ::capnp::Text::Builder getDescription();
|
||||
inline void setDescription( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initDescription(unsigned int size);
|
||||
inline void adoptDescription(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownDescription();
|
||||
|
||||
inline bool hasValue();
|
||||
inline ::stream::variant::Variant::Builder getValue();
|
||||
inline void setValue( ::stream::variant::Variant::Reader value);
|
||||
inline ::stream::variant::Variant::Builder initValue();
|
||||
inline void adoptValue(::capnp::Orphan< ::stream::variant::Variant>&& value);
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> disownValue();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class MetaDataEntry::Pipeline {
|
||||
public:
|
||||
typedef MetaDataEntry Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::variant::Variant::Pipeline getValue();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class MetaData::Reader {
|
||||
public:
|
||||
typedef MetaData Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasEntries() const;
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Reader getEntries() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class MetaData::Builder {
|
||||
public:
|
||||
typedef MetaData Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasEntries();
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Builder getEntries();
|
||||
inline void setEntries( ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Reader value);
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Builder initEntries(unsigned int size);
|
||||
inline void adoptEntries(::capnp::Orphan< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>> disownEntries();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class MetaData::Pipeline {
|
||||
public:
|
||||
typedef MetaData Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline bool MetaDataEntry::Reader::hasName() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool MetaDataEntry::Builder::hasName() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader MetaDataEntry::Reader::getName() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder MetaDataEntry::Builder::getName() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void MetaDataEntry::Builder::setName( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder MetaDataEntry::Builder::initName(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void MetaDataEntry::Builder::adoptName(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> MetaDataEntry::Builder::disownName() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool MetaDataEntry::Reader::hasDescription() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool MetaDataEntry::Builder::hasDescription() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader MetaDataEntry::Reader::getDescription() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder MetaDataEntry::Builder::getDescription() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void MetaDataEntry::Builder::setDescription( ::capnp::Text::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder MetaDataEntry::Builder::initDescription(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void MetaDataEntry::Builder::adoptDescription(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> MetaDataEntry::Builder::disownDescription() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool MetaDataEntry::Reader::hasValue() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool MetaDataEntry::Builder::hasValue() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::variant::Variant::Reader MetaDataEntry::Reader::getValue() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_reader.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder MetaDataEntry::Builder::getValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::variant::Variant::Pipeline MetaDataEntry::Pipeline::getValue() {
|
||||
return ::stream::variant::Variant::Pipeline(_typeless.getPointerField(2));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void MetaDataEntry::Builder::setValue( ::stream::variant::Variant::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::set(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder MetaDataEntry::Builder::initValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::init(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void MetaDataEntry::Builder::adoptValue(
|
||||
::capnp::Orphan< ::stream::variant::Variant>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> MetaDataEntry::Builder::disownValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<2>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool MetaData::Reader::hasEntries() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool MetaData::Builder::hasEntries() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Reader MetaData::Reader::getEntries() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Builder MetaData::Builder::getEntries() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void MetaData::Builder::setEntries( ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>::Builder MetaData::Builder::initEntries(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void MetaData::Builder::adoptEntries(
|
||||
::capnp::Orphan< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>> MetaData::Builder::disownEntries() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::metaData::MetaDataEntry, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: metaDataView.capnp
|
||||
|
||||
#include "metaDataView.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<33> b_8ff3115ade0dced6 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
214, 206, 13, 222, 90, 17, 243, 143,
|
||||
19, 0, 0, 0, 1, 0, 0, 0,
|
||||
37, 235, 246, 245, 136, 214, 1, 244,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 2, 1, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 101, 116, 97, 68, 97, 116, 97,
|
||||
86, 105, 101, 119, 46, 99, 97, 112,
|
||||
110, 112, 58, 77, 101, 116, 97, 68,
|
||||
97, 116, 97, 86, 105, 101, 119, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 0, 0, 0, 3, 0, 1, 0,
|
||||
20, 0, 0, 0, 2, 0, 1, 0,
|
||||
100, 97, 116, 97, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
56, 212, 213, 232, 233, 209, 66, 147,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_8ff3115ade0dced6 = b_8ff3115ade0dced6.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_8ff3115ade0dced6[] = {
|
||||
&s_9342d1e9e8d5d438,
|
||||
};
|
||||
static const uint16_t m_8ff3115ade0dced6[] = {0};
|
||||
static const uint16_t i_8ff3115ade0dced6[] = {0};
|
||||
const ::capnp::_::RawSchema s_8ff3115ade0dced6 = {
|
||||
0x8ff3115ade0dced6, b_8ff3115ade0dced6.words, 33, d_8ff3115ade0dced6, m_8ff3115ade0dced6,
|
||||
1, 1, i_8ff3115ade0dced6, nullptr, nullptr, { &s_8ff3115ade0dced6, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace metaDataView {
|
||||
|
||||
// MetaDataView
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t MetaDataView::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t MetaDataView::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind MetaDataView::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* MetaDataView::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: metaDataView.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
#include "metaData.capnp.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(8ff3115ade0dced6);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace metaDataView {
|
||||
|
||||
struct MetaDataView {
|
||||
MetaDataView() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(8ff3115ade0dced6, 0, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class MetaDataView::Reader {
|
||||
public:
|
||||
typedef MetaDataView Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasData() const;
|
||||
inline ::stream::metaData::MetaData::Reader getData() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class MetaDataView::Builder {
|
||||
public:
|
||||
typedef MetaDataView Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasData();
|
||||
inline ::stream::metaData::MetaData::Builder getData();
|
||||
inline void setData( ::stream::metaData::MetaData::Reader value);
|
||||
inline ::stream::metaData::MetaData::Builder initData();
|
||||
inline void adoptData(::capnp::Orphan< ::stream::metaData::MetaData>&& value);
|
||||
inline ::capnp::Orphan< ::stream::metaData::MetaData> disownData();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class MetaDataView::Pipeline {
|
||||
public:
|
||||
typedef MetaDataView Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::metaData::MetaData::Pipeline getData();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline bool MetaDataView::Reader::hasData() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool MetaDataView::Builder::hasData() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Reader MetaDataView::Reader::getData() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Builder MetaDataView::Builder::getData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::metaData::MetaData::Pipeline MetaDataView::Pipeline::getData() {
|
||||
return ::stream::metaData::MetaData::Pipeline(_typeless.getPointerField(0));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void MetaDataView::Builder::setData( ::stream::metaData::MetaData::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::metaData::MetaData::Builder MetaDataView::Builder::initData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void MetaDataView::Builder::adoptData(
|
||||
::capnp::Orphan< ::stream::metaData::MetaData>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::metaData::MetaData> MetaDataView::Builder::disownData() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::metaData::MetaData>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: propertySet.capnp
|
||||
|
||||
#include "propertySet.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<49> b_ab971fd3eda1ed27 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
39, 237, 161, 237, 211, 31, 151, 171,
|
||||
18, 0, 0, 0, 1, 0, 1, 0,
|
||||
244, 191, 20, 32, 245, 192, 68, 163,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 250, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 119, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 114, 111, 112, 101, 114, 116, 121,
|
||||
83, 101, 116, 46, 99, 97, 112, 110,
|
||||
112, 58, 80, 114, 111, 112, 101, 114,
|
||||
116, 121, 78, 97, 109, 101, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
8, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 98, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 0, 0, 0, 3, 0, 1, 0,
|
||||
52, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
49, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
44, 0, 0, 0, 3, 0, 1, 0,
|
||||
56, 0, 0, 0, 2, 0, 1, 0,
|
||||
110, 97, 109, 101, 115, 112, 97, 99,
|
||||
101, 73, 100, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 97, 109, 101, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_ab971fd3eda1ed27 = b_ab971fd3eda1ed27.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_ab971fd3eda1ed27[] = {
|
||||
&s_f96a70ebaebd19c6,
|
||||
};
|
||||
static const uint16_t m_ab971fd3eda1ed27[] = {1, 0};
|
||||
static const uint16_t i_ab971fd3eda1ed27[] = {0, 1};
|
||||
const ::capnp::_::RawSchema s_ab971fd3eda1ed27 = {
|
||||
0xab971fd3eda1ed27, b_ab971fd3eda1ed27.words, 49, d_ab971fd3eda1ed27, m_ab971fd3eda1ed27,
|
||||
1, 2, i_ab971fd3eda1ed27, nullptr, nullptr, { &s_ab971fd3eda1ed27, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<48> b_c5163eb42a82d19a = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
154, 209, 130, 42, 180, 62, 22, 197,
|
||||
18, 0, 0, 0, 1, 0, 1, 0,
|
||||
244, 191, 20, 32, 245, 192, 68, 163,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 234, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 119, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 114, 111, 112, 101, 114, 116, 121,
|
||||
83, 101, 116, 46, 99, 97, 112, 110,
|
||||
112, 58, 78, 97, 109, 101, 100, 86,
|
||||
97, 108, 117, 101, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
8, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 0, 0, 3, 0, 1, 0,
|
||||
48, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 0, 0, 0, 3, 0, 1, 0,
|
||||
52, 0, 0, 0, 2, 0, 1, 0,
|
||||
110, 97, 109, 101, 73, 100, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 108, 117, 101, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_c5163eb42a82d19a = b_c5163eb42a82d19a.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_c5163eb42a82d19a[] = {
|
||||
&s_f96a70ebaebd19c6,
|
||||
};
|
||||
static const uint16_t m_c5163eb42a82d19a[] = {0, 1};
|
||||
static const uint16_t i_c5163eb42a82d19a[] = {0, 1};
|
||||
const ::capnp::_::RawSchema s_c5163eb42a82d19a = {
|
||||
0xc5163eb42a82d19a, b_c5163eb42a82d19a.words, 48, d_c5163eb42a82d19a, m_c5163eb42a82d19a,
|
||||
1, 2, i_c5163eb42a82d19a, nullptr, nullptr, { &s_c5163eb42a82d19a, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<38> b_ee9f1a259aa6017f = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
127, 1, 166, 154, 37, 26, 159, 238,
|
||||
18, 0, 0, 0, 1, 0, 0, 0,
|
||||
244, 191, 20, 32, 245, 192, 68, 163,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 242, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 114, 111, 112, 101, 114, 116, 121,
|
||||
83, 101, 116, 46, 99, 97, 112, 110,
|
||||
112, 58, 80, 114, 111, 112, 101, 114,
|
||||
116, 121, 83, 101, 116, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 0, 0, 0, 90, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 3, 0, 1, 0,
|
||||
40, 0, 0, 0, 2, 0, 1, 0,
|
||||
112, 114, 111, 112, 101, 114, 116, 105,
|
||||
101, 115, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
154, 209, 130, 42, 180, 62, 22, 197,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_ee9f1a259aa6017f = b_ee9f1a259aa6017f.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_ee9f1a259aa6017f[] = {
|
||||
&s_c5163eb42a82d19a,
|
||||
};
|
||||
static const uint16_t m_ee9f1a259aa6017f[] = {0};
|
||||
static const uint16_t i_ee9f1a259aa6017f[] = {0};
|
||||
const ::capnp::_::RawSchema s_ee9f1a259aa6017f = {
|
||||
0xee9f1a259aa6017f, b_ee9f1a259aa6017f.words, 38, d_ee9f1a259aa6017f, m_ee9f1a259aa6017f,
|
||||
1, 1, i_ee9f1a259aa6017f, nullptr, nullptr, { &s_ee9f1a259aa6017f, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace propertySet {
|
||||
|
||||
// PropertyName
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t PropertyName::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t PropertyName::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind PropertyName::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* PropertyName::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// NamedValue
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t NamedValue::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t NamedValue::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind NamedValue::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* NamedValue::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// PropertySet
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t PropertySet::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t PropertySet::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind PropertySet::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* PropertySet::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,480 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: propertySet.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
#include "variant.capnp.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(ab971fd3eda1ed27);
|
||||
CAPNP_DECLARE_SCHEMA(c5163eb42a82d19a);
|
||||
CAPNP_DECLARE_SCHEMA(ee9f1a259aa6017f);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace propertySet {
|
||||
|
||||
struct PropertyName {
|
||||
PropertyName() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(ab971fd3eda1ed27, 1, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct NamedValue {
|
||||
NamedValue() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(c5163eb42a82d19a, 1, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct PropertySet {
|
||||
PropertySet() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(ee9f1a259aa6017f, 0, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class PropertyName::Reader {
|
||||
public:
|
||||
typedef PropertyName Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline ::uint64_t getNamespaceId() const;
|
||||
|
||||
inline bool hasName() const;
|
||||
inline ::stream::variant::Variant::Reader getName() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class PropertyName::Builder {
|
||||
public:
|
||||
typedef PropertyName Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline ::uint64_t getNamespaceId();
|
||||
inline void setNamespaceId( ::uint64_t value);
|
||||
|
||||
inline bool hasName();
|
||||
inline ::stream::variant::Variant::Builder getName();
|
||||
inline void setName( ::stream::variant::Variant::Reader value);
|
||||
inline ::stream::variant::Variant::Builder initName();
|
||||
inline void adoptName(::capnp::Orphan< ::stream::variant::Variant>&& value);
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> disownName();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class PropertyName::Pipeline {
|
||||
public:
|
||||
typedef PropertyName Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::variant::Variant::Pipeline getName();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class NamedValue::Reader {
|
||||
public:
|
||||
typedef NamedValue Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline ::uint64_t getNameId() const;
|
||||
|
||||
inline bool hasValue() const;
|
||||
inline ::stream::variant::Variant::Reader getValue() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class NamedValue::Builder {
|
||||
public:
|
||||
typedef NamedValue Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline ::uint64_t getNameId();
|
||||
inline void setNameId( ::uint64_t value);
|
||||
|
||||
inline bool hasValue();
|
||||
inline ::stream::variant::Variant::Builder getValue();
|
||||
inline void setValue( ::stream::variant::Variant::Reader value);
|
||||
inline ::stream::variant::Variant::Builder initValue();
|
||||
inline void adoptValue(::capnp::Orphan< ::stream::variant::Variant>&& value);
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> disownValue();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class NamedValue::Pipeline {
|
||||
public:
|
||||
typedef NamedValue Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::variant::Variant::Pipeline getValue();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class PropertySet::Reader {
|
||||
public:
|
||||
typedef PropertySet Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasProperties() const;
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Reader getProperties() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class PropertySet::Builder {
|
||||
public:
|
||||
typedef PropertySet Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasProperties();
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Builder getProperties();
|
||||
inline void setProperties( ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Reader value);
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Builder initProperties(unsigned int size);
|
||||
inline void adoptProperties(::capnp::Orphan< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>> disownProperties();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class PropertySet::Pipeline {
|
||||
public:
|
||||
typedef PropertySet Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline ::uint64_t PropertyName::Reader::getNamespaceId() const {
|
||||
return _reader.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::uint64_t PropertyName::Builder::getNamespaceId() {
|
||||
return _builder.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void PropertyName::Builder::setNamespaceId( ::uint64_t value) {
|
||||
_builder.setDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool PropertyName::Reader::hasName() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool PropertyName::Builder::hasName() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::variant::Variant::Reader PropertyName::Reader::getName() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder PropertyName::Builder::getName() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::variant::Variant::Pipeline PropertyName::Pipeline::getName() {
|
||||
return ::stream::variant::Variant::Pipeline(_typeless.getPointerField(0));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void PropertyName::Builder::setName( ::stream::variant::Variant::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder PropertyName::Builder::initName() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void PropertyName::Builder::adoptName(
|
||||
::capnp::Orphan< ::stream::variant::Variant>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> PropertyName::Builder::disownName() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline ::uint64_t NamedValue::Reader::getNameId() const {
|
||||
return _reader.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::uint64_t NamedValue::Builder::getNameId() {
|
||||
return _builder.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void NamedValue::Builder::setNameId( ::uint64_t value) {
|
||||
_builder.setDataField< ::uint64_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool NamedValue::Reader::hasValue() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool NamedValue::Builder::hasValue() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::variant::Variant::Reader NamedValue::Reader::getValue() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder NamedValue::Builder::getValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::variant::Variant::Pipeline NamedValue::Pipeline::getValue() {
|
||||
return ::stream::variant::Variant::Pipeline(_typeless.getPointerField(0));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void NamedValue::Builder::setValue( ::stream::variant::Variant::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder NamedValue::Builder::initValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void NamedValue::Builder::adoptValue(
|
||||
::capnp::Orphan< ::stream::variant::Variant>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> NamedValue::Builder::disownValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool PropertySet::Reader::hasProperties() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool PropertySet::Builder::hasProperties() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Reader PropertySet::Reader::getProperties() const {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Builder PropertySet::Builder::getProperties() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void PropertySet::Builder::setProperties( ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>::Builder PropertySet::Builder::initProperties(unsigned int size) {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void PropertySet::Builder::adoptProperties(
|
||||
::capnp::Orphan< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>&& value) {
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>> PropertySet::Builder::disownProperties() {
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::propertySet::NamedValue, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
|
|
@ -0,0 +1,452 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: repetition.capnp
|
||||
|
||||
#include "repetition.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<79> b_9425aecc5b90c16e = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
110, 193, 144, 91, 204, 174, 37, 148,
|
||||
17, 0, 0, 0, 1, 0, 4, 0,
|
||||
55, 226, 130, 50, 37, 72, 69, 156,
|
||||
0, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 66, 1, 0, 0,
|
||||
37, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 0, 0, 0, 231, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 46, 99, 97, 112, 110, 112,
|
||||
58, 82, 101, 103, 117, 108, 97, 114,
|
||||
79, 114, 116, 104, 111, 82, 101, 112,
|
||||
101, 116, 105, 116, 105, 111, 110, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
16, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
97, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
92, 0, 0, 0, 3, 0, 1, 0,
|
||||
104, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
101, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 0, 0, 0, 3, 0, 1, 0,
|
||||
108, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 2, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 0, 0, 0, 3, 0, 1, 0,
|
||||
112, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 0, 0, 0, 3, 0, 1, 0,
|
||||
116, 0, 0, 0, 2, 0, 1, 0,
|
||||
100, 120, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 121, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 120, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 121, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_9425aecc5b90c16e = b_9425aecc5b90c16e.words;
|
||||
#if !CAPNP_LITE
|
||||
static const uint16_t m_9425aecc5b90c16e[] = {0, 1, 2, 3};
|
||||
static const uint16_t i_9425aecc5b90c16e[] = {0, 1, 2, 3};
|
||||
const ::capnp::_::RawSchema s_9425aecc5b90c16e = {
|
||||
0x9425aecc5b90c16e, b_9425aecc5b90c16e.words, 79, nullptr, m_9425aecc5b90c16e,
|
||||
0, 4, i_9425aecc5b90c16e, nullptr, nullptr, { &s_9425aecc5b90c16e, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<79> b_8ad514566ec69992 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
146, 153, 198, 110, 86, 20, 213, 138,
|
||||
17, 0, 0, 0, 1, 0, 2, 0,
|
||||
55, 226, 130, 50, 37, 72, 69, 156,
|
||||
2, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 26, 1, 0, 0,
|
||||
37, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 0, 0, 0, 231, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 46, 99, 97, 112, 110, 112,
|
||||
58, 82, 101, 103, 117, 108, 97, 114,
|
||||
82, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
16, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
97, 0, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
92, 0, 0, 0, 3, 0, 1, 0,
|
||||
104, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
101, 0, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 0, 0, 0, 3, 0, 1, 0,
|
||||
108, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 0, 0, 0, 3, 0, 1, 0,
|
||||
112, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 0, 0, 0, 3, 0, 1, 0,
|
||||
116, 0, 0, 0, 2, 0, 1, 0,
|
||||
97, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
169, 23, 16, 131, 13, 157, 234, 195,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
98, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
169, 23, 16, 131, 13, 157, 234, 195,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 97, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 98, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_8ad514566ec69992 = b_8ad514566ec69992.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_8ad514566ec69992[] = {
|
||||
&s_c3ea9d0d831017a9,
|
||||
};
|
||||
static const uint16_t m_8ad514566ec69992[] = {0, 1, 2, 3};
|
||||
static const uint16_t i_8ad514566ec69992[] = {0, 1, 2, 3};
|
||||
const ::capnp::_::RawSchema s_8ad514566ec69992 = {
|
||||
0x8ad514566ec69992, b_8ad514566ec69992.words, 79, d_8ad514566ec69992, m_8ad514566ec69992,
|
||||
1, 4, i_8ad514566ec69992, nullptr, nullptr, { &s_8ad514566ec69992, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<38> b_ba39d45a51b9e73b = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
59, 231, 185, 81, 90, 212, 57, 186,
|
||||
17, 0, 0, 0, 1, 0, 0, 0,
|
||||
55, 226, 130, 50, 37, 72, 69, 156,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 50, 1, 0, 0,
|
||||
37, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 46, 99, 97, 112, 110, 112,
|
||||
58, 69, 110, 117, 109, 101, 114, 97,
|
||||
116, 101, 100, 82, 101, 112, 101, 116,
|
||||
105, 116, 105, 111, 110, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 0, 0, 0, 3, 0, 1, 0,
|
||||
36, 0, 0, 0, 2, 0, 1, 0,
|
||||
100, 101, 108, 116, 97, 115, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
169, 23, 16, 131, 13, 157, 234, 195,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_ba39d45a51b9e73b = b_ba39d45a51b9e73b.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_ba39d45a51b9e73b[] = {
|
||||
&s_c3ea9d0d831017a9,
|
||||
};
|
||||
static const uint16_t m_ba39d45a51b9e73b[] = {0};
|
||||
static const uint16_t i_ba39d45a51b9e73b[] = {0};
|
||||
const ::capnp::_::RawSchema s_ba39d45a51b9e73b = {
|
||||
0xba39d45a51b9e73b, b_ba39d45a51b9e73b.words, 38, d_ba39d45a51b9e73b, m_ba39d45a51b9e73b,
|
||||
1, 1, i_ba39d45a51b9e73b, nullptr, nullptr, { &s_ba39d45a51b9e73b, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<26> b_927c0face2bd19e7 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
231, 25, 189, 226, 172, 15, 124, 146,
|
||||
17, 0, 0, 0, 1, 0, 1, 0,
|
||||
55, 226, 130, 50, 37, 72, 69, 156,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 226, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 46, 99, 97, 112, 110, 112,
|
||||
58, 82, 101, 112, 101, 116, 105, 116,
|
||||
105, 111, 110, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
221, 231, 117, 117, 81, 203, 55, 148,
|
||||
13, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 121, 112, 101, 115, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_927c0face2bd19e7 = b_927c0face2bd19e7.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_927c0face2bd19e7[] = {
|
||||
&s_9437cb517575e7dd,
|
||||
};
|
||||
static const uint16_t m_927c0face2bd19e7[] = {0};
|
||||
static const uint16_t i_927c0face2bd19e7[] = {0};
|
||||
const ::capnp::_::RawSchema s_927c0face2bd19e7 = {
|
||||
0x927c0face2bd19e7, b_927c0face2bd19e7.words, 26, d_927c0face2bd19e7, m_927c0face2bd19e7,
|
||||
1, 1, i_927c0face2bd19e7, nullptr, nullptr, { &s_927c0face2bd19e7, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<80> b_9437cb517575e7dd = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
221, 231, 117, 117, 81, 203, 55, 148,
|
||||
28, 0, 0, 0, 1, 0, 1, 0,
|
||||
231, 25, 189, 226, 172, 15, 124, 146,
|
||||
1, 0, 7, 0, 1, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 18, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 231, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 112, 101, 116, 105, 116, 105,
|
||||
111, 110, 46, 99, 97, 112, 110, 112,
|
||||
58, 82, 101, 112, 101, 116, 105, 116,
|
||||
105, 111, 110, 46, 116, 121, 112, 101,
|
||||
115, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 255, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
97, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
92, 0, 0, 0, 3, 0, 1, 0,
|
||||
104, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 254, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
101, 0, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 0, 0, 0, 3, 0, 1, 0,
|
||||
108, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 253, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 0, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 0, 0, 0, 3, 0, 1, 0,
|
||||
116, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 252, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
113, 0, 0, 0, 90, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 0, 0, 0, 3, 0, 1, 0,
|
||||
124, 0, 0, 0, 2, 0, 1, 0,
|
||||
115, 105, 110, 103, 108, 101, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
169, 23, 16, 131, 13, 157, 234, 195,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 103, 117, 108, 97, 114, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
146, 153, 198, 110, 86, 20, 213, 138,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
114, 101, 103, 117, 108, 97, 114, 79,
|
||||
114, 116, 104, 111, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
110, 193, 144, 91, 204, 174, 37, 148,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
101, 110, 117, 109, 101, 114, 97, 116,
|
||||
101, 100, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
59, 231, 185, 81, 90, 212, 57, 186,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_9437cb517575e7dd = b_9437cb517575e7dd.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_9437cb517575e7dd[] = {
|
||||
&s_8ad514566ec69992,
|
||||
&s_927c0face2bd19e7,
|
||||
&s_9425aecc5b90c16e,
|
||||
&s_ba39d45a51b9e73b,
|
||||
&s_c3ea9d0d831017a9,
|
||||
};
|
||||
static const uint16_t m_9437cb517575e7dd[] = {3, 1, 2, 0};
|
||||
static const uint16_t i_9437cb517575e7dd[] = {0, 1, 2, 3};
|
||||
const ::capnp::_::RawSchema s_9437cb517575e7dd = {
|
||||
0x9437cb517575e7dd, b_9437cb517575e7dd.words, 80, d_9437cb517575e7dd, m_9437cb517575e7dd,
|
||||
5, 4, i_9437cb517575e7dd, nullptr, nullptr, { &s_9437cb517575e7dd, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace repetition {
|
||||
|
||||
// RegularOrthoRepetition
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t RegularOrthoRepetition::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t RegularOrthoRepetition::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind RegularOrthoRepetition::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* RegularOrthoRepetition::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// RegularRepetition
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t RegularRepetition::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t RegularRepetition::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind RegularRepetition::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* RegularRepetition::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// EnumeratedRepetition
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t EnumeratedRepetition::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t EnumeratedRepetition::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind EnumeratedRepetition::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* EnumeratedRepetition::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// Repetition
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Repetition::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Repetition::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Repetition::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Repetition::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// Repetition::Types
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Repetition::Types::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Repetition::Types::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Repetition::Types::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Repetition::Types::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,331 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: variant.capnp
|
||||
|
||||
#include "variant.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<48> b_dcf203025f9c6db8 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
184, 109, 156, 95, 2, 3, 242, 220,
|
||||
14, 0, 0, 0, 1, 0, 0, 0,
|
||||
66, 164, 246, 229, 82, 216, 227, 146,
|
||||
2, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 202, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 119, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 114, 105, 97, 110, 116, 46,
|
||||
99, 97, 112, 110, 112, 58, 65, 114,
|
||||
114, 97, 121, 69, 110, 116, 114, 121,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
8, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 34, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 0, 0, 3, 0, 1, 0,
|
||||
48, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 0, 0, 0, 3, 0, 1, 0,
|
||||
52, 0, 0, 0, 2, 0, 1, 0,
|
||||
107, 101, 121, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 108, 117, 101, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_dcf203025f9c6db8 = b_dcf203025f9c6db8.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_dcf203025f9c6db8[] = {
|
||||
&s_f96a70ebaebd19c6,
|
||||
};
|
||||
static const uint16_t m_dcf203025f9c6db8[] = {0, 1};
|
||||
static const uint16_t i_dcf203025f9c6db8[] = {0, 1};
|
||||
const ::capnp::_::RawSchema s_dcf203025f9c6db8 = {
|
||||
0xdcf203025f9c6db8, b_dcf203025f9c6db8.words, 48, d_dcf203025f9c6db8, m_dcf203025f9c6db8,
|
||||
1, 2, i_dcf203025f9c6db8, nullptr, nullptr, { &s_dcf203025f9c6db8, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<25> b_f96a70ebaebd19c6 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
14, 0, 0, 0, 1, 0, 2, 0,
|
||||
66, 164, 246, 229, 82, 216, 227, 146,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 178, 0, 0, 0,
|
||||
29, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 0, 0, 0, 63, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 114, 105, 97, 110, 116, 46,
|
||||
99, 97, 112, 110, 112, 58, 86, 97,
|
||||
114, 105, 97, 110, 116, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
160, 103, 140, 31, 120, 18, 4, 135,
|
||||
13, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 108, 117, 101, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_f96a70ebaebd19c6 = b_f96a70ebaebd19c6.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_f96a70ebaebd19c6[] = {
|
||||
&s_870412781f8c67a0,
|
||||
};
|
||||
static const uint16_t m_f96a70ebaebd19c6[] = {0};
|
||||
static const uint16_t i_f96a70ebaebd19c6[] = {0};
|
||||
const ::capnp::_::RawSchema s_f96a70ebaebd19c6 = {
|
||||
0xf96a70ebaebd19c6, b_f96a70ebaebd19c6.words, 25, d_f96a70ebaebd19c6, m_f96a70ebaebd19c6,
|
||||
1, 1, i_f96a70ebaebd19c6, nullptr, nullptr, { &s_f96a70ebaebd19c6, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<160> b_870412781f8c67a0 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
160, 103, 140, 31, 120, 18, 4, 135,
|
||||
22, 0, 0, 0, 1, 0, 2, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
1, 0, 7, 0, 1, 0, 9, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 226, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 0, 0, 0, 255, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 97, 114, 105, 97, 110, 116, 46,
|
||||
99, 97, 112, 110, 112, 58, 86, 97,
|
||||
114, 105, 97, 110, 116, 46, 118, 97,
|
||||
108, 117, 101, 0, 0, 0, 0, 0,
|
||||
36, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 255, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
237, 0, 0, 0, 34, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
232, 0, 0, 0, 3, 0, 1, 0,
|
||||
244, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 254, 255, 16, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
241, 0, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
236, 0, 0, 0, 3, 0, 1, 0,
|
||||
248, 0, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 253, 255, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
245, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
240, 0, 0, 0, 3, 0, 1, 0,
|
||||
252, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 252, 255, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
249, 0, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
244, 0, 0, 0, 3, 0, 1, 0,
|
||||
0, 1, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 251, 255, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
253, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
248, 0, 0, 0, 3, 0, 1, 0,
|
||||
4, 1, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 250, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
252, 0, 0, 0, 3, 0, 1, 0,
|
||||
8, 1, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 249, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 1, 0, 0, 42, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 3, 0, 1, 0,
|
||||
28, 1, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 248, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 1, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
20, 1, 0, 0, 3, 0, 1, 0,
|
||||
48, 1, 0, 0, 2, 0, 1, 0,
|
||||
8, 0, 247, 255, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 1, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 1, 0, 0, 3, 0, 1, 0,
|
||||
52, 1, 0, 0, 2, 0, 1, 0,
|
||||
110, 105, 108, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
98, 111, 111, 108, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
117, 105, 110, 116, 54, 52, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 110, 116, 54, 52, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 111, 117, 98, 108, 101, 0, 0,
|
||||
11, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
11, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 101, 120, 116, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 105, 115, 116, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
198, 25, 189, 174, 235, 112, 106, 249,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
97, 114, 114, 97, 121, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0, 1, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
184, 109, 156, 95, 2, 3, 242, 220,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
111, 98, 106, 101, 99, 116, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_870412781f8c67a0 = b_870412781f8c67a0.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_870412781f8c67a0[] = {
|
||||
&s_dcf203025f9c6db8,
|
||||
&s_f96a70ebaebd19c6,
|
||||
};
|
||||
static const uint16_t m_870412781f8c67a0[] = {7, 1, 4, 3, 6, 0, 8, 5, 2};
|
||||
static const uint16_t i_870412781f8c67a0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const ::capnp::_::RawSchema s_870412781f8c67a0 = {
|
||||
0x870412781f8c67a0, b_870412781f8c67a0.words, 160, d_870412781f8c67a0, m_870412781f8c67a0,
|
||||
2, 9, i_870412781f8c67a0, nullptr, nullptr, { &s_870412781f8c67a0, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace stream {
|
||||
namespace variant {
|
||||
|
||||
// ArrayEntry
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t ArrayEntry::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t ArrayEntry::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind ArrayEntry::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* ArrayEntry::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// Variant
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Variant::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Variant::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Variant::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Variant::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// Variant::Value
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t Variant::Value::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t Variant::Value::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind Variant::Value::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* Variant::Value::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,873 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: variant.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(dcf203025f9c6db8);
|
||||
CAPNP_DECLARE_SCHEMA(f96a70ebaebd19c6);
|
||||
CAPNP_DECLARE_SCHEMA(870412781f8c67a0);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace stream {
|
||||
namespace variant {
|
||||
|
||||
struct ArrayEntry {
|
||||
ArrayEntry() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(dcf203025f9c6db8, 0, 2)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct Variant {
|
||||
Variant() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
struct Value;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(f96a70ebaebd19c6, 2, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct Variant::Value {
|
||||
Value() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
enum Which: uint16_t {
|
||||
NIL,
|
||||
BOOL,
|
||||
UINT64,
|
||||
INT64,
|
||||
DOUBLE,
|
||||
TEXT,
|
||||
LIST,
|
||||
ARRAY,
|
||||
OBJECT,
|
||||
};
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(870412781f8c67a0, 2, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class ArrayEntry::Reader {
|
||||
public:
|
||||
typedef ArrayEntry Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasKey() const;
|
||||
inline ::stream::variant::Variant::Reader getKey() const;
|
||||
|
||||
inline bool hasValue() const;
|
||||
inline ::stream::variant::Variant::Reader getValue() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class ArrayEntry::Builder {
|
||||
public:
|
||||
typedef ArrayEntry Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool hasKey();
|
||||
inline ::stream::variant::Variant::Builder getKey();
|
||||
inline void setKey( ::stream::variant::Variant::Reader value);
|
||||
inline ::stream::variant::Variant::Builder initKey();
|
||||
inline void adoptKey(::capnp::Orphan< ::stream::variant::Variant>&& value);
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> disownKey();
|
||||
|
||||
inline bool hasValue();
|
||||
inline ::stream::variant::Variant::Builder getValue();
|
||||
inline void setValue( ::stream::variant::Variant::Reader value);
|
||||
inline ::stream::variant::Variant::Builder initValue();
|
||||
inline void adoptValue(::capnp::Orphan< ::stream::variant::Variant>&& value);
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> disownValue();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class ArrayEntry::Pipeline {
|
||||
public:
|
||||
typedef ArrayEntry Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline ::stream::variant::Variant::Pipeline getKey();
|
||||
inline ::stream::variant::Variant::Pipeline getValue();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class Variant::Reader {
|
||||
public:
|
||||
typedef Variant Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline typename Value::Reader getValue() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class Variant::Builder {
|
||||
public:
|
||||
typedef Variant Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline typename Value::Builder getValue();
|
||||
inline typename Value::Builder initValue();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class Variant::Pipeline {
|
||||
public:
|
||||
typedef Variant Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline typename Value::Pipeline getValue();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class Variant::Value::Reader {
|
||||
public:
|
||||
typedef Value Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline Which which() const;
|
||||
inline bool isNil() const;
|
||||
inline ::capnp::Void getNil() const;
|
||||
|
||||
inline bool isBool() const;
|
||||
inline bool getBool() const;
|
||||
|
||||
inline bool isUint64() const;
|
||||
inline ::uint64_t getUint64() const;
|
||||
|
||||
inline bool isInt64() const;
|
||||
inline ::int64_t getInt64() const;
|
||||
|
||||
inline bool isDouble() const;
|
||||
inline double getDouble() const;
|
||||
|
||||
inline bool isText() const;
|
||||
inline bool hasText() const;
|
||||
inline ::capnp::Text::Reader getText() const;
|
||||
|
||||
inline bool isList() const;
|
||||
inline bool hasList() const;
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Reader getList() const;
|
||||
|
||||
inline bool isArray() const;
|
||||
inline bool hasArray() const;
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Reader getArray() const;
|
||||
|
||||
inline bool isObject() const;
|
||||
inline bool hasObject() const;
|
||||
inline ::capnp::Text::Reader getObject() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class Variant::Value::Builder {
|
||||
public:
|
||||
typedef Value Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline Which which();
|
||||
inline bool isNil();
|
||||
inline ::capnp::Void getNil();
|
||||
inline void setNil( ::capnp::Void value = ::capnp::VOID);
|
||||
|
||||
inline bool isBool();
|
||||
inline bool getBool();
|
||||
inline void setBool(bool value);
|
||||
|
||||
inline bool isUint64();
|
||||
inline ::uint64_t getUint64();
|
||||
inline void setUint64( ::uint64_t value);
|
||||
|
||||
inline bool isInt64();
|
||||
inline ::int64_t getInt64();
|
||||
inline void setInt64( ::int64_t value);
|
||||
|
||||
inline bool isDouble();
|
||||
inline double getDouble();
|
||||
inline void setDouble(double value);
|
||||
|
||||
inline bool isText();
|
||||
inline bool hasText();
|
||||
inline ::capnp::Text::Builder getText();
|
||||
inline void setText( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initText(unsigned int size);
|
||||
inline void adoptText(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownText();
|
||||
|
||||
inline bool isList();
|
||||
inline bool hasList();
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Builder getList();
|
||||
inline void setList( ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Reader value);
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Builder initList(unsigned int size);
|
||||
inline void adoptList(::capnp::Orphan< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>> disownList();
|
||||
|
||||
inline bool isArray();
|
||||
inline bool hasArray();
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Builder getArray();
|
||||
inline void setArray( ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Reader value);
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Builder initArray(unsigned int size);
|
||||
inline void adoptArray(::capnp::Orphan< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>> disownArray();
|
||||
|
||||
inline bool isObject();
|
||||
inline bool hasObject();
|
||||
inline ::capnp::Text::Builder getObject();
|
||||
inline void setObject( ::capnp::Text::Reader value);
|
||||
inline ::capnp::Text::Builder initObject(unsigned int size);
|
||||
inline void adoptObject(::capnp::Orphan< ::capnp::Text>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::Text> disownObject();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class Variant::Value::Pipeline {
|
||||
public:
|
||||
typedef Value Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline bool ArrayEntry::Reader::hasKey() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool ArrayEntry::Builder::hasKey() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::variant::Variant::Reader ArrayEntry::Reader::getKey() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder ArrayEntry::Builder::getKey() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::variant::Variant::Pipeline ArrayEntry::Pipeline::getKey() {
|
||||
return ::stream::variant::Variant::Pipeline(_typeless.getPointerField(0));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void ArrayEntry::Builder::setKey( ::stream::variant::Variant::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder ArrayEntry::Builder::initKey() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void ArrayEntry::Builder::adoptKey(
|
||||
::capnp::Orphan< ::stream::variant::Variant>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> ArrayEntry::Builder::disownKey() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool ArrayEntry::Reader::hasValue() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool ArrayEntry::Builder::hasValue() {
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::stream::variant::Variant::Reader ArrayEntry::Reader::getValue() const {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder ArrayEntry::Builder::getValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline ::stream::variant::Variant::Pipeline ArrayEntry::Pipeline::getValue() {
|
||||
return ::stream::variant::Variant::Pipeline(_typeless.getPointerField(1));
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline void ArrayEntry::Builder::setValue( ::stream::variant::Variant::Reader value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::stream::variant::Variant::Builder ArrayEntry::Builder::initValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void ArrayEntry::Builder::adoptValue(
|
||||
::capnp::Orphan< ::stream::variant::Variant>&& value) {
|
||||
::capnp::_::PointerHelpers< ::stream::variant::Variant>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::stream::variant::Variant> ArrayEntry::Builder::disownValue() {
|
||||
return ::capnp::_::PointerHelpers< ::stream::variant::Variant>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline typename Variant::Value::Reader Variant::Reader::getValue() const {
|
||||
return typename Variant::Value::Reader(_reader);
|
||||
}
|
||||
inline typename Variant::Value::Builder Variant::Builder::getValue() {
|
||||
return typename Variant::Value::Builder(_builder);
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline typename Variant::Value::Pipeline Variant::Pipeline::getValue() {
|
||||
return typename Variant::Value::Pipeline(_typeless.noop());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline typename Variant::Value::Builder Variant::Builder::initValue() {
|
||||
_builder.setDataField< ::uint16_t>(::capnp::bounded<0>() * ::capnp::ELEMENTS, 0);
|
||||
_builder.setDataField<bool>(::capnp::bounded<16>() * ::capnp::ELEMENTS, 0);
|
||||
_builder.setDataField< ::uint64_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0);
|
||||
_builder.getPointerField(::capnp::bounded<0>() * ::capnp::POINTERS).clear();
|
||||
return typename Variant::Value::Builder(_builder);
|
||||
}
|
||||
inline ::stream::variant::Variant::Value::Which Variant::Value::Reader::which() const {
|
||||
return _reader.getDataField<Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline ::stream::variant::Variant::Value::Which Variant::Value::Builder::which() {
|
||||
return _builder.getDataField<Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isNil() const {
|
||||
return which() == Variant::Value::NIL;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isNil() {
|
||||
return which() == Variant::Value::NIL;
|
||||
}
|
||||
inline ::capnp::Void Variant::Value::Reader::getNil() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::NIL),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _reader.getDataField< ::capnp::Void>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::capnp::Void Variant::Value::Builder::getNil() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::NIL),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _builder.getDataField< ::capnp::Void>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void Variant::Value::Builder::setNil( ::capnp::Void value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::NIL);
|
||||
_builder.setDataField< ::capnp::Void>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isBool() const {
|
||||
return which() == Variant::Value::BOOL;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isBool() {
|
||||
return which() == Variant::Value::BOOL;
|
||||
}
|
||||
inline bool Variant::Value::Reader::getBool() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::BOOL),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<16>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Builder::getBool() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::BOOL),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<16>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void Variant::Value::Builder::setBool(bool value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::BOOL);
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<16>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isUint64() const {
|
||||
return which() == Variant::Value::UINT64;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isUint64() {
|
||||
return which() == Variant::Value::UINT64;
|
||||
}
|
||||
inline ::uint64_t Variant::Value::Reader::getUint64() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::UINT64),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _reader.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::uint64_t Variant::Value::Builder::getUint64() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::UINT64),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _builder.getDataField< ::uint64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void Variant::Value::Builder::setUint64( ::uint64_t value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::UINT64);
|
||||
_builder.setDataField< ::uint64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isInt64() const {
|
||||
return which() == Variant::Value::INT64;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isInt64() {
|
||||
return which() == Variant::Value::INT64;
|
||||
}
|
||||
inline ::int64_t Variant::Value::Reader::getInt64() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::INT64),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _reader.getDataField< ::int64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::int64_t Variant::Value::Builder::getInt64() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::INT64),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _builder.getDataField< ::int64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void Variant::Value::Builder::setInt64( ::int64_t value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::INT64);
|
||||
_builder.setDataField< ::int64_t>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isDouble() const {
|
||||
return which() == Variant::Value::DOUBLE;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isDouble() {
|
||||
return which() == Variant::Value::DOUBLE;
|
||||
}
|
||||
inline double Variant::Value::Reader::getDouble() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::DOUBLE),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _reader.getDataField<double>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline double Variant::Value::Builder::getDouble() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::DOUBLE),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return _builder.getDataField<double>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void Variant::Value::Builder::setDouble(double value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::DOUBLE);
|
||||
_builder.setDataField<double>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isText() const {
|
||||
return which() == Variant::Value::TEXT;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isText() {
|
||||
return which() == Variant::Value::TEXT;
|
||||
}
|
||||
inline bool Variant::Value::Reader::hasText() const {
|
||||
if (which() != Variant::Value::TEXT) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Variant::Value::Builder::hasText() {
|
||||
if (which() != Variant::Value::TEXT) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader Variant::Value::Reader::getText() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::TEXT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder Variant::Value::Builder::getText() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::TEXT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Variant::Value::Builder::setText( ::capnp::Text::Reader value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::TEXT);
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder Variant::Value::Builder::initText(unsigned int size) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::TEXT);
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Variant::Value::Builder::adoptText(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::TEXT);
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> Variant::Value::Builder::disownText() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::TEXT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isList() const {
|
||||
return which() == Variant::Value::LIST;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isList() {
|
||||
return which() == Variant::Value::LIST;
|
||||
}
|
||||
inline bool Variant::Value::Reader::hasList() const {
|
||||
if (which() != Variant::Value::LIST) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Variant::Value::Builder::hasList() {
|
||||
if (which() != Variant::Value::LIST) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Reader Variant::Value::Reader::getList() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::LIST),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Builder Variant::Value::Builder::getList() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::LIST),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Variant::Value::Builder::setList( ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Reader value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::LIST);
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>::Builder Variant::Value::Builder::initList(unsigned int size) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::LIST);
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Variant::Value::Builder::adoptList(
|
||||
::capnp::Orphan< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>&& value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::LIST);
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>> Variant::Value::Builder::disownList() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::LIST),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::Variant, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isArray() const {
|
||||
return which() == Variant::Value::ARRAY;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isArray() {
|
||||
return which() == Variant::Value::ARRAY;
|
||||
}
|
||||
inline bool Variant::Value::Reader::hasArray() const {
|
||||
if (which() != Variant::Value::ARRAY) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Variant::Value::Builder::hasArray() {
|
||||
if (which() != Variant::Value::ARRAY) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Reader Variant::Value::Reader::getArray() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::ARRAY),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Builder Variant::Value::Builder::getArray() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::ARRAY),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Variant::Value::Builder::setArray( ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Reader value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::ARRAY);
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>::Builder Variant::Value::Builder::initArray(unsigned int size) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::ARRAY);
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Variant::Value::Builder::adoptArray(
|
||||
::capnp::Orphan< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>&& value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::ARRAY);
|
||||
::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>> Variant::Value::Builder::disownArray() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::ARRAY),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::List< ::stream::variant::ArrayEntry, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool Variant::Value::Reader::isObject() const {
|
||||
return which() == Variant::Value::OBJECT;
|
||||
}
|
||||
inline bool Variant::Value::Builder::isObject() {
|
||||
return which() == Variant::Value::OBJECT;
|
||||
}
|
||||
inline bool Variant::Value::Reader::hasObject() const {
|
||||
if (which() != Variant::Value::OBJECT) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool Variant::Value::Builder::hasObject() {
|
||||
if (which() != Variant::Value::OBJECT) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::capnp::Text::Reader Variant::Value::Reader::getObject() const {
|
||||
KJ_IREQUIRE((which() == Variant::Value::OBJECT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::capnp::Text::Builder Variant::Value::Builder::getObject() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::OBJECT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::get(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void Variant::Value::Builder::setObject( ::capnp::Text::Reader value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::OBJECT);
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::set(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::capnp::Text::Builder Variant::Value::Builder::initObject(unsigned int size) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::OBJECT);
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::init(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), size);
|
||||
}
|
||||
inline void Variant::Value::Builder::adoptObject(
|
||||
::capnp::Orphan< ::capnp::Text>&& value) {
|
||||
_builder.setDataField<Variant::Value::Which>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, Variant::Value::OBJECT);
|
||||
::capnp::_::PointerHelpers< ::capnp::Text>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::capnp::Text> Variant::Value::Builder::disownObject() {
|
||||
KJ_IREQUIRE((which() == Variant::Value::OBJECT),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::capnp::Text>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
capnp_version=$(capnp --version)
|
||||
if [ "$capnp_version" != "Cap'n Proto version 1.0.1" ]; then
|
||||
echo "ERROR: needs capnp version 1.0.1, got '$capnp_version'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
src=(
|
||||
cell.capnp
|
||||
geometry.capnp
|
||||
header.capnp
|
||||
layoutView.capnp
|
||||
library.capnp
|
||||
metaData.capnp
|
||||
metaDataView.capnp
|
||||
propertySet.capnp
|
||||
repetition.capnp
|
||||
variant.capnp
|
||||
)
|
||||
|
||||
srcdir=$(pwd)/capnp_src
|
||||
|
||||
dest=$(pwd)/capnp
|
||||
rm -rf $dest
|
||||
mkdir $dest
|
||||
|
||||
cd $srcdir
|
||||
for f in ${src[@]}; do
|
||||
echo "Compiling $f .."
|
||||
capnp compile -o /usr/bin/capnpc-c++:$dest --src-prefix $dest -I $srcdir $f
|
||||
done
|
||||
|
||||
pri=$dest/capnp.pri
|
||||
echo "" >$pri
|
||||
echo "HEADERS=\\" >>$pri
|
||||
for f in ${src[@]}; do
|
||||
echo " capnp/$f.h \\" >>$pri
|
||||
done
|
||||
echo "" >>$pri
|
||||
|
||||
echo "SOURCES=\\" >>$pri
|
||||
for f in ${src[@]}; do
|
||||
echo " capnp/$f.c++ \\" >>$pri
|
||||
done
|
||||
echo "" >>$pri
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@0xbfd8ee64184d5def;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::cell");
|
||||
|
||||
# The Cell header
|
||||
|
||||
struct Cell
|
||||
{
|
||||
# Enumerates the views the cell provides. These are base-0 indexes
|
||||
# into the Library::viewSpecsTable::viewSpecs list. The corresponding
|
||||
# view messages follow this Cell message.
|
||||
#
|
||||
# In KLayout, a cell can have the following views:
|
||||
# "layout": the shapes and instances (LayoutView message)
|
||||
# "metaData": the cell's meta data (MetaDataView message)
|
||||
#
|
||||
# If "layout" is missing, the cell is a "ghost cell" - i.e. one
|
||||
# which does not have a content yet. Such cells are treated specially,
|
||||
# e.g. they do not appear as structures in GDS files.
|
||||
#
|
||||
# "metaData" is an optional view that holds arbitrary meta data
|
||||
# (key/value pairs) per cell.
|
||||
|
||||
viewIds @0 :List(UInt16);
|
||||
}
|
||||
|
||||
# Followed by "viewIds.size" messages with the view data
|
||||
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
@0x814220fba761a890;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::geometry");
|
||||
|
||||
# Enumerates the possible orthogonal fixpoint transformations
|
||||
enum FixPointTransformation {
|
||||
r0 @0; # no rotation
|
||||
r90 @1; # rotation by 90 degree counterclockwise
|
||||
r180 @2; # rotation by 180 degree counterclockwise
|
||||
r270 @3; # rotation by 270 degree counterclockwise
|
||||
m0 @4; # mirror at x axis ("0 degree axis")
|
||||
m45 @5; # mirror at positive x/y diagonal ("45 degree axis")
|
||||
m90 @6; # mirror at y axis ("90 degree axis")
|
||||
m135 @7; # mirror at negative x/y diagonal ("135 degree axis")
|
||||
}
|
||||
|
||||
# Implements a Vector
|
||||
# A vector is a displacement or differences between points.
|
||||
# In contrast to that, a point is a fixed position in 2d space.
|
||||
# Coordinates are always expressed as 64 bit coordinates.
|
||||
struct Vector
|
||||
{
|
||||
dx @0 :Int64;
|
||||
dy @1 :Int64;
|
||||
}
|
||||
|
||||
# A point
|
||||
# A point describes a position. In constrast to the vector,
|
||||
# the position is not the distance between two points.
|
||||
# Coordinates are always expressed as 64 bit coordinates.
|
||||
struct Point
|
||||
{
|
||||
x @0 :Int64;
|
||||
y @1 :Int64;
|
||||
}
|
||||
|
||||
# A rectangle
|
||||
# Rectangles are implemented by a lower-left point and a vector
|
||||
# connecting the upper-right point with the lower left one.
|
||||
struct Box
|
||||
{
|
||||
# delta.x or .y is >= 0 for normal boxes
|
||||
# delta.x < 0 or delta.y indicates an empty box
|
||||
p1 @0 :Point;
|
||||
delta @1 :Vector;
|
||||
}
|
||||
|
||||
# An edge
|
||||
# An edge is a connection between two points.
|
||||
# Edges are implemented by on point and a vector connecting a
|
||||
# second point with the first one.
|
||||
struct Edge
|
||||
{
|
||||
p1 @0 :Point;
|
||||
delta @1 :Vector;
|
||||
}
|
||||
|
||||
# An edge pair
|
||||
# An edge pair is the combination of two edges. Edge pairs are
|
||||
# useful objects to describe DRC errors.
|
||||
struct EdgePair
|
||||
{
|
||||
e1 @0 :Edge;
|
||||
e2 @1 :Edge;
|
||||
}
|
||||
|
||||
# A contour
|
||||
# A contour is a sequence of points. Here, the contour is described
|
||||
# by a first point and vectors connecting every point to it's
|
||||
# successor.
|
||||
struct Contour
|
||||
{
|
||||
# p1 is the first point, deltas are the differences
|
||||
# to the next point. I.e.
|
||||
# points = { p1, p1+delta[0], p1+delta[0]+delta[1] ... }
|
||||
p1 @0 :Point;
|
||||
deltas @1 :List(Vector);
|
||||
}
|
||||
|
||||
# A simple polygon
|
||||
# A simple polygon is made from one contour. The contour forms
|
||||
# the hull of the polygon. First and last point are implicitly
|
||||
# connected.
|
||||
# The contour shall be orientated clockwise and should not
|
||||
# be self-intersecting. If can be self-touching to make polygons
|
||||
# with holes.
|
||||
# The hull must have three points at least.
|
||||
# No repeated points must be present and degenerated sequences
|
||||
# such as reflecting edges or collinear edge pairs should be avoided,
|
||||
# as they are not guaranteed to be preserved.
|
||||
struct SimplePolygon
|
||||
{
|
||||
hull @0 :Contour;
|
||||
}
|
||||
|
||||
# A polygon with holes
|
||||
# Like the simple polygon, but adds holes to the polygon.
|
||||
# The holes are described by contours as well as the hull.
|
||||
# Hole contours must not be overlapping and shall be
|
||||
# oriented counterclockwise.
|
||||
# The same restrictions apply for the holes as for the hull
|
||||
# contour.
|
||||
struct Polygon
|
||||
{
|
||||
hull @0 :Contour;
|
||||
holes @1 :List(Contour);
|
||||
}
|
||||
|
||||
# A path
|
||||
# A path is a list of points in form of a contour which
|
||||
# are connected by a wide line. The width of the line
|
||||
# is specified as the half-width to enforce on-gridness
|
||||
# of the boundary of the path. The point sequence is
|
||||
# called the path's "spine".
|
||||
# The line ends can be configured to be flat, square,
|
||||
# circular or round.
|
||||
# The spine needs to have at least one point.
|
||||
# Paths with single points are allowed. With square
|
||||
# ends, this represents a square, with round ends this
|
||||
# represents a circle.
|
||||
struct Path
|
||||
{
|
||||
# The spine
|
||||
spine @0 :Contour;
|
||||
|
||||
# The path's half width
|
||||
halfWidth @1 :UInt64;
|
||||
|
||||
# Extension at the start and end -
|
||||
# only valid with extensionType "variable":
|
||||
beginExtension @2 :Int64;
|
||||
endExtension @3 :Int64;
|
||||
|
||||
# The type of extension
|
||||
extensionType @4 :ExtensionType;
|
||||
|
||||
enum ExtensionType
|
||||
{
|
||||
flush @0; # flat
|
||||
square @1; # square
|
||||
round @2; # circular
|
||||
variable @3; # variable (given by "beginExtension" and "endExtension")
|
||||
}
|
||||
}
|
||||
|
||||
# A text
|
||||
# "texts" are not called "Text" as not to collide with Cap'n'Proto's
|
||||
# built-in "Text" type.
|
||||
# A text is a label at a specific position.
|
||||
struct Label
|
||||
{
|
||||
# The position of the label
|
||||
position @0 :Point;
|
||||
|
||||
# The orientation of the label
|
||||
orientation @1 :FixPointTransformation;
|
||||
|
||||
# base-0 index in the Header::TextStringsTable list
|
||||
stringId @2 :UInt64;
|
||||
|
||||
# Alignment
|
||||
horizontalAlign @3 :HAlignment;
|
||||
verticalAlign @4 :VAlignment;
|
||||
|
||||
# The offset by which the text is displayed relative to the
|
||||
# position (this feature is ignored as of now)
|
||||
displayOffset @5 :Vector;
|
||||
|
||||
# Text height in DBU
|
||||
size @6 :UInt64;
|
||||
|
||||
# Horizontal alignment flags
|
||||
enum HAlignment
|
||||
{
|
||||
left @0;
|
||||
center @1;
|
||||
right @2;
|
||||
}
|
||||
|
||||
# Vertical alignment flags
|
||||
enum VAlignment
|
||||
{
|
||||
bottom @0;
|
||||
center @1;
|
||||
top @2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
@0xc5f5e75ece54ff24;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::header");
|
||||
|
||||
using MetaData = import "metaData.capnp".MetaData;
|
||||
|
||||
# A library dictionary entry
|
||||
# These entries are used later to form the library list
|
||||
struct LibrarySpec
|
||||
{
|
||||
# The name of the library
|
||||
name @0 :Text;
|
||||
|
||||
# The type of library:
|
||||
# The type carries information about the usage of the library.
|
||||
# Types are:
|
||||
# "layout": traverses "layout" views
|
||||
# "schematic": traverses "schematic" views through "symbol"
|
||||
# more t.b.d
|
||||
type @1 :Text;
|
||||
}
|
||||
|
||||
# The global header
|
||||
struct Header
|
||||
{
|
||||
# File-global meta data
|
||||
metaData @0 :MetaData;
|
||||
|
||||
# The name of the tool that generated this file
|
||||
generator @1 :Text;
|
||||
|
||||
# The technology this stream is intended for
|
||||
# This is an arbitrary string as of now.
|
||||
technology @2 :Text;
|
||||
|
||||
# The list of libraries contained in this stream
|
||||
libraries @3 :List(LibrarySpec);
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
@0x973a841036ae34e0;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::layoutView");
|
||||
|
||||
using Box = import "geometry.capnp".Box;
|
||||
using Polygon = import "geometry.capnp".Polygon;
|
||||
using SimplePolygon = import "geometry.capnp".SimplePolygon;
|
||||
using Edge = import "geometry.capnp".Edge;
|
||||
using EdgePair = import "geometry.capnp".EdgePair;
|
||||
using Path = import "geometry.capnp".Path;
|
||||
using Point = import "geometry.capnp".Point;
|
||||
using Vector = import "geometry.capnp".Vector;
|
||||
using Label = import "geometry.capnp".Label;
|
||||
using FixPointTransformation = import "geometry.capnp".FixPointTransformation;
|
||||
using Repetition = import "repetition.capnp".Repetition;
|
||||
|
||||
struct SingleObject(Object)
|
||||
{
|
||||
basic @0 :Object;
|
||||
}
|
||||
|
||||
struct ObjectArray(Object)
|
||||
{
|
||||
basic @0 :Object;
|
||||
|
||||
# "repetitionId" is 0 for single instance, otherwise it's a base-1 index in the
|
||||
# "Layer::repetitions" list
|
||||
repetitionId @1 :UInt64;
|
||||
}
|
||||
|
||||
struct ObjectWithProperties(Object)
|
||||
{
|
||||
basic @0 :Object;
|
||||
|
||||
# "propertySetId" is 0 for "no properties", otherwise it's a base-1 index in the
|
||||
# "Header::propertiesTable::propertySets" list.
|
||||
propertySetId @1 :UInt64;
|
||||
}
|
||||
|
||||
struct ObjectContainerForType(Object)
|
||||
{
|
||||
basic @0 :List(SingleObject(Object)); # NOTE: can't be "List(Object)" simply
|
||||
withProperties @1 :List(ObjectWithProperties(Object));
|
||||
arrays @2 :List(ObjectArray(Object));
|
||||
arraysWithProperties @3 :List(ObjectWithProperties(ObjectArray(Object)));
|
||||
}
|
||||
|
||||
# A layer
|
||||
# A layer is a collection of objects - with repetitions and/or properties.
|
||||
# "objects" can be geometrical objects such as boxes and others.
|
||||
struct Layer
|
||||
{
|
||||
# The layer index - this is a base-0 index into Library::layerTable::layerEntries
|
||||
layerId @0 :UInt64;
|
||||
|
||||
# The repetitions
|
||||
# The "repetitionId" specified above is a base-1 index in that this.
|
||||
repetitions @1 :List(Repetition);
|
||||
|
||||
# Containers for the different objects the layer can be composed of.
|
||||
# Every container can hold objects with properties and/or repetitions.
|
||||
boxes @2 :ObjectContainerForType(Box);
|
||||
polygons @3 :ObjectContainerForType(Polygon);
|
||||
simplePolygons @4 :ObjectContainerForType(SimplePolygon);
|
||||
paths @5 :ObjectContainerForType(Path);
|
||||
labels @6 :ObjectContainerForType(Label);
|
||||
edges @7 :ObjectContainerForType(Edge);
|
||||
edgePairs @8 :ObjectContainerForType(EdgePair);
|
||||
points @9 :ObjectContainerForType(Point);
|
||||
}
|
||||
|
||||
# Specifies a transformation for a cell
|
||||
# Transformations can be "simple": such transformations
|
||||
# do not allow arbitrary angle rotations or scaling.
|
||||
# "complex" transformations on the other hand, support
|
||||
# arbitrary angle rotations and scaling but come with
|
||||
# potential issues with off-grid vertexes rendered
|
||||
# by their resulting geometries.
|
||||
#
|
||||
# The order of the transformations in the simple cases is:
|
||||
# 1. Apply simple.orientation
|
||||
# 2. Apply displacement (shift)
|
||||
#
|
||||
# In the complex case the order is:
|
||||
# 1. Multiplication by the "scale" factor
|
||||
# 2. Mirror at x axis if "mirror" is true
|
||||
# 3. Rotate by "angle" degrees counter-clockwise
|
||||
# 4. Apply displacement (shift)
|
||||
|
||||
struct CellTransformation
|
||||
{
|
||||
displacement @0 :Vector;
|
||||
|
||||
transformation :union {
|
||||
simple :group {
|
||||
orientation @1 : FixPointTransformation;
|
||||
}
|
||||
complex :group {
|
||||
angle @2 :Float64; # rotation angle in degree
|
||||
mirror @3 :Bool; # at x axis before rotation
|
||||
scale @4 :Float64; # before rotation, mirror and displacement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A cell placement
|
||||
struct CellInstance
|
||||
{
|
||||
# This is a base-0 index into Library::cellSpecsTable::cellSpecs
|
||||
cellId @0 :UInt64;
|
||||
|
||||
# The transformation describes how the cell is placed
|
||||
transformation @1 :CellTransformation;
|
||||
}
|
||||
|
||||
# The LayoutView class:
|
||||
# This message represents the entire layout view of a cell
|
||||
struct LayoutView
|
||||
{
|
||||
# The cell bounding box
|
||||
# This bounding box includes all geometries, including child cells
|
||||
# but maybe larger than the actual size due to shapes not written
|
||||
# to the stream.
|
||||
boundingBox @0 :Box;
|
||||
|
||||
# The layers present in the layout view
|
||||
layers @1 :List(Layer);
|
||||
|
||||
# The repetitions used for the cell instances
|
||||
instanceRepetitions @2 :List(Repetition);
|
||||
|
||||
# The cell instance container: lists cell instances with properties
|
||||
# and/or repetitions.
|
||||
# Regular array repetitions play a special role as they are preserved
|
||||
# in edit mode.
|
||||
instances @3 :ObjectContainerForType(CellInstance);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
@0x86931e1824fec888;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::library");
|
||||
|
||||
using MetaData = import "metaData.capnp".MetaData;
|
||||
using PropertySet = import "propertySet.capnp".PropertySet;
|
||||
using PropertyName = import "propertySet.capnp".PropertyName;
|
||||
using NamedValue = import "propertySet.capnp".NamedValue;
|
||||
using Box = import "geometry.capnp".Box;
|
||||
|
||||
using Variant = import "variant.capnp".Variant;
|
||||
|
||||
# A table listing the names of the properties used in this library
|
||||
struct PropertyNamesTable
|
||||
{
|
||||
# Namespaces are intended to separate property names which are otherwise
|
||||
# identical. Different applications or system can define their own namespace
|
||||
# which acts as a prefix to the property names.
|
||||
# The "namespaceId" used in PropertyName is a base-1 index in this table
|
||||
namespaces @0 :List(Text);
|
||||
|
||||
# Names with namespace Ids:
|
||||
# The "nameId" used in PropertySet is a base-0 index in this table
|
||||
names @1 :List(PropertyName);
|
||||
}
|
||||
|
||||
# A table of all property/name combinations used in this library:
|
||||
# Shapes or other objects specifying properties do not carry a dictionary,
|
||||
# but just state the "Id" of the property set, which is a pointer into
|
||||
# this table. This serves the compactness goal of the format as properties
|
||||
# are often repeated.
|
||||
struct PropertiesTable
|
||||
{
|
||||
# NOTE: the propertyId used in many places is 0 for "no property"
|
||||
# otherwise "propertyId" is the base-1 index of the property set in this list
|
||||
propertySets @0 :List(PropertySet);
|
||||
}
|
||||
|
||||
# A table of all text (label) strings used:
|
||||
# A label object does not directly specify the text, but stores a
|
||||
# base-0 index into this table. This also serves the compactness goal.
|
||||
struct TextStringsTable
|
||||
{
|
||||
textStrings @0 :List(Text);
|
||||
}
|
||||
|
||||
# A reference to a library:
|
||||
# This is merely a pointer to an external entity. It is up to the
|
||||
# application to resolve this reference.
|
||||
struct LibraryRef
|
||||
{
|
||||
libraryName @0 :Text;
|
||||
}
|
||||
|
||||
# A list of all library references
|
||||
struct LibraryRefs
|
||||
{
|
||||
refs @0 :List(LibraryRef);
|
||||
}
|
||||
|
||||
# A structure describing the parameters of a cell
|
||||
# Cell parameters are name/value pairs. It is up to the application
|
||||
# to provide a cell implementation and identify the parameters to use.
|
||||
struct CellParameters
|
||||
{
|
||||
values @0 :List(NamedValue);
|
||||
}
|
||||
|
||||
# A cell header:
|
||||
# This structure describes a cell inside a library. A cell is primarily
|
||||
# given by a name which must be unique inside the library. A cell can refer
|
||||
# to a separate library and/or a parameterized cell.
|
||||
# an any case, the cell's actual content is copied into the stream, so a
|
||||
# consumer of a stream can obtain the actual geometry of a cell, instead
|
||||
# of having to find the provider to build it.
|
||||
struct CellSpec
|
||||
{
|
||||
# The name of the cell in the current stream. This needs to be a unique name.
|
||||
# This attribute is mandatory. If the cell refers to a library cell, the cell
|
||||
# name inside the library can be different from the cell name.
|
||||
name @0 :Text;
|
||||
|
||||
# Specifies, whether the cell refers to a library.
|
||||
# "libraryNameId" is 0 for a local cell (no library reference), otherwise it's a base-1
|
||||
# index into "Header::libraryRefs".
|
||||
libraryRefId @1 :UInt64;
|
||||
|
||||
# The name of the cell inside the library, if one is specified
|
||||
libraryCellName @2 :Text;
|
||||
|
||||
# The cell parameters, if the cell is a parameterized cell.
|
||||
parameters @3 :CellParameters;
|
||||
|
||||
# "propertySetId" is 0 for "no properties", otherwise it's a base-1 index in the
|
||||
# "Header::propertiesTable::propertySets" list.
|
||||
propertySetId @4 :UInt64;
|
||||
}
|
||||
|
||||
# A table of all cells
|
||||
struct CellSpecsTable
|
||||
{
|
||||
cellSpecs @0 :List(CellSpec);
|
||||
}
|
||||
|
||||
# A node in the hierarchy tree:
|
||||
# The hierarchy tree lists all cells with their children.
|
||||
struct CellHierarchyTreeNode
|
||||
{
|
||||
# The cellId is a base-0 index in CellSpecsTable::cellSpecs
|
||||
cellId @0 :UInt64;
|
||||
|
||||
# Same for the child cell Ids
|
||||
childCellIds @1 :List(UInt64);
|
||||
}
|
||||
|
||||
# The full hierarchy tree
|
||||
struct CellHierarchyTree
|
||||
{
|
||||
# The number of top cells (cells without a parent)
|
||||
# As the "nodes" list is sorted top-down, the first
|
||||
# "numberOfTopCells" cells are actually top cells.
|
||||
numberOfTopCells @0 :UInt64;
|
||||
|
||||
# top-down sorted cells
|
||||
nodes @1 :List(CellHierarchyTreeNode);
|
||||
}
|
||||
|
||||
# A layer specification:
|
||||
# A layer can be specified by a several layer numbers
|
||||
# and/or a name. If no numbers are given, the name will
|
||||
# identify the layer. Otherwise the numbers will identify
|
||||
# the layer.
|
||||
# Layers can be unnamed and unnumbered and layer specifications
|
||||
# do not need to be unique.
|
||||
# The purpose is a hint and additionally identifies the
|
||||
# purpose of the shapes on the layer.
|
||||
struct LayerEntry
|
||||
{
|
||||
# layerNumbers = [] for no layer/datatype,
|
||||
# [layer] for single layer/no datatype
|
||||
# [layer, datatype] for GDS2 layer/datatype
|
||||
layerNumbers @0 :List(UInt64);
|
||||
name @1 :Text;
|
||||
purpose @2 :Purpose;
|
||||
|
||||
enum Purpose {
|
||||
drawing @0; # default
|
||||
fill @1;
|
||||
slot @2;
|
||||
pin @3;
|
||||
boundary @4;
|
||||
text @5;
|
||||
comment @6;
|
||||
blockage @7;
|
||||
wire @8;
|
||||
errors @9;
|
||||
handles @10;
|
||||
symbol @11;
|
||||
}
|
||||
}
|
||||
|
||||
# All layer entries
|
||||
struct LayerTable
|
||||
{
|
||||
# The layerId used inside the LayoutView struct is a
|
||||
# base-0 index into this table.
|
||||
layerEntries @0 :List(LayerEntry);
|
||||
}
|
||||
|
||||
# A specification for a view
|
||||
struct ViewSpec
|
||||
{
|
||||
# The view name: the view name carries information about
|
||||
# the usage - e.g. "layout", "metaData", "abstractLayout", "schematic", "symbol" ...
|
||||
name @0 :Text;
|
||||
|
||||
# The class representing the view
|
||||
# For layout views, this is "LayoutView".
|
||||
class @1 :Text;
|
||||
|
||||
# The resolution: this is the number of database
|
||||
# units per micrometer. This specification is favored
|
||||
# over database unit in micrometers as this is usually
|
||||
# an integer number.
|
||||
# As of now, only layout views need this resolution value as they represent
|
||||
# geometries in integer multiples of the resolution.
|
||||
# If not used, this value should be zero.
|
||||
resolution @2 :Float64;
|
||||
|
||||
# The layer table:
|
||||
# All layers used in this stream are listed here.
|
||||
# Layers can be present without being used (in a sense of having shapes in them).
|
||||
# On the contrary, layers must be listed here, before they can be used for shapes.
|
||||
layerTable @3 :LayerTable;
|
||||
|
||||
# View properties:
|
||||
# "propertySetId" is 0 for "no properties", otherwise it's a base-1 index in the
|
||||
# "Header::propertiesTable::propertySets" list.
|
||||
# For layout views, this corresponds to OASIS file properties for example.
|
||||
propertySetId @4 :UInt64;
|
||||
|
||||
# Meta data attached to the view type
|
||||
metaData @5 :MetaData;
|
||||
}
|
||||
|
||||
# A table of all views
|
||||
struct ViewSpecsTable
|
||||
{
|
||||
# The "viewIds" used in the "Cell" structure is a base-0 index into this
|
||||
# list.
|
||||
viewSpecs @0 :List(ViewSpec);
|
||||
}
|
||||
|
||||
# The header for a library
|
||||
struct Library
|
||||
{
|
||||
# Meta data:
|
||||
# Meta data is a generic container for arbitrary data attached to the stream.
|
||||
# In contrast to properties, meta data is available on cell and library level
|
||||
# only and is intended for application specific data.
|
||||
metaData @0 :MetaData;
|
||||
|
||||
# Library names:
|
||||
# The "libraryNameId" used in this scheme refers to this table
|
||||
# as a base-1 index into it. A "libraryNameId" of 0 means "no library referenced".
|
||||
libraryRefs @1 :LibraryRefs;
|
||||
|
||||
# Property names:
|
||||
# The "nameId" used in a number of places in the scheme refers
|
||||
# to this table as a base-0 index into it.
|
||||
propertyNamesTable @2 :PropertyNamesTable;
|
||||
|
||||
# Properties tables:
|
||||
# The "propertySetId" used in many places in this schema refers to
|
||||
# this table as a base-1 index into it. A property set Id of 0
|
||||
# indicates "no properties".
|
||||
propertiesTable @3 :PropertiesTable;
|
||||
|
||||
# Text strings:
|
||||
# This text string repository is mainly used by layout views for
|
||||
# compact representation of text strings.
|
||||
textStringsTable @4 :TextStringsTable;
|
||||
|
||||
# View specs table:
|
||||
# Defines the views with some additional attributes. Not all views
|
||||
# listed here need to be used by the cells. Every cell selects
|
||||
# views from this list. However, a cell cannot select a view that is
|
||||
# not in this list.
|
||||
viewSpecsTable @5 :ViewSpecsTable;
|
||||
|
||||
# The cell specifications:
|
||||
# The cell specifications describe the cell's origin and
|
||||
# attributes of the cell.
|
||||
cellSpecsTable @6 :CellSpecsTable;
|
||||
|
||||
# The cell hierarchy tree:
|
||||
# This tree is mandatory for pure layout streams. It provides
|
||||
# quick access to the structure, so stream processing can be planned
|
||||
# in some cases by just reading the header.
|
||||
cellHierarchyTree @7 :CellHierarchyTree;
|
||||
}
|
||||
|
||||
# Followed by many "Cell" messages
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
@0x91d51203f4528da2;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::metaData");
|
||||
|
||||
using Variant = import "variant.capnp".Variant;
|
||||
|
||||
# An entry for meta data
|
||||
struct MetaDataEntry
|
||||
{
|
||||
# The key
|
||||
name @0 :Text;
|
||||
|
||||
# Some optional description text
|
||||
description @1 :Text;
|
||||
|
||||
# The value
|
||||
value @2 :Variant;
|
||||
}
|
||||
|
||||
# The MetaData View class:
|
||||
# This message represents the meta data view of cell.
|
||||
# Meta data is a generic concept - basically a list of
|
||||
# key/value pairs for custom payload, with not specific
|
||||
# implied interpretation by the application.
|
||||
struct MetaData
|
||||
{
|
||||
entries @0 :List(MetaDataEntry);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
@0xf401d688f5f6eb25;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::metaDataView");
|
||||
|
||||
using MetaData = import "metaData.capnp".MetaData;
|
||||
|
||||
# A meta data view for a cell:
|
||||
# A cell can add arbirary key/value information through this view.
|
||||
struct MetaDataView
|
||||
{
|
||||
data @0 :MetaData;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
@0xa344c0f52014bff4;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::propertySet");
|
||||
|
||||
using Variant = import "variant.capnp".Variant;
|
||||
|
||||
# The name of a shape or instance property
|
||||
struct PropertyName
|
||||
{
|
||||
# A "namespaceID" of 0 means "no namespace". Otherwise it's a base-1 index in the
|
||||
# property namespace table in "header::propertyNamesTable::namespaces".
|
||||
# The namespace is intended as a kind of prefix, uniquely identifying the name
|
||||
# of the property, so that different owners can use the same name as long as the
|
||||
# own the namespace.
|
||||
namespaceId @0 :UInt64;
|
||||
|
||||
# The "name":
|
||||
# The property name does not need to be a string, but can be any type,
|
||||
# specifically integer values. This way, properties can map GDS user properties.
|
||||
name @1 :Variant;
|
||||
}
|
||||
|
||||
# A pair of name and value
|
||||
struct NamedValue
|
||||
{
|
||||
# The namdId is a base-0 index into Library::propertyNamesTable
|
||||
nameId @0 :UInt64;
|
||||
|
||||
# The value associated with the name
|
||||
value @1 :Variant;
|
||||
}
|
||||
|
||||
# A set of name/value pairs forming the set of properties for a shape or instance
|
||||
struct PropertySet
|
||||
{
|
||||
properties @0 :List(NamedValue);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
@0x9c4548253282e237;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::repetition");
|
||||
|
||||
using Vector = import "geometry.capnp".Vector;
|
||||
|
||||
# A regular array with x and y spacing
|
||||
# The displacements of an object are:
|
||||
# disp = (ix*dx, iy*dy)
|
||||
# where ix=0..nx-1 and iy=0..ny-1
|
||||
struct RegularOrthoRepetition
|
||||
{
|
||||
dx @0 :Int64;
|
||||
dy @1 :Int64;
|
||||
nx @2 :UInt64;
|
||||
ny @3 :UInt64;
|
||||
}
|
||||
|
||||
# A regular array with free step vectors which do not need to be orthogonal
|
||||
# The displacements of an object are:
|
||||
# disp = ia*a+ib*b
|
||||
# where ia=0..na-1 and ib=0..nb-1
|
||||
struct RegularRepetition
|
||||
{
|
||||
a @0 :Vector;
|
||||
b @1 :Vector;
|
||||
na @2 :UInt64;
|
||||
nb @3 :UInt64;
|
||||
}
|
||||
|
||||
# A free repetition given by a set of displacements
|
||||
struct EnumeratedRepetition
|
||||
{
|
||||
# The number of instances represented by this repetition type is one
|
||||
# more than the length of the list. The first entry is implicitly
|
||||
# assumed to be (0,0) and is dropped.
|
||||
# The list is given in incremental offsets.
|
||||
# So the offsets are:
|
||||
# offsets = { (0,0), delta[0], delta[0]+delta[1] ... }
|
||||
deltas @0 :List(Vector);
|
||||
}
|
||||
|
||||
# A generic repetition object
|
||||
# This union describes a set of object "placements".
|
||||
# Placements are basically shifts of some original
|
||||
# object by a given vector.
|
||||
struct Repetition
|
||||
{
|
||||
types :union {
|
||||
single @0 :Vector;
|
||||
regular @1 :RegularRepetition;
|
||||
regularOrtho @2 :RegularOrthoRepetition;
|
||||
enumerated @3 :EnumeratedRepetition;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
@0x92e3d852e5f6a442;
|
||||
|
||||
using Cxx = import "/capnp/c++.capnp";
|
||||
$Cxx.namespace("stream::variant");
|
||||
|
||||
# A helper struct to build a dictionary of key/value pairs
|
||||
struct ArrayEntry
|
||||
{
|
||||
key @0 :Variant;
|
||||
value @1 :Variant;
|
||||
}
|
||||
|
||||
# A generic type representing a number of C++ types
|
||||
struct Variant {
|
||||
value :union {
|
||||
nil @0 :Void;
|
||||
bool @1 :Bool;
|
||||
uint64 @2 :UInt64;
|
||||
int64 @3 :Int64;
|
||||
double @4 :Float64;
|
||||
text @5 :Text;
|
||||
list @6 :List(Variant);
|
||||
array @7 :List(ArrayEntry);
|
||||
object @8 :Text;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
TARGET = lstream
|
||||
DESTDIR = $$OUT_PWD/../../../../db_plugins
|
||||
|
||||
include($$PWD/../../../db_plugin.pri)
|
||||
include($$PWD/capnp/capnp.pri)
|
||||
|
||||
INCLUDEPATH += capnp $$VERSION_INC
|
||||
LIBS += -L$$DESTDIR/.. -lxkj -lxcapnp
|
||||
|
||||
HEADERS += \
|
||||
lstrCompressed.h \
|
||||
lstrCompressor.h \
|
||||
lstrFormat.h \
|
||||
lstrPlugin.h \
|
||||
lstrReader.h \
|
||||
lstrWriter.h \
|
||||
|
||||
SOURCES += \
|
||||
gsiDeclLStream.cc \
|
||||
lstrCompressed.cc \
|
||||
lstrCompressor.cc \
|
||||
lstrFormat.cc \
|
||||
lstrPlugin.cc \
|
||||
lstrReader.cc \
|
||||
lstrWriter.cc \
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
rm -rf capnp_src
|
||||
rm *.cc *.h
|
||||
|
||||
tmp=.tmp
|
||||
rm -rf $tmp
|
||||
mkdir $tmp
|
||||
cd $tmp
|
||||
|
||||
git clone ssh://git@codeberg.org/klayoutmatthias/lstream.git .
|
||||
|
||||
cp capnp/*.capnp ../capnp_src
|
||||
cp db_plugin/*{cc,h} ..
|
||||
cd ..
|
||||
|
||||
./capnp_compile.sh
|
||||
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrFormat.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "gsiDecl.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// gsi Implementation of specific methods of LoadLayoutOptions
|
||||
|
||||
static void set_lstream_bbox_meta_info_key (db::LoadLayoutOptions *options, const std::string &key)
|
||||
{
|
||||
options->get_options<lstr::ReaderOptions> ().bbox_meta_info_key = key;
|
||||
}
|
||||
|
||||
static const std::string &get_lstream_bbox_meta_info_key (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<lstr::ReaderOptions> ().bbox_meta_info_key;
|
||||
}
|
||||
|
||||
// extend lay::LoadLayoutOptions with the OASIS options
|
||||
static
|
||||
gsi::ClassExt<db::LoadLayoutOptions> lstream_reader_options (
|
||||
gsi::method_ext ("lstream_bbox_meta_info_key=", &set_lstream_bbox_meta_info_key, gsi::arg ("key"),
|
||||
"@brief If not an empty string, this attribute specifies the key under which the cell bounding box information is stored"
|
||||
) +
|
||||
gsi::method_ext ("lstream_bbox_meta_info_key", &get_lstream_bbox_meta_info_key,
|
||||
"@brief If not an empty string, this attribute specifies the key under which the cell bounding box information is stored"
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// gsi Implementation of specific methods
|
||||
|
||||
static void set_lstream_compression (db::SaveLayoutOptions *options, int comp)
|
||||
{
|
||||
options->get_options<lstr::WriterOptions> ().compression_level = comp;
|
||||
}
|
||||
|
||||
static int get_lstream_compression (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<lstr::WriterOptions> ().compression_level;
|
||||
}
|
||||
|
||||
static void set_lstream_recompress (db::SaveLayoutOptions *options, bool f)
|
||||
{
|
||||
options->get_options<lstr::WriterOptions> ().recompress = f;
|
||||
}
|
||||
|
||||
static bool get_lstream_recompress (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<lstr::WriterOptions> ().recompress;
|
||||
}
|
||||
|
||||
static void set_lstream_permissive (db::SaveLayoutOptions *options, bool f)
|
||||
{
|
||||
options->get_options<lstr::WriterOptions> ().permissive = f;
|
||||
}
|
||||
|
||||
static bool get_lstream_permissive (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<lstr::WriterOptions> ().permissive;
|
||||
}
|
||||
|
||||
// extend lay::SaveLayoutOptions with the OASIS options
|
||||
static
|
||||
gsi::ClassExt<db::SaveLayoutOptions> lstream_writer_options (
|
||||
gsi::method_ext ("lstream_recompress=", &set_lstream_recompress, gsi::arg ("flag"),
|
||||
"@brief Sets LStream recompression mode\n"
|
||||
"If this flag is true, shape arrays already existing will be resolved and compression is applied "
|
||||
"to the individual shapes again. If this flag is false (the default), shape arrays already existing "
|
||||
"will be written as such.\n"
|
||||
) +
|
||||
gsi::method_ext ("lstream_recompress?", &get_lstream_recompress,
|
||||
"@brief Gets the LStream recompression mode\n"
|
||||
"See \\oasis_recompress= method for a description of this predicate."
|
||||
) +
|
||||
gsi::method_ext ("lstream_permissive=", &set_lstream_permissive, gsi::arg ("flag"),
|
||||
"@brief Sets LStream permissive mode\n"
|
||||
"If this flag is true, certain shapes which cannot be written to LStream are reported as warnings, "
|
||||
"not as errors. For example, paths with odd width (are rounded).\n"
|
||||
) +
|
||||
gsi::method_ext ("lstream_permissive?", &get_lstream_permissive,
|
||||
"@brief Gets the LStream permissive mode\n"
|
||||
"See \\oasis_permissive= method for a description of this predicate."
|
||||
) +
|
||||
gsi::method_ext ("lstream_compression_level=", &set_lstream_compression, gsi::arg ("level"),
|
||||
"@brief Set the LStream compression level\n"
|
||||
"The LStream compression level is an integer number between 0 and 10. 0 basically is no compression, "
|
||||
"1 produces shape arrays in a simple fashion. 2 and higher compression levels will use a more elaborate "
|
||||
"algorithm to find shape arrays which uses 2nd and further neighbor distances. The higher the level, the "
|
||||
"higher the memory requirements and run times.\n"
|
||||
) +
|
||||
gsi::method_ext ("lstream_compression_level", &get_lstream_compression,
|
||||
"@brief Get the LStream compression level\n"
|
||||
"See \\oasis_compression_level= method for a description of the LStream compression level."
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,520 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrCompressed.h"
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbHash.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
Compressed::Compressed ()
|
||||
: m_next_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Compressed::make_rep_id (const RegularArray &array, const std::vector<db::Vector> &irregular)
|
||||
{
|
||||
if (! array.is_null ()) {
|
||||
|
||||
auto ia = m_array_to_rep_id.find (array);
|
||||
if (ia != m_array_to_rep_id.end ()) {
|
||||
return ia->second;
|
||||
} else {
|
||||
++m_next_id;
|
||||
m_array_to_rep_id.insert (std::make_pair (array, m_next_id));
|
||||
return m_next_id;
|
||||
}
|
||||
|
||||
} else if (! irregular.empty ()) {
|
||||
|
||||
auto ii = m_irregular_to_rep_id.find (irregular);
|
||||
if (ii != m_irregular_to_rep_id.end ()) {
|
||||
return ii->second;
|
||||
} else {
|
||||
++m_next_id;
|
||||
m_irregular_to_rep_id.insert (std::make_pair (irregular, m_next_id));
|
||||
return m_next_id;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Obj>
|
||||
void
|
||||
Compressed::write_shape (const db::Shape &shape, const db::Vector &disp, RegularArray ®ular, std::vector<db::Vector> &irregular_array)
|
||||
{
|
||||
Obj sh;
|
||||
shape.instantiate (sh);
|
||||
if (! object_is_empty (sh)) {
|
||||
sh.move (disp);
|
||||
if (shape.prop_id () != 0) {
|
||||
write (db::object_with_properties<Obj> (sh, shape.prop_id ()), regular, irregular_array);
|
||||
} else {
|
||||
write (sh, regular, irregular_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Compressed::compress_shapes (const db::Shapes &shapes, unsigned int level, bool recompress)
|
||||
{
|
||||
RegularArray no_array;
|
||||
std::vector<db::Vector> no_irregular_array;
|
||||
|
||||
Compressor<db::Path> path_compressor (level);
|
||||
Compressor<db::SimplePolygon> simple_polygon_compressor (level);
|
||||
Compressor<db::Polygon> polygon_compressor (level);
|
||||
Compressor<db::Edge> edge_compressor (level);
|
||||
Compressor<db::EdgePair> edge_pair_compressor (level);
|
||||
Compressor<db::Box> box_compressor (level);
|
||||
Compressor<db::Text> text_compressor (level);
|
||||
Compressor<db::Point> point_compressor (level);
|
||||
|
||||
Compressor<db::PathWithProperties> path_with_properties_compressor (level);
|
||||
Compressor<db::SimplePolygonWithProperties> simple_polygon_with_properties_compressor (level);
|
||||
Compressor<db::PolygonWithProperties> polygon_with_properties_compressor (level);
|
||||
Compressor<db::EdgeWithProperties> edge_with_properties_compressor (level);
|
||||
Compressor<db::EdgePairWithProperties> edge_pair_with_properties_compressor (level);
|
||||
Compressor<db::BoxWithProperties> box_with_properties_compressor (level);
|
||||
Compressor<db::TextWithProperties> text_with_properties_compressor (level);
|
||||
Compressor<db::PointWithProperties> point_with_properties_compressor (level);
|
||||
|
||||
for (db::ShapeIterator shape = shapes.begin (db::ShapeIterator::All); ! shape.at_end (); ) {
|
||||
|
||||
if (level <= 0 || (! recompress && shape.in_array ())) {
|
||||
|
||||
RegularArray array;
|
||||
std::vector<db::Vector> irregular_array;
|
||||
|
||||
bool transfer_array = (shape.in_array () && level > 0);
|
||||
db::Vector disp;
|
||||
if (transfer_array) {
|
||||
disp = create_repetition (shape.array (), array, irregular_array);
|
||||
}
|
||||
|
||||
if (shape->is_simple_polygon ()) {
|
||||
write_shape<db::SimplePolygon> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_polygon ()) {
|
||||
write_shape<db::Polygon> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_path ()) {
|
||||
write_shape<db::Path> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_text ()) {
|
||||
write_shape<db::Text> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_edge ()) {
|
||||
write_shape<db::Edge> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_edge_pair ()) {
|
||||
write_shape<db::EdgePair> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_box ()) {
|
||||
write_shape<db::Box> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_point ()) {
|
||||
write_shape<db::Point> (*shape, disp, array, irregular_array);
|
||||
} else if (shape->is_user_object ()) {
|
||||
// ignore
|
||||
} else {
|
||||
tl_assert (false); // unknown shape type
|
||||
}
|
||||
|
||||
if (transfer_array) {
|
||||
shape.finish_array ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
switch (shape->type ()) {
|
||||
case db::Shape::Polygon:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto polygon = *shape->basic_ptr (db::PolygonWithProperties::tag ());
|
||||
polygon_with_properties_compressor.add (polygon);
|
||||
} else {
|
||||
auto polygon = *shape->basic_ptr (db::Polygon::tag ());
|
||||
polygon_compressor.add (polygon);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::PolygonRef:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto polygon_ref = *shape->basic_ptr (db::object_with_properties<db::PolygonRef>::tag ());
|
||||
db::PolygonWithProperties polygon (polygon_ref.obj (), polygon_ref.properties_id ());
|
||||
polygon_with_properties_compressor.add (polygon, polygon_ref.trans ().disp ());
|
||||
} else {
|
||||
auto polygon_ref = *shape->basic_ptr (db::PolygonRef::tag ());
|
||||
polygon_compressor.add (polygon_ref.obj (), polygon_ref.trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::PolygonPtrArrayMember:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto polygon_ref = *shape->basic_ptr (db::object_with_properties<db::Shape::polygon_ptr_array_type>::tag ());
|
||||
db::PolygonWithProperties polygon (polygon_ref.object ().obj (), polygon_ref.properties_id ());
|
||||
polygon_with_properties_compressor.add (polygon, shape->array_trans ().disp ());
|
||||
} else {
|
||||
auto polygon_ref = *shape->basic_ptr (db::Shape::polygon_ptr_array_type::tag ());
|
||||
polygon_compressor.add (polygon_ref.object ().obj (), shape->array_trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::SimplePolygon:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto simple_polygon = *shape->basic_ptr (db::SimplePolygonWithProperties::tag ());
|
||||
simple_polygon_with_properties_compressor.add (simple_polygon);
|
||||
} else {
|
||||
auto simple_polygon = *shape->basic_ptr (db::SimplePolygon::tag ());
|
||||
simple_polygon_compressor.add (simple_polygon);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::SimplePolygonRef:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto polygon_ref = *shape->basic_ptr (db::object_with_properties<db::SimplePolygonRef>::tag ());
|
||||
db::SimplePolygonWithProperties polygon (polygon_ref.obj (), polygon_ref.properties_id ());
|
||||
simple_polygon_with_properties_compressor.add (polygon, polygon_ref.trans ().disp ());
|
||||
} else {
|
||||
auto polygon_ref = *shape->basic_ptr (db::SimplePolygonRef::tag ());
|
||||
simple_polygon_compressor.add (polygon_ref.obj (), polygon_ref.trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::SimplePolygonPtrArrayMember:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto simple_polygon_ref = *shape->basic_ptr (db::object_with_properties<db::Shape::simple_polygon_ptr_array_type>::tag ());
|
||||
db::SimplePolygonWithProperties simple_polygon (simple_polygon_ref.object ().obj (), simple_polygon_ref.properties_id ());
|
||||
simple_polygon_with_properties_compressor.add (simple_polygon, shape->array_trans ().disp ());
|
||||
} else {
|
||||
auto simple_polygon_ref = *shape->basic_ptr (db::Shape::simple_polygon_ptr_array_type::tag ());
|
||||
simple_polygon_compressor.add (simple_polygon_ref.object ().obj (), shape->array_trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::Edge:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto edge = *shape->basic_ptr (db::EdgeWithProperties::tag ());
|
||||
edge_with_properties_compressor.add (edge);
|
||||
} else {
|
||||
auto edge = *shape->basic_ptr (db::Edge::tag ());
|
||||
edge_compressor.add (edge);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::EdgePair:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto edge_pair = *shape->basic_ptr (db::EdgePairWithProperties::tag ());
|
||||
edge_pair_with_properties_compressor.add (edge_pair);
|
||||
} else {
|
||||
auto edge_pair = *shape->basic_ptr (db::EdgePair::tag ());
|
||||
edge_pair_compressor.add (edge_pair);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::Path:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto path = *shape->basic_ptr (db::PathWithProperties::tag ());
|
||||
path_with_properties_compressor.add (path);
|
||||
} else {
|
||||
auto path = *shape->basic_ptr (db::Path::tag ());
|
||||
path_compressor.add (path);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::PathRef:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto path_ref = *shape->basic_ptr (db::object_with_properties<db::PathRef>::tag ());
|
||||
db::PathWithProperties path (path_ref.obj (), path_ref.properties_id ());
|
||||
path_with_properties_compressor.add (path, path_ref.trans ().disp ());
|
||||
} else {
|
||||
const db::PathRef &path_ref = *shape->basic_ptr (db::PathRef::tag ());
|
||||
path_compressor.add (path_ref.obj (), path_ref.trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::PathPtrArrayMember:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto path_ref = *shape->basic_ptr (db::object_with_properties<db::Shape::path_ptr_array_type>::tag ());
|
||||
db::PathWithProperties path (path_ref.object ().obj (), path_ref.properties_id ());
|
||||
path_with_properties_compressor.add (path, shape->array_trans ().disp ());
|
||||
} else {
|
||||
const db::Shape::path_ptr_array_type &path_ref = *shape->basic_ptr (db::Shape::path_ptr_array_type::tag ());
|
||||
path_compressor.add (path_ref.object ().obj (), shape->array_trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::Box:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto box = *shape->basic_ptr (db::BoxWithProperties::tag ());
|
||||
box_with_properties_compressor.add (box);
|
||||
} else {
|
||||
auto box = *shape->basic_ptr (db::Box::tag ());
|
||||
box_compressor.add (box);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::Point:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto point = *shape->basic_ptr (db::PointWithProperties::tag ());
|
||||
point_with_properties_compressor.add (point);
|
||||
} else {
|
||||
auto point = *shape->basic_ptr (db::Point::tag ());
|
||||
point_compressor.add (point);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::BoxArray:
|
||||
case db::Shape::BoxArrayMember:
|
||||
case db::Shape::ShortBox:
|
||||
case db::Shape::ShortBoxArrayMember:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
db::BoxWithProperties box;
|
||||
shape->instantiate (box);
|
||||
box.properties_id (shape->prop_id ());
|
||||
box_with_properties_compressor.add (box);
|
||||
} else {
|
||||
db::Box box;
|
||||
shape->instantiate (box);
|
||||
box_compressor.add (box);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::Text:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto text = *shape->basic_ptr (db::TextWithProperties::tag ());
|
||||
text_with_properties_compressor.add (text);
|
||||
} else {
|
||||
auto text = *shape->basic_ptr (db::Text::tag ());
|
||||
text_compressor.add (text);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::TextRef:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto text_ref = *shape->basic_ptr (db::object_with_properties<db::TextRef>::tag ());
|
||||
db::TextWithProperties text (text_ref.obj (), text_ref.properties_id ());
|
||||
text_with_properties_compressor.add (text, text_ref.trans ().disp ());
|
||||
} else {
|
||||
auto text_ref = *shape->basic_ptr (db::TextRef::tag ());
|
||||
text_compressor.add (text_ref.obj (), text_ref.trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::TextPtrArrayMember:
|
||||
|
||||
if (shape->has_prop_id ()) {
|
||||
auto text_ref = *shape->basic_ptr (db::object_with_properties<db::Shape::text_ptr_array_type>::tag ());
|
||||
db::TextWithProperties text (text_ref.object ().obj (), text_ref.properties_id ());
|
||||
text_with_properties_compressor.add (text, shape->array_trans ().disp ());
|
||||
} else {
|
||||
auto text_ref = *shape->basic_ptr (db::Shape::text_ptr_array_type::tag ());
|
||||
text_compressor.add (text_ref.object ().obj (), shape->array_trans ().disp ());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case db::Shape::UserObject:
|
||||
// ignore.
|
||||
break;
|
||||
|
||||
default:
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
path_compressor.flush (this);
|
||||
simple_polygon_compressor.flush (this);
|
||||
polygon_compressor.flush (this);
|
||||
edge_compressor.flush (this);
|
||||
edge_pair_compressor.flush (this);
|
||||
box_compressor.flush (this);
|
||||
point_compressor.flush (this);
|
||||
text_compressor.flush (this);
|
||||
|
||||
path_with_properties_compressor.flush (this);
|
||||
simple_polygon_with_properties_compressor.flush (this);
|
||||
polygon_with_properties_compressor.flush (this);
|
||||
edge_with_properties_compressor.flush (this);
|
||||
edge_pair_with_properties_compressor.flush (this);
|
||||
box_with_properties_compressor.flush (this);
|
||||
point_with_properties_compressor.flush (this);
|
||||
text_with_properties_compressor.flush (this);
|
||||
}
|
||||
|
||||
template <class Array>
|
||||
static db::Vector
|
||||
create_repetition_from_array (const Array *array, RegularArray ®ular, std::vector<db::Vector> &irregular_array)
|
||||
{
|
||||
db::Vector a, b;
|
||||
unsigned long na = 0, nb = 0;
|
||||
|
||||
if (array->is_iterated_array (&irregular_array)) {
|
||||
|
||||
// Take out the first displacement and move that to the shape and sort the displacements.
|
||||
// This way, sequences get normalized and there is a better chance of getting identical
|
||||
// repetition vectors.
|
||||
tl_assert (! irregular_array.empty ());
|
||||
db::Vector po = irregular_array.front ();
|
||||
std::vector<db::Vector>::iterator pw = irregular_array.begin();
|
||||
for (std::vector<db::Vector>::iterator p = pw + 1; p != irregular_array.end (); ++p) {
|
||||
*pw++ = *p - po;
|
||||
}
|
||||
irregular_array.erase (pw, irregular_array.end ());
|
||||
std::sort (irregular_array.begin (), irregular_array.end (), vector_cmp_x ());
|
||||
|
||||
return po;
|
||||
|
||||
} else if (array->is_regular_array (a, b, na, nb)) {
|
||||
|
||||
regular = RegularArray (a, b, size_t (na), size_t (nb));
|
||||
return db::Vector ();
|
||||
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
db::Vector
|
||||
Compressed::create_repetition (const db::Shape &array_shape, RegularArray ®ular, std::vector<db::Vector> &irregular_array)
|
||||
{
|
||||
switch (array_shape.type ()) {
|
||||
case db::Shape::PolygonPtrArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::polygon_ptr_array_type::tag ()), regular, irregular_array);
|
||||
case db::Shape::SimplePolygonPtrArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::simple_polygon_ptr_array_type::tag ()), regular, irregular_array);
|
||||
case db::Shape::PathPtrArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::path_ptr_array_type::tag ()), regular, irregular_array);
|
||||
case db::Shape::BoxArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::box_array_type::tag ()), regular, irregular_array);
|
||||
case db::Shape::ShortBoxArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::short_box_array_type::tag ()), regular, irregular_array);
|
||||
case db::Shape::TextPtrArray:
|
||||
return create_repetition_from_array (array_shape.basic_ptr (db::Shape::text_ptr_array_type::tag ()), regular, irregular_array);
|
||||
default:
|
||||
tl_assert (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Compressed::compress_instances (const db::Cell::const_iterator &begin_instances, const std::set<db::cell_index_type> &cells_to_write, unsigned int level)
|
||||
{
|
||||
// use compression 0 for the instances - this preserves the arrays and does not create new ones, the
|
||||
// remaining ones are compressed into irregular arrays
|
||||
Compressor<db::CellInstArray> inst_compressor (0);
|
||||
Compressor<db::CellInstArrayWithProperties> inst_with_properties_compressor (0);
|
||||
|
||||
// Collect all instances
|
||||
for (auto inst_iterator = begin_instances; ! inst_iterator.at_end (); ++inst_iterator) {
|
||||
|
||||
if (cells_to_write.find (inst_iterator->cell_index ()) != cells_to_write.end ()) {
|
||||
|
||||
db::properties_id_type prop_id = inst_iterator->prop_id ();
|
||||
db::CellInstArray inst_array = inst_iterator->cell_inst ();
|
||||
|
||||
if (level == 0 || inst_array.size () > 1) {
|
||||
|
||||
// Recode the instance array into a regular array or irregular array spec (the latter hardly used) and
|
||||
// a single instance.
|
||||
RegularArray array;
|
||||
std::vector<db::Vector> irregular_array;
|
||||
|
||||
db::Vector disp;
|
||||
bool transfer_array = (inst_array.size () > 1 && level > 0);
|
||||
if (transfer_array) {
|
||||
disp = create_repetition_from_array (&inst_array, array, irregular_array);
|
||||
}
|
||||
|
||||
db::CellInstArray single_inst (inst_array.object (), db::Trans (-disp) * inst_array.front ());
|
||||
|
||||
// no compression -> just keep as is
|
||||
if (prop_id != 0) {
|
||||
write (db::CellInstArrayWithProperties (single_inst, prop_id), array, irregular_array);
|
||||
} else {
|
||||
write (single_inst, array, irregular_array);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// We have a single instance: reduce by displacement and compress into enumerated (irregular) arrays.
|
||||
// As we configured the compressor with level 0, no regular array formation will happen here. This is
|
||||
// good for instances as array instances are special.
|
||||
db::Vector disp = inst_array.front ().disp ();
|
||||
db::CellInstArray single_inst (inst_array.object (), db::Trans (-disp) * inst_array.front ());
|
||||
|
||||
if (prop_id != 0) {
|
||||
inst_with_properties_compressor.add (db::CellInstArrayWithProperties (single_inst, prop_id), disp);
|
||||
} else {
|
||||
inst_compressor.add (single_inst, disp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inst_compressor.flush (this);
|
||||
inst_with_properties_compressor.flush (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrCompressed
|
||||
#define HDR_lstrCompressed
|
||||
|
||||
#include "lstrCompressor.h"
|
||||
|
||||
#include "dbVector.h"
|
||||
#include "dbBox.h"
|
||||
#include "dbPath.h"
|
||||
#include "dbEdge.h"
|
||||
#include "dbEdgePair.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbText.h"
|
||||
#include "dbObjectWithProperties.h"
|
||||
#include "dbCell.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A container for storing objects and compressing them using regular or irregular repetitions
|
||||
*
|
||||
* Use this object to compress db::Shapes or db::Instances containers.
|
||||
* Use "Compressed::compress_shapes" to compress a Shapes container and
|
||||
* "Compressed::compress_instances" to compress an Instances container.
|
||||
*
|
||||
* After feeding the objects to be compressed using one of these methods,
|
||||
* you can access the compressed objects using "Compressed::get_container".
|
||||
* These containers are separated by objects and carray plain objects
|
||||
* (no compression), plain objects with properties (no compression either),
|
||||
* array objects (object that have been compressed into regular or irregular
|
||||
* arrays) and array objects with properties (the same, but also with
|
||||
* properties).
|
||||
*
|
||||
* During compression, arrays are formed. The array definitions are kept
|
||||
* in two lists: regular arrays and irregular (iterated or enumerated)
|
||||
* arrays. The former can be obtained using "Compressed::begin/end_regular_arrays",
|
||||
* the latter using "Compressed::begin/end_irregular_arrays".
|
||||
* The total number of array objects can be obtained using
|
||||
* "Compressed::num_arrays".
|
||||
*/
|
||||
class Compressed
|
||||
: public CompressorDelivery
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Represents compressed objects
|
||||
*
|
||||
* "plain" is a list of plain objects - those which have not been
|
||||
* compressed.
|
||||
*
|
||||
* "with_properties" is a list of pairs of objects and properties
|
||||
* Id. The properties Id is a concept from the db namespace and
|
||||
* represents a property set by some opaque identifier.
|
||||
*
|
||||
* "array" is a list of pairs of objects and repetition specifications.
|
||||
* The repetition is specified through an index (a uint64_t value).
|
||||
* The index is given by the second value when you iterate the repetitions
|
||||
* in "Compressed::begin_regular_arrays" or "Compressed::begin_irregular_arrays".
|
||||
*
|
||||
* "array_with_properties" is a list of pairs or pairs: "first.first"
|
||||
* is the object, "first.second" the properties Id and "second" the
|
||||
* repetition index (see "array").
|
||||
*/
|
||||
template <class Obj>
|
||||
struct compressed_container
|
||||
{
|
||||
std::list<Obj> plain;
|
||||
std::list<std::pair<Obj, db::properties_id_type> > with_properties;
|
||||
std::list<std::pair<Obj, uint64_t> > array;
|
||||
std::list<std::pair<std::pair<Obj, db::properties_id_type>, uint64_t> > array_with_properties;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* Note that you need to create a fresh object to compress
|
||||
* instances are shapes. There is no "clear" or "restart" method.
|
||||
*/
|
||||
Compressed ();
|
||||
|
||||
/**
|
||||
* @brief Compresses a shape container
|
||||
*
|
||||
* This method should be called on a fresh Compressed object only.
|
||||
*
|
||||
* @param shapes The shapes container to compress
|
||||
* @param level Compression level (see below)
|
||||
* @param recompress Indicates where to recompress (see below)
|
||||
*
|
||||
* "level" is a value the indicates the compression effort made for forming
|
||||
* regular arrays. A value of "0" indicates that no arrays will be formed.
|
||||
* "2" indicates "reasonable effort" to form arrays. Roughly, the value indicates
|
||||
* how many neighbors to investigate for forming arrays.
|
||||
*
|
||||
* If "recompress" is true, existing arrays will be exploded and fed into
|
||||
* the compression algorithm again. If false, they will be maintained.
|
||||
*/
|
||||
void compress_shapes (const db::Shapes &shapes, unsigned int level, bool recompress);
|
||||
|
||||
/**
|
||||
* @brief Compresses instances
|
||||
*
|
||||
* This method should be called on a fresh Compressed object only.
|
||||
*
|
||||
* @param begin_instances The instance iterator specifying the instances to compress
|
||||
* @param cells_to_write A filter specifying the cells to write
|
||||
* @param level Compression level (see "compress_shapes")
|
||||
*
|
||||
* "Cell::begin" can be used to generate the value for "instance_iterator".
|
||||
*
|
||||
* Instances for cells not in "cells_to_write" are not generated.
|
||||
*/
|
||||
void compress_instances (const db::Cell::const_iterator &begin_instances, const std::set<db::cell_index_type> &cells_to_write, unsigned int level);
|
||||
|
||||
/**
|
||||
* @brief Gets the compressed objects for a given object type
|
||||
*
|
||||
* Object types can be "db::Box", "db::Edge", "db::EdgePair",
|
||||
* "db::Polygon", "db::SimplePolygon", "db::Path" or "db::Text"
|
||||
* for Shapes and "db::CellInstArray" for instances.
|
||||
*
|
||||
* For "db::CellInstArray", the objects will be single instances
|
||||
* and the array nature is reflected by the repetition type.
|
||||
*
|
||||
* Note that either "compress_shapes" or "compress_instances" has
|
||||
* to be called before the container is available.
|
||||
*/
|
||||
template <class Obj> compressed_container<Obj> &get_container ();
|
||||
|
||||
/**
|
||||
* @brief begin iterator for the regular arrays
|
||||
*
|
||||
* The iterator delivers a pair of regular array specifications and
|
||||
* an index. The array specification is a RegularArray object that
|
||||
* specifies the array axes, pitches and array dimensions.
|
||||
*
|
||||
* The second value is the repetition index, by which the compressed
|
||||
* objects refer to that array.
|
||||
*
|
||||
* Note that either "compress_shapes" or "compress_instances" has
|
||||
* to be called before the arrays are available.
|
||||
*/
|
||||
std::map<RegularArray, uint64_t>::const_iterator begin_regular_arrays () const { return m_array_to_rep_id.begin (); }
|
||||
|
||||
/**
|
||||
* @brief end iterator for the regular arrays
|
||||
*/
|
||||
std::map<RegularArray, uint64_t>::const_iterator end_regular_arrays () const { return m_array_to_rep_id.end (); }
|
||||
|
||||
/**
|
||||
* @brief begin iterator for the irregular arrays
|
||||
*
|
||||
* The iterator delivers a pair of irregular array specifications and
|
||||
* an index. The array specification is a list of displacements that
|
||||
* specify the placements of the object.
|
||||
*
|
||||
* The second value is the repetition index, by which the compressed
|
||||
* objects refer to that array.
|
||||
*
|
||||
* Note that either "compress_shapes" or "compress_instances" has
|
||||
* to be called before the arrays are available.
|
||||
*/
|
||||
std::map<std::vector<db::Vector>, uint64_t>::const_iterator begin_irregular_arrays () const { return m_irregular_to_rep_id.begin (); }
|
||||
|
||||
/**
|
||||
* @brief end iterator for the irregular arrays
|
||||
*/
|
||||
std::map<std::vector<db::Vector>, uint64_t>::const_iterator end_irregular_arrays () const { return m_irregular_to_rep_id.end (); }
|
||||
|
||||
/**
|
||||
* @brief Gets the total number of arrays stored in this object
|
||||
*
|
||||
* Note that either "compress_shapes" or "compress_instances" has
|
||||
* to be called before the arrays are available.
|
||||
*/
|
||||
size_t num_arrays () const
|
||||
{
|
||||
return m_array_to_rep_id.size () + m_irregular_to_rep_id.size ();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void write (const db::Point &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::PointWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::Box &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::BoxWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::Edge &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::EdgeWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::EdgePair &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::EdgePairWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::Polygon &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::PolygonWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::SimplePolygon &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::SimplePolygonWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::Path &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::PathWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::Text &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::TextWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::CellInstArray &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
virtual void write (const db::CellInstArrayWithProperties &obj, const RegularArray &array, const disp_vector &irregular) { store (obj, array, irregular); }
|
||||
|
||||
private:
|
||||
compressed_container<db::Point> m_points;
|
||||
compressed_container<db::Box> m_boxes;
|
||||
compressed_container<db::Edge> m_edges;
|
||||
compressed_container<db::EdgePair> m_edge_pairs;
|
||||
compressed_container<db::Path> m_paths;
|
||||
compressed_container<db::Polygon> m_polygons;
|
||||
compressed_container<db::SimplePolygon> m_simple_polygons;
|
||||
compressed_container<db::Text> m_texts;
|
||||
compressed_container<db::CellInstArray> m_instances;
|
||||
|
||||
template <class Obj>
|
||||
void store_no_props (const Obj &obj, const RegularArray &array, const std::vector<db::Vector> &irregular)
|
||||
{
|
||||
compressed_container<Obj> &cont = get_container<Obj> ();
|
||||
if (array.is_null () && irregular.empty ()) {
|
||||
cont.plain.push_back (obj);
|
||||
} else {
|
||||
cont.array.push_back (std::make_pair (obj, make_rep_id (array, irregular)));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Obj>
|
||||
void store (const Obj &obj, const RegularArray &array, const std::vector<db::Vector> &irregular)
|
||||
{
|
||||
store_no_props (obj, array, irregular);
|
||||
}
|
||||
|
||||
template <class Obj>
|
||||
void store (const db::object_with_properties<Obj> &obj, const RegularArray &array, const std::vector<db::Vector> &irregular)
|
||||
{
|
||||
compressed_container<Obj> &cont = get_container<Obj> ();
|
||||
if (obj.properties_id () == 0) {
|
||||
store_no_props<Obj> (obj, array, irregular);
|
||||
} else {
|
||||
if (array.is_null () && irregular.empty ()) {
|
||||
cont.with_properties.push_back (std::pair<Obj, db::properties_id_type> (obj, obj.properties_id ()));
|
||||
} else {
|
||||
cont.array_with_properties.push_back (std::make_pair (std::pair<Obj, db::properties_id_type> (obj, obj.properties_id ()), make_rep_id (array, irregular)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t m_next_id;
|
||||
std::map<RegularArray, uint64_t> m_array_to_rep_id;
|
||||
std::map<std::vector<db::Vector>, uint64_t> m_irregular_to_rep_id;
|
||||
|
||||
uint64_t make_rep_id (const RegularArray &array, const std::vector<db::Vector> &irregular);
|
||||
db::Vector create_repetition (const db::Shape &array, RegularArray ®ular, std::vector<db::Vector> &irregular_array);
|
||||
template <class Obj>
|
||||
void write_shape(const db::Shape &shape, RegularArray ®ular, std::vector<db::Vector> &irregular_array);
|
||||
template <class Obj>
|
||||
void write_shape(const db::Shape &shape, const db::Vector &disp, RegularArray ®ular, std::vector<db::Vector> &irregular_array);
|
||||
};
|
||||
|
||||
template <> inline Compressed::compressed_container<db::Point> &Compressed::get_container () { return m_points; }
|
||||
template <> inline Compressed::compressed_container<db::Box> &Compressed::get_container () { return m_boxes; }
|
||||
template <> inline Compressed::compressed_container<db::Edge> &Compressed::get_container () { return m_edges; }
|
||||
template <> inline Compressed::compressed_container<db::EdgePair> &Compressed::get_container () { return m_edge_pairs; }
|
||||
template <> inline Compressed::compressed_container<db::Path> &Compressed::get_container () { return m_paths; }
|
||||
template <> inline Compressed::compressed_container<db::Polygon> &Compressed::get_container () { return m_polygons; }
|
||||
template <> inline Compressed::compressed_container<db::SimplePolygon> &Compressed::get_container () { return m_simple_polygons; }
|
||||
template <> inline Compressed::compressed_container<db::Text> &Compressed::get_container () { return m_texts; }
|
||||
template <> inline Compressed::compressed_container<db::CellInstArray> &Compressed::get_container () { return m_instances; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrCompressor.h"
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbHash.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Utilities that prevent signed coordinate overflow
|
||||
|
||||
template <class R>
|
||||
inline R safe_scale (double sf, R value)
|
||||
{
|
||||
double i = floor (sf * value + 0.5);
|
||||
if (i < double (std::numeric_limits<R>::min ())) {
|
||||
throw tl::Exception ("Scaling failed: coordinate underflow");
|
||||
}
|
||||
if (i > double (std::numeric_limits<R>::max ())) {
|
||||
throw tl::Exception ("Scaling failed: coordinate overflow");
|
||||
}
|
||||
return R (i);
|
||||
}
|
||||
|
||||
template <class R>
|
||||
inline R safe_diff (R a, R b)
|
||||
{
|
||||
R d = a - b;
|
||||
if ((a > b && d < 0) || (a < b && d > 0)) {
|
||||
throw tl::Exception ("Signed coordinate difference overflow");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
template <class Obj>
|
||||
void
|
||||
Compressor<Obj>::flush (CompressorDelivery *writer)
|
||||
{
|
||||
// produce the repetitions
|
||||
|
||||
std::vector<db::Vector> empty_irregular;
|
||||
RegularArray empty_regular;
|
||||
|
||||
disp_vector displacements;
|
||||
typedef std::vector <std::pair <db::Vector, std::pair <db::Coord, int> > > tmp_rep_vector;
|
||||
tmp_rep_vector repetitions;
|
||||
std::vector<std::pair<db::Vector, RegularArray> > rep_vector;
|
||||
|
||||
for (auto n = m_normalized.begin (); n != m_normalized.end (); ++n) {
|
||||
|
||||
rep_vector.clear ();
|
||||
|
||||
// don't compress below a threshold of 10 shapes
|
||||
if (m_level < 1 || n->second.size () < 10) {
|
||||
|
||||
// Simple compression: just sort and make irregular repetitions
|
||||
std::sort (n->second.begin (), n->second.end (), vector_cmp_x ());
|
||||
|
||||
} else {
|
||||
|
||||
disp_vector::iterator d;
|
||||
tmp_rep_vector::iterator rw;
|
||||
|
||||
std::unordered_set<db::Coord> xcoords, ycoords;
|
||||
if (m_level > 1) {
|
||||
for (d = n->second.begin (); d != n->second.end (); ++d) {
|
||||
xcoords.insert (d->x ());
|
||||
ycoords.insert (d->y ());
|
||||
}
|
||||
}
|
||||
|
||||
bool xfirst = xcoords.size () < ycoords.size ();
|
||||
|
||||
double simple_rep_cost = 0;
|
||||
double array_cost = 0;
|
||||
|
||||
// Try single-point compression to repetitions in the x and y direction. For the first
|
||||
// direction, use the one with more distinct values. For this, a better compression is
|
||||
// expected.
|
||||
for (int xypass = 0; xypass <= 1; ++xypass) {
|
||||
|
||||
bool xrep = (xfirst == (xypass == 0));
|
||||
|
||||
displacements.clear ();
|
||||
repetitions.clear ();
|
||||
|
||||
displacements.swap (n->second);
|
||||
if (xrep) {
|
||||
std::sort (displacements.begin (), displacements.end (), vector_cmp_x ());
|
||||
} else {
|
||||
std::sort (displacements.begin (), displacements.end (), vector_cmp_y ());
|
||||
}
|
||||
|
||||
if (xypass == 0 && m_level > 1) {
|
||||
// Establish a baseline for the repetition cost
|
||||
simple_rep_cost += cost_of (displacements.front ().x ()) + cost_of (displacements.front ().y ());
|
||||
for (d = displacements.begin () + 1; d != displacements.end (); ++d) {
|
||||
simple_rep_cost += std::max (1.0, cost_of (double (d->x ()) - double (d[-1].x ())) + cost_of (double (d->y ()) - double (d[-1].y ())));
|
||||
}
|
||||
}
|
||||
|
||||
disp_vector::iterator dwindow = displacements.begin ();
|
||||
for (d = displacements.begin (); d != displacements.end (); ) {
|
||||
|
||||
if (m_level < 2) {
|
||||
|
||||
disp_vector::iterator dd = d;
|
||||
++dd;
|
||||
|
||||
db::Vector dxy;
|
||||
int nxy = 1;
|
||||
|
||||
if (dd != displacements.end ()) {
|
||||
|
||||
dxy = xrep ? db::Vector (safe_diff (dd->x (), d->x ()), 0) : db::Vector (0, safe_diff (dd->y (), d->y ()));
|
||||
while (dd != displacements.end () && *dd == dd[-1] + dxy) {
|
||||
++dd;
|
||||
++nxy;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Note in level 1 optimization, no cost estimation is done, hence small arrays won't be removed.
|
||||
// To compensate that, we use a minimum size of 3 items per array.
|
||||
if (nxy < 3) {
|
||||
|
||||
n->second.push_back (*d++);
|
||||
|
||||
} else {
|
||||
|
||||
repetitions.push_back (std::make_pair (*d, std::make_pair (xrep ? dxy.x () : dxy.y (), nxy)));
|
||||
d = dd;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// collect the nearest neighbor distances and counts for 2..level order neighbors
|
||||
int nxy_max = 1;
|
||||
unsigned int nn_max = 0;
|
||||
|
||||
// move the window of identical x/y coordinates if necessary
|
||||
if (d == dwindow) {
|
||||
for (dwindow = d + 1; dwindow != displacements.end () && (xrep ? (dwindow->y () == d->y ()) : (dwindow->x () == d->x ())); ++dwindow)
|
||||
;
|
||||
}
|
||||
|
||||
for (unsigned int nn = 0; nn < m_level; ++nn) {
|
||||
|
||||
disp_vector::iterator dd = d + (nn + 1);
|
||||
if (dd >= dwindow) {
|
||||
break;
|
||||
}
|
||||
|
||||
db::Vector dxy = xrep ? db::Vector (safe_diff (dd->x (), d->x ()), 0) : db::Vector (0, safe_diff (dd->y (), d->y ()));
|
||||
|
||||
int nxy = 2;
|
||||
while (dd != dwindow) {
|
||||
disp_vector::iterator df = std::lower_bound (dd + 1, dwindow, *dd + dxy);
|
||||
if (df == dwindow || *df != *dd + dxy) {
|
||||
break;
|
||||
}
|
||||
++nxy;
|
||||
dd = df;
|
||||
}
|
||||
|
||||
if (nxy > nxy_max) {
|
||||
nxy_max = nxy;
|
||||
nn_max = nn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nxy_max < 2) {
|
||||
|
||||
// no candidate found - just keep that one
|
||||
n->second.push_back (*d++);
|
||||
|
||||
} else {
|
||||
|
||||
// take out the ones of this sequence from the list
|
||||
db::Vector dxy_max = xrep ? db::Vector (safe_diff ((d + nn_max + 1)->x (), d->x ()), 0) : db::Vector (0, safe_diff ((d + nn_max + 1)->y (), d->y ()));
|
||||
|
||||
disp_vector::iterator ds = dwindow;
|
||||
disp_vector::iterator dt = dwindow;
|
||||
db::Vector df = *d + dxy_max * long (nxy_max - 1);
|
||||
|
||||
do {
|
||||
--ds;
|
||||
if (*ds != df) {
|
||||
*--dt = *ds;
|
||||
} else {
|
||||
df -= dxy_max;
|
||||
}
|
||||
} while (ds != d);
|
||||
|
||||
repetitions.push_back (std::make_pair (*d, std::make_pair (xrep ? dxy_max.x () : dxy_max.y (), nxy_max)));
|
||||
|
||||
d = dt;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Apply some heuristic criterion that allows the algorithm to determine whether it's worth doing the compression
|
||||
|
||||
// Try to compact these repetitions further, y direction first, then x direction
|
||||
for (int xypass2 = 1; xypass2 >= 0; --xypass2) {
|
||||
|
||||
if (xypass2) {
|
||||
std::sort (repetitions.begin (), repetitions.end (), rep_vector_cmp<vector_cmp_y> ());
|
||||
} else {
|
||||
std::sort (repetitions.begin (), repetitions.end (), rep_vector_cmp<vector_cmp_x> ());
|
||||
}
|
||||
|
||||
rw = repetitions.begin ();
|
||||
for (auto r = repetitions.begin (); r != repetitions.end (); ) {
|
||||
|
||||
auto rr = r;
|
||||
++rr;
|
||||
|
||||
db::Vector dxy2;
|
||||
if (rr != repetitions.end ()) {
|
||||
dxy2 = xypass2 ? db::Vector (0, safe_diff (rr->first.y (), r->first.y ())) : db::Vector (safe_diff (rr->first.x (), r->first.x ()), 0);
|
||||
}
|
||||
int nxy2 = 1;
|
||||
|
||||
db::Vector dxy2n (dxy2);
|
||||
while (rr != repetitions.end () && rr->second == r->second && rr->first == r->first + dxy2n) {
|
||||
++nxy2;
|
||||
++rr;
|
||||
dxy2n += dxy2;
|
||||
}
|
||||
|
||||
if (nxy2 < 2 && xypass2) {
|
||||
*rw++ = *r;
|
||||
} else {
|
||||
if (m_level < 2) {
|
||||
Obj obj = n->first;
|
||||
obj.move (r->first);
|
||||
db::Vector a (xrep ? r->second.first : 0, xrep ? 0 : r->second.first);
|
||||
writer->write (obj, RegularArray (a, dxy2, r->second.second, nxy2), empty_irregular);
|
||||
} else {
|
||||
db::Vector a (xrep ? r->second.first : 0, xrep ? 0 : r->second.first);
|
||||
rep_vector.push_back (std::make_pair (r->first, RegularArray (a, dxy2, r->second.second, nxy2)));
|
||||
}
|
||||
}
|
||||
|
||||
r = rr;
|
||||
|
||||
}
|
||||
|
||||
repetitions.erase (rw, repetitions.end ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_level > 1) {
|
||||
|
||||
// Compute a cost for the repetitions
|
||||
|
||||
if (! n->second.empty ()) {
|
||||
// irregular repetition contribution
|
||||
array_cost += cost_of (n->second.front ().x ()) + cost_of (n->second.front ().y ());
|
||||
for (auto d = n->second.begin () + 1; d != n->second.end (); ++d) {
|
||||
array_cost += std::max(1.0, cost_of (d->x () - d[-1].x ()) + cost_of (d->y () - d[-1].y ()));
|
||||
}
|
||||
}
|
||||
|
||||
bool array_set = false;
|
||||
db::Vector a_ref, b_ref;
|
||||
size_t in_ref = 0, im_ref = 0;
|
||||
bool ref_set = false;
|
||||
db::Coord x_ref = 0, y_ref = 0;
|
||||
|
||||
for (auto r = rep_vector.begin (); r != rep_vector.end (); ++r) {
|
||||
|
||||
db::Vector a, b;
|
||||
size_t in = 0, im = 0;
|
||||
|
||||
array_cost += 2; // two bytes for the shape
|
||||
|
||||
// The cost of the first point (takes into account compression by reuse of one coordinate)
|
||||
if (!ref_set || x_ref != r->first.x ()) {
|
||||
array_cost += cost_of (r->first.x ());
|
||||
}
|
||||
if (!ref_set || y_ref != r->first.y ()) {
|
||||
array_cost += cost_of (r->first.y ());
|
||||
}
|
||||
ref_set = true;
|
||||
x_ref = r->first.x ();
|
||||
y_ref = r->first.y ();
|
||||
|
||||
// Cost of the repetition (takes into account reuse)
|
||||
if (! array_set || a != a_ref || b != b_ref || in != in_ref || im != im_ref) {
|
||||
array_set = true;
|
||||
a_ref = a;
|
||||
b_ref = b;
|
||||
in_ref = in;
|
||||
im_ref = im;
|
||||
array_cost += cost_of (a.x ()) + cost_of (b.x ()) + cost_of (a.y ()) + cost_of (b.y ()) + cost_of (in) + cost_of (im);
|
||||
} else {
|
||||
array_cost += 1; // one byte
|
||||
}
|
||||
|
||||
// Note: the pointlist is reused, hence does not contribute
|
||||
|
||||
}
|
||||
|
||||
// And resolve the repetitions if it does not make sense to keep them
|
||||
if (array_cost > simple_rep_cost) {
|
||||
for (auto r = rep_vector.begin (); r != rep_vector.end (); ++r) {
|
||||
for (size_t ia = 0; ia < r->second.na (); ++ia) {
|
||||
for (size_t ib = 0; ib < r->second.nb (); ++ib) {
|
||||
n->second.push_back (r->first + r->second.a () * long (ia) + r->second.b () * long (ib));
|
||||
}
|
||||
}
|
||||
}
|
||||
rep_vector.clear ();
|
||||
std::sort (n->second.begin (), n->second.end (), vector_cmp_x ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto r = rep_vector.begin (); r != rep_vector.end (); ++r) {
|
||||
Obj obj = n->first;
|
||||
obj.move (r->first);
|
||||
writer->write (obj, r->second, empty_irregular);
|
||||
}
|
||||
|
||||
if (n->second.size () > 1) {
|
||||
|
||||
// need to normalize?
|
||||
db::Vector p0 = n->second.front ();
|
||||
std::vector<db::Vector>::iterator pw = n->second.begin();
|
||||
for (auto p = pw + 1; p != n->second.end (); ++p) {
|
||||
*pw++ = *p - p0;
|
||||
}
|
||||
n->second.erase (pw, n->second.end ());
|
||||
|
||||
Obj obj = n->first;
|
||||
obj.move (p0);
|
||||
writer->write (obj, empty_regular, n->second);
|
||||
|
||||
} else if (! n->second.empty ()) {
|
||||
|
||||
Obj obj = n->first;
|
||||
obj.move (n->second.front ());
|
||||
writer->write (obj, empty_regular, empty_irregular);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class Compressor<db::Point>;
|
||||
template class Compressor<db::PointWithProperties>;
|
||||
template class Compressor<db::Box>;
|
||||
template class Compressor<db::BoxWithProperties>;
|
||||
template class Compressor<db::Edge>;
|
||||
template class Compressor<db::EdgeWithProperties>;
|
||||
template class Compressor<db::EdgePair>;
|
||||
template class Compressor<db::EdgePairWithProperties>;
|
||||
template class Compressor<db::Polygon>;
|
||||
template class Compressor<db::PolygonWithProperties>;
|
||||
template class Compressor<db::SimplePolygon>;
|
||||
template class Compressor<db::SimplePolygonWithProperties>;
|
||||
template class Compressor<db::Text>;
|
||||
template class Compressor<db::TextWithProperties>;
|
||||
template class Compressor<db::Path>;
|
||||
template class Compressor<db::PathWithProperties>;
|
||||
template class Compressor<db::CellInstArray>;
|
||||
template class Compressor<db::CellInstArrayWithProperties>;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrCompressor
|
||||
#define HDR_lstrCompressor
|
||||
|
||||
#include "dbVector.h"
|
||||
#include "dbBox.h"
|
||||
#include "dbPath.h"
|
||||
#include "dbEdge.h"
|
||||
#include "dbEdgePair.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbText.h"
|
||||
#include "dbInstances.h"
|
||||
#include "dbObjectWithProperties.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
const unsigned int max_lstreame_compression_level = 10;
|
||||
|
||||
/**
|
||||
* @brief Compare operator for points, distinct x clustered (with same y)
|
||||
*/
|
||||
struct vector_cmp_x
|
||||
{
|
||||
bool operator() (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
if (a.y () != b.y ()) {
|
||||
return a.y () < b.y ();
|
||||
} else {
|
||||
return a.x () < b.x ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare operator for points, distinct y clustered (with same x)
|
||||
*/
|
||||
struct vector_cmp_y
|
||||
{
|
||||
bool operator() (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
if (a.x () != b.x ()) {
|
||||
return a.x () < b.x ();
|
||||
} else {
|
||||
return a.y () < b.y ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Returns the cost value of a coordinate difference (or coordinate)
|
||||
* The cost is used to estimate the size cost of a coordinate difference
|
||||
* in the OASIS output.
|
||||
* The cost is roughly the number of bytes required to represent the
|
||||
* number. It does not consider gdelta compression, actual byte count or similar.
|
||||
*
|
||||
* TODO: this heuristics is taken from OASIS. I should be adapted to LStream.
|
||||
*/
|
||||
inline double cost_of (double d)
|
||||
{
|
||||
int exp = 0;
|
||||
frexp (d, &exp);
|
||||
return double ((exp + 7) / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A predicate describing whether an object is empty
|
||||
*
|
||||
* An object is "empty", if it does not have at least one reference point.
|
||||
* For example, an empty box is empty. Such objects cannot be written and are
|
||||
* stripped.
|
||||
*/
|
||||
template <class Object>
|
||||
static inline bool object_is_empty (const Object &) { return false; }
|
||||
static inline bool object_is_empty (const db::Box &object) { return object.empty (); }
|
||||
static inline bool object_is_empty (const db::Polygon &object) { return object.hull ().begin () == object.hull ().end (); }
|
||||
static inline bool object_is_empty (const db::SimplePolygon &object) { return object.hull ().begin () == object.hull ().end (); }
|
||||
static inline bool object_is_empty (const db::Path &object) { return object.begin () == object.end (); }
|
||||
|
||||
/**
|
||||
* @brief Normalization of the position of an object
|
||||
*/
|
||||
template <class Object>
|
||||
static inline db::Vector reduce_object (Object &object)
|
||||
{
|
||||
db::Disp tr;
|
||||
object.reduce (tr);
|
||||
return tr.disp ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specialization for EdgePair which currently does not have "reduce"
|
||||
*/
|
||||
static inline db::Vector reduce_object_edge_pair (db::EdgePair &ep)
|
||||
{
|
||||
db::EdgePair::vector_type d (ep.first ().p1 ());
|
||||
ep.move (-d);
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::EdgePair &ep)
|
||||
{
|
||||
return reduce_object_edge_pair (ep);
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::EdgePairWithProperties &ep)
|
||||
{
|
||||
return reduce_object_edge_pair (ep);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specialization for EdgePair which currently does not have "reduce"
|
||||
*/
|
||||
static inline db::Vector reduce_object_point (db::Point &pt)
|
||||
{
|
||||
db::Vector d = db::Point () - pt;
|
||||
pt = db::Point ();
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::Point &pt)
|
||||
{
|
||||
return reduce_object_point (pt);
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::PointWithProperties &pt)
|
||||
{
|
||||
return reduce_object_point (pt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specialization for CellInstArray
|
||||
*/
|
||||
static inline db::Vector reduce_object_cell_inst_array (db::CellInstArray &ci)
|
||||
{
|
||||
db::Vector d = ci.front ().disp ();
|
||||
ci.move (-d);
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::CellInstArray &ci)
|
||||
{
|
||||
return reduce_object_cell_inst_array (ci);
|
||||
}
|
||||
|
||||
static inline db::Vector reduce_object (db::CellInstArrayWithProperties &ci)
|
||||
{
|
||||
return reduce_object_cell_inst_array (ci);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator for points/abstract repetition pair with configurable point compare operator
|
||||
*/
|
||||
template <class PC>
|
||||
struct rep_vector_cmp
|
||||
{
|
||||
bool operator () (const std::pair <db::Vector, std::pair <db::Coord, int> > &a, const std::pair <db::Vector, std::pair <db::Coord, int> > &b)
|
||||
{
|
||||
if (a.second != b.second) {
|
||||
return a.second < b.second;
|
||||
}
|
||||
PC pc;
|
||||
return pc (a.first, b.first);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a regular array
|
||||
*
|
||||
* A regular array is a set of displacements given by the
|
||||
* formula
|
||||
*
|
||||
* d = ia*a + ib*b
|
||||
*
|
||||
* where "ia" is an integer running from 0 to na-1, "ib" is an integer
|
||||
* running from 0 to nb-1 and "a" and "b" are two arbitrary vectors.
|
||||
*
|
||||
* The axes "a" and "b" do not need to be orthogonal in the general
|
||||
* case, but they should not be collinear.
|
||||
*
|
||||
* "na" and "nb" are the dimensions of the array.
|
||||
*
|
||||
* An array can be "null", which means it does not represent any
|
||||
* placements.
|
||||
*/
|
||||
class RegularArray
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Creates a null array
|
||||
*/
|
||||
RegularArray ()
|
||||
: m_na (0), m_nb (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates an array with the given axes and dimensions
|
||||
*
|
||||
* @param a The "a" axis
|
||||
* @param b The "b" axis
|
||||
* @param na The "a" dimension
|
||||
* @param nb The "b" dimension
|
||||
*/
|
||||
RegularArray (const db::Vector &a, const db::Vector &b, size_t na, size_t nb)
|
||||
: m_a (a), m_b (b), m_na (na), m_nb (nb)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the array is a null array
|
||||
*/
|
||||
bool is_null () const
|
||||
{
|
||||
return m_na == 0 || m_nb == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the a axis
|
||||
*/
|
||||
const db::Vector &a () const { return m_a; }
|
||||
|
||||
/**
|
||||
* @brief Gets the b axis
|
||||
*/
|
||||
const db::Vector &b () const { return m_b; }
|
||||
|
||||
/**
|
||||
* @brief Gets the a dimension
|
||||
*/
|
||||
size_t na () const { return m_na; }
|
||||
|
||||
/**
|
||||
* @brief Gets the b dimension
|
||||
*/
|
||||
size_t nb () const { return m_nb; }
|
||||
|
||||
/**
|
||||
* @brief The equality operator
|
||||
*/
|
||||
bool operator== (const RegularArray &other) const
|
||||
{
|
||||
return m_a == other.m_a &&
|
||||
m_b == other.m_b &&
|
||||
m_na == other.m_na &&
|
||||
m_nb == other.m_nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The less operator
|
||||
*
|
||||
* This operator is provided for strict weak ordering
|
||||
* for us of the array as a key in std::map or std::set.
|
||||
*/
|
||||
bool operator< (const RegularArray &other) const
|
||||
{
|
||||
if (m_a != other.m_a) {
|
||||
return m_a < other.m_a;
|
||||
}
|
||||
if (m_b != other.m_b) {
|
||||
return m_b < other.m_b;
|
||||
}
|
||||
if (m_na != other.m_na) {
|
||||
return m_na < other.m_na;
|
||||
}
|
||||
if (m_nb != other.m_nb) {
|
||||
return m_nb < other.m_nb;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
db::Vector m_a, m_b;
|
||||
size_t m_na, m_nb;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An interface by which the compressor delivers the results of the compression
|
||||
*
|
||||
* Note that we're lacking virtual templates, hence the large number of
|
||||
* methods for every object type.
|
||||
*/
|
||||
class CompressorDelivery
|
||||
{
|
||||
public:
|
||||
typedef std::vector<db::Vector> disp_vector;
|
||||
|
||||
virtual ~CompressorDelivery () { }
|
||||
|
||||
virtual void write (const db::Point &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::PointWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::Box &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::BoxWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::Edge &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::EdgeWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::EdgePair &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::EdgePairWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::Polygon &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::PolygonWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::SimplePolygon &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::SimplePolygonWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::Path &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::PathWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::Text &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::TextWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::CellInstArray &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
virtual void write (const db::CellInstArrayWithProperties &obj, const RegularArray &array, const disp_vector &irregular) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The compressor object
|
||||
*
|
||||
* The task of the compressor object is to accept a serial stream
|
||||
* of individual objects and arranging them into arrays as far as possible.
|
||||
*
|
||||
* Arrays can be regular (RegularArray) or enumerated (lists of placements).
|
||||
*
|
||||
* Individual objects are fed using the "add" method. Once all objects
|
||||
* are fed "flush" can be used to deliver the compressed arrays to a
|
||||
* "CompressorDelivery" object.
|
||||
*
|
||||
* Note that once "flush" is called, "add" should no longer be used.
|
||||
* For compressing new objects, construct a fresh Compressor object.
|
||||
*/
|
||||
template <class Obj>
|
||||
class Compressor
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param level The compression level
|
||||
*
|
||||
* Allowed levels are:
|
||||
* 0 - simple
|
||||
* 1 - form simple arrays
|
||||
* 2++ - search for 2nd, 3rd ... order neighbors
|
||||
*/
|
||||
Compressor (unsigned int level)
|
||||
: m_level (level)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a new object with the given displacement
|
||||
*
|
||||
* The object is supposed to be reduced (positioned at 0,0)
|
||||
* already and the displacement specifies where the object
|
||||
* was sitting originally.
|
||||
*/
|
||||
void add (const Obj &obj, const db::Vector &disp)
|
||||
{
|
||||
if (! object_is_empty (obj)) {
|
||||
m_normalized [obj].push_back (disp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an object with reduction
|
||||
*
|
||||
* The object added can sit anywhere. Before it is added,
|
||||
* it is reduced (positioned at 0,0) and the displacement
|
||||
* is recorded for array formation.
|
||||
*/
|
||||
void add (const Obj &obj)
|
||||
{
|
||||
if (! object_is_empty (obj)) {
|
||||
Obj red (obj);
|
||||
auto disp = reduce_object (red);
|
||||
m_normalized [red].push_back (disp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates arrays and delivers when to the delivery interface
|
||||
*
|
||||
* This method will can "deliver->write (Object, ...)" as many times as
|
||||
* needed.
|
||||
*
|
||||
* Note that single objects may be delivered as well. These are encoded
|
||||
* as null regular arrays and empty irregular placement lists.
|
||||
*/
|
||||
void flush (CompressorDelivery *delivery);
|
||||
|
||||
private:
|
||||
typedef std::vector<db::Vector> disp_vector;
|
||||
|
||||
std::unordered_map <Obj, disp_vector> m_normalized;
|
||||
unsigned int m_level;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrFormat.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
WriterOptions::WriterOptions ()
|
||||
: compression_level (2), recompress (false), permissive (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ReaderOptions::ReaderOptions ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrFormat
|
||||
#define HDR_lstrFormat
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Structure that holds the LStream specific options for the reader
|
||||
* NOTE: this structure is non-public linkage by intention. This way it's instantiated
|
||||
* in all compile units and the shared object does not need to be linked.
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC ReaderOptions
|
||||
: public db::FormatSpecificReaderOptions
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
ReaderOptions ();
|
||||
|
||||
/**
|
||||
* @brief If not empty, this string specifies a key under which the bbox from the stream is stored in the cells
|
||||
*/
|
||||
std::string bbox_meta_info_key;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificReaderOptions
|
||||
*/
|
||||
virtual db::FormatSpecificReaderOptions *clone () const
|
||||
{
|
||||
return new ReaderOptions (*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificReaderOptions
|
||||
*/
|
||||
virtual const std::string &format_name () const
|
||||
{
|
||||
static const std::string n ("LStream");
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure that holds the OASIS specific options for the Writer
|
||||
* NOTE: this structure is non-public linkage by intention. This way it's instantiated
|
||||
* in all compile units and the shared object does not need to be linked.
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC WriterOptions
|
||||
: public db::FormatSpecificWriterOptions
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
WriterOptions ();
|
||||
|
||||
/**
|
||||
* @brief OASIS writer compression level
|
||||
*
|
||||
* This level describes how hard the OASIS writer will try to compress the shapes
|
||||
* using shape arrays. Building shape arrays may take some time and requires some memory.
|
||||
* 0 - no shape array building
|
||||
* 1 - nearest neighbor shape array formation
|
||||
* 2++ - enhanced shape array search algorithm using 2nd and further neighbor distances as well
|
||||
*/
|
||||
int compression_level;
|
||||
|
||||
/**
|
||||
* @brief Recompressions
|
||||
*
|
||||
* If the recompression flag is true, existing shape arrays will be resolved and
|
||||
* put into the compressor again (may take longer).
|
||||
*/
|
||||
bool recompress;
|
||||
|
||||
/**
|
||||
* @brief Permissive mode
|
||||
*
|
||||
* In permissive mode, a warning is issued for certain cases rather than
|
||||
* an error. For example paths/circles with odd diameter (rounded).
|
||||
*/
|
||||
bool permissive;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
virtual db::FormatSpecificWriterOptions *clone () const
|
||||
{
|
||||
return new WriterOptions (*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
virtual const std::string &format_name () const
|
||||
{
|
||||
static std::string n ("LStream");
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrReader.h"
|
||||
#include "lstrWriter.h"
|
||||
#include "lstrPlugin.h"
|
||||
#include "lstrFormat.h"
|
||||
|
||||
#include "dbStream.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Signature string and generator
|
||||
|
||||
const char *LStream_sig = "LStream_1.0";
|
||||
|
||||
const char *LStream_generator = "klayout " STRINGIFY(KLAYOUT_VERSION);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief The LStream plugin
|
||||
*
|
||||
* Providing a class a regiserting it will enable this file
|
||||
* format inside KLayout.
|
||||
*
|
||||
* It implements the "db::StreamFormatDeclaration" interface
|
||||
* and provides KLayout with the necessary information to
|
||||
* implement the format.
|
||||
*/
|
||||
class LStreamFormatDeclaration
|
||||
: public db::StreamFormatDeclaration
|
||||
{
|
||||
virtual std::string format_name () const { return "LStream"; }
|
||||
virtual std::string format_desc () const { return "LStream"; }
|
||||
virtual std::string format_title () const { return "LStream"; }
|
||||
virtual std::string file_format () const { return "LStream files (*.lstr *.lstr.gz)"; }
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the given stream represents the particular format
|
||||
*
|
||||
* KLayout will use this method to identify a file by content, rather than
|
||||
* suffix. In the LStream case, the format is detected by the magic bytes
|
||||
* at the front of the stream.
|
||||
*/
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
const char *hdr = stream.get (strlen (LStream_sig) + 1);
|
||||
return (hdr && strcmp (hdr, LStream_sig) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a reader object that does the actual reading
|
||||
*/
|
||||
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
|
||||
{
|
||||
return new Reader (s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a writer object that does the actual reading
|
||||
*/
|
||||
virtual db::WriterBase *create_writer () const
|
||||
{
|
||||
return new Writer ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether reading is supported
|
||||
*/
|
||||
virtual bool can_read () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether writing is supported
|
||||
*/
|
||||
virtual bool can_write () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual tl::XMLElementBase *xml_writer_options_element () const
|
||||
{
|
||||
return new db::WriterOptionsXMLElement<lstr::WriterOptions> ("lstream",
|
||||
tl::make_member (&lstr::WriterOptions::compression_level, "compression-level") +
|
||||
tl::make_member (&lstr::WriterOptions::recompress, "recompress") +
|
||||
tl::make_member (&lstr::WriterOptions::permissive, "permissive")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new LStreamFormatDeclaration (), 0, "LStream");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrPlugin
|
||||
#define HDR_lstrPlugin
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The magic bytes at the beginning of a LStream file
|
||||
*/
|
||||
extern const char *LStream_sig;
|
||||
|
||||
/**
|
||||
* @brief The generator name for writing Header::generator
|
||||
*/
|
||||
extern const char *LStream_generator;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrReader
|
||||
#define HDR_lstrReader
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbCommonReader.h"
|
||||
#include "dbStreamLayers.h"
|
||||
|
||||
#include "library.capnp.h"
|
||||
#include "repetition.capnp.h"
|
||||
#include "layoutView.capnp.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlString.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <kj/io.h>
|
||||
|
||||
namespace kj
|
||||
{
|
||||
class BufferedInputStream;
|
||||
}
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A reimplementation of the kj::InputStream interface to provide KLayout streams for Cap'n'Proto
|
||||
*
|
||||
* Note: this implementation is not based on the buffered streams of KLayout
|
||||
* which are not compatible with kj::BufferedInputStreamWrapper as of now.
|
||||
* Instead we use the unterlying basic stream of KLayout which is pretty
|
||||
* much compatible with kj.
|
||||
*/
|
||||
class InputStream
|
||||
: public kj::InputStream
|
||||
{
|
||||
public:
|
||||
InputStream (tl::InputStream *is)
|
||||
: mp_is (is), m_pos (is->pos ()), m_pos_before (is->pos ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual size_t tryRead (void *buffer, size_t /*min_bytes*/, size_t max_bytes)
|
||||
{
|
||||
size_t n = mp_is->base ()->read ((char *) buffer, max_bytes);
|
||||
m_pos_before = m_pos;
|
||||
m_pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* TODO: we don't have "skip" on the delegate right now.
|
||||
virtual void skip (size_t bytes)
|
||||
{
|
||||
mp_is->base ()->skip (bytes);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Resets the basic stream, so we can restart
|
||||
*/
|
||||
void reset ()
|
||||
{
|
||||
mp_is->base ()->reset ();
|
||||
m_pos_before = m_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the position in the stream after the current chunk
|
||||
*/
|
||||
size_t position ()
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the position in the stream before the current chunk
|
||||
*/
|
||||
size_t position_before ()
|
||||
{
|
||||
return m_pos_before;
|
||||
}
|
||||
|
||||
private:
|
||||
tl::InputStream *mp_is;
|
||||
size_t m_pos, m_pos_before;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic base class of LStream reader exceptions
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC LStreamReaderException
|
||||
: public db::ReaderException
|
||||
{
|
||||
public:
|
||||
LStreamReaderException (const std::string &msg, const std::string &cell, const std::string &source, const std::string &pos)
|
||||
: db::ReaderException (
|
||||
cell.empty () ?
|
||||
tl::sprintf (tl::to_string (tr ("%s, in file: %s (position %s)")), msg, source, pos) :
|
||||
tl::sprintf (tl::to_string (tr ("%s (cell=%s), in file: %s (position %s)")), msg, cell, source, pos)
|
||||
)
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The LStream format stream reader
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC Reader
|
||||
: public db::CommonReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a stream reader object
|
||||
*
|
||||
* @param s The stream delegate from which to read stream data from
|
||||
*/
|
||||
Reader (tl::InputStream &s);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Reader () noexcept;
|
||||
|
||||
/**
|
||||
* @brief Format
|
||||
*/
|
||||
virtual const char *format () const { return "LStream"; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Implementation of the db::CommonReader interface
|
||||
*
|
||||
* This method will read the information from the stream
|
||||
* passed in the constructor.
|
||||
*/
|
||||
virtual void do_read (db::Layout &layout);
|
||||
|
||||
/**
|
||||
* @brief Implementation of db::CommonReader InputStream
|
||||
*
|
||||
* This method is called to initialize the reader
|
||||
* from the given options.
|
||||
*/
|
||||
virtual void init (const db::LoadLayoutOptions &options);
|
||||
|
||||
/**
|
||||
* @brief Issues an errors
|
||||
*/
|
||||
void error (const std::string &msg);
|
||||
|
||||
/**
|
||||
* @brief Issues a warning
|
||||
*
|
||||
* The warning level indicates the severity.
|
||||
* A higher value indicates lower severity.
|
||||
*/
|
||||
void warn (const std::string &msg, int warn_level = 1);
|
||||
|
||||
/**
|
||||
* @brief Accessor method to the current cellname
|
||||
*/
|
||||
const std::string &cellname () const { return m_cellname; }
|
||||
|
||||
private:
|
||||
lstr::InputStream m_stream;
|
||||
std::string m_source;
|
||||
std::string m_bbox_meta_data_key;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
size_t m_library_index;
|
||||
std::string m_cellname;
|
||||
std::string m_libname;
|
||||
db::Cell *mp_cell;
|
||||
db::Layout *mp_layout;
|
||||
std::map<uint64_t, unsigned int> m_layer_id_map;
|
||||
std::map<uint64_t, std::string> m_library_names_by_id;
|
||||
std::map<uint64_t, db::property_names_id_type> m_property_name_id_map;
|
||||
std::map<uint64_t, db::properties_id_type> m_properties_id_map;
|
||||
std::map<uint64_t, const db::StringRef *> m_text_strings_by_id;
|
||||
uint64_t m_layout_view_id;
|
||||
uint64_t m_meta_data_view_id;
|
||||
std::vector<std::pair<db::cell_index_type, std::string> > m_cells;
|
||||
|
||||
void yield_progress ();
|
||||
std::string position ();
|
||||
void do_read_internal (db::Layout &layout);
|
||||
void read_header (kj::BufferedInputStream &is);
|
||||
void read_library (kj::BufferedInputStream &is);
|
||||
void skip_library (kj::BufferedInputStream &is);
|
||||
void read_cell (db::cell_index_type cell_index, kj::BufferedInputStream &is);
|
||||
void make_single_cell_instance (db::cell_index_type of_cell, db::properties_id_type prop_id, const db::ICplxTrans &ct);
|
||||
void make_cell_instance (db::cell_index_type of_cell, db::properties_id_type prop_id, stream::repetition::Repetition::Reader repetition, const db::ICplxTrans &ct);
|
||||
void read_instances (stream::layoutView::LayoutView::Reader layout_view);
|
||||
template <class Object, class CPObject>
|
||||
void read_shapes (unsigned int li, typename stream::layoutView::ObjectContainerForType<CPObject>::Reader reader, capnp::List<stream::repetition::Repetition, capnp::Kind::STRUCT>::Reader repetitions);
|
||||
void read_layer (stream::layoutView::Layer::Reader reader);
|
||||
void read_layout_view (db::cell_index_type cell_index, kj::BufferedInputStream &is);
|
||||
void read_meta_data_view (db::cell_index_type cell_index, kj::BufferedInputStream &is);
|
||||
void read_layers (stream::library::ViewSpec::Reader view_specs);
|
||||
tl::Variant make_variant (stream::variant::Variant::Value::Reader variant);
|
||||
void make_meta_data(const db::Cell *cell, stream::metaData::MetaData::Reader property_set);
|
||||
std::map<std::string, tl::Variant> make_pcell_parameters (stream::library::CellParameters::Reader cell_parameters);
|
||||
void read_cells(stream::library::Library::Reader header);
|
||||
void read_library_refs (stream::library::Library::Reader header);
|
||||
void read_properties (stream::library::Library::Reader header);
|
||||
void read_text_strings (stream::library::Library::Reader header);
|
||||
unsigned int get_layer_by_id (uint64_t id) const;
|
||||
std::string get_library_name_by_id (uint64_t id) const;
|
||||
db::property_names_id_type get_property_name_id_by_id (uint64_t id) const;
|
||||
db::properties_id_type get_properties_id_by_id (uint64_t id) const;
|
||||
const db::StringRef *get_string_by_id (uint64_t id) const;
|
||||
db::Vector make_object (stream::geometry::Vector::Reader reader);
|
||||
db::Point make_object (stream::geometry::Point::Reader reader);
|
||||
db::Box make_object (stream::geometry::Box::Reader reader);
|
||||
db::Edge make_object (stream::geometry::Edge::Reader reader);
|
||||
db::EdgePair make_object (stream::geometry::EdgePair::Reader reader);
|
||||
db::SimplePolygonRef make_object (stream::geometry::SimplePolygon::Reader reader);
|
||||
db::PolygonRef make_object (stream::geometry::Polygon::Reader reader);
|
||||
db::PathRef make_object (stream::geometry::Path::Reader reader);
|
||||
db::Text make_object (stream::geometry::Label::Reader reader);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::PolygonRef &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::SimplePolygonRef &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::PathRef &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::EdgePair &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::Edge &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::Point &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::Text &object, stream::repetition::Repetition::Reader repetition);
|
||||
void make_object_array (unsigned int li, db::properties_id_type prop_id, const db::Box &object, stream::repetition::Repetition::Reader repetition);
|
||||
template <class Object>
|
||||
void make_object_array_ref (unsigned int li, db::properties_id_type prop_id, const Object &object, stream::repetition::Repetition::Reader repetition);
|
||||
template <class Object, class ObjectPtr>
|
||||
void make_object_array_ptr (unsigned int li, db::properties_id_type prop_id, const Object &object, stream::repetition::Repetition::Reader repetition);
|
||||
template <class Object>
|
||||
void make_object_array_explode (unsigned int li, db::properties_id_type prop_id, const Object &object, stream::repetition::Repetition::Reader repetition);
|
||||
|
||||
virtual void common_reader_error (const std::string &msg) { error (msg); }
|
||||
virtual void common_reader_warn (const std::string &msg, int warn_level = 1) { warn (msg, warn_level); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_lstrWriter
|
||||
#define HDR_lstrWriter
|
||||
|
||||
#include "lstrCompressed.h"
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbWriterTools.h"
|
||||
#include "dbWriter.h"
|
||||
|
||||
#include "tlProgress.h"
|
||||
|
||||
#include "header.capnp.h"
|
||||
#include "library.capnp.h"
|
||||
#include "variant.capnp.h"
|
||||
#include "geometry.capnp.h"
|
||||
#include "cell.capnp.h"
|
||||
#include "layoutView.capnp.h"
|
||||
|
||||
#include <capnp/serialize-packed.h>
|
||||
|
||||
namespace kj
|
||||
{
|
||||
class BufferedOutputStream;
|
||||
}
|
||||
|
||||
namespace lstr
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The LStream format stream writer
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC Writer
|
||||
: public db::WriterBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Instantiate the writer
|
||||
*/
|
||||
Writer ();
|
||||
|
||||
/**
|
||||
* @brief Writes the layout object
|
||||
*
|
||||
* @param layout The layout object to write
|
||||
* @param stream The stream to write to
|
||||
* @param options The writer options to use
|
||||
*/
|
||||
void write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options);
|
||||
|
||||
private:
|
||||
tl::OutputStream *mp_stream;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
db::SaveLayoutOptions m_options;
|
||||
bool m_recompress;
|
||||
int m_compression_level;
|
||||
bool m_permissive;
|
||||
db::Layout *mp_layout;
|
||||
std::string m_cellname;
|
||||
unsigned int m_layout_view_id;
|
||||
unsigned int m_meta_data_view_id;
|
||||
std::map<db::lib_id_type, uint64_t> m_ls_lib_ids;
|
||||
std::vector<std::pair <unsigned int, db::LayerProperties> > m_layers_to_write;
|
||||
std::set<db::cell_index_type> m_cells_to_write;
|
||||
std::map<db::property_names_id_type, uint64_t> m_ls_prop_name_ids;
|
||||
std::map<db::properties_id_type, uint64_t> m_ls_prop_ids;
|
||||
std::map<std::string, uint64_t> m_text_strings;
|
||||
std::map<db::cell_index_type, uint64_t> m_ls_cell_ids;
|
||||
|
||||
void yield_progress ();
|
||||
void warn (const std::string &msg);
|
||||
void write_header (kj::BufferedOutputStream &os);
|
||||
void write_library (kj::BufferedOutputStream &os);
|
||||
void make_library_refs_table (stream::library::LibraryRefs::Builder library_names);
|
||||
uint64_t get_library_ref_id (db::lib_id_type lib_id);
|
||||
void collect_property_ids (std::vector<db::properties_id_type> &prop_ids, std::vector<db::property_names_id_type> &prop_names);
|
||||
uint64_t make_property_id (db::properties_id_type id, std::vector<db::properties_id_type> &prop_ids, std::vector<db::property_names_id_type> &prop_names);
|
||||
uint64_t make_property_name_id_from_id (db::property_names_id_type name_id, std::vector<db::property_names_id_type> &prop_names);
|
||||
uint64_t make_property_name_id_from_variant (const tl::Variant &name, std::vector<db::property_names_id_type> &prop_names);
|
||||
uint64_t get_property_id (db::properties_id_type id);
|
||||
uint64_t get_property_name_id_from_id (db::property_names_id_type name_id);
|
||||
uint64_t get_property_name_id_from_variant (const tl::Variant &name);
|
||||
void make_property_names_tables (const std::vector<db::property_names_id_type> &prop_names, stream::library::PropertyNamesTable::Builder property_names);
|
||||
void make_properties_tables (const std::vector<db::properties_id_type> &prop_ids, stream::library::PropertiesTable::Builder properties);
|
||||
void make_variant_value (const tl::Variant &value, stream::variant::Variant::Builder builder);
|
||||
void collect_text_strings (std::vector<std::string> &text_strings);
|
||||
uint64_t make_text_string_id (const std::string &string, std::vector<std::string> &text_strings);
|
||||
uint64_t get_text_string_id (const std::string &string);
|
||||
void make_text_strings_table (const std::vector<std::string> &text_strings, stream::library::TextStringsTable::Builder table);
|
||||
void make_layer_table (stream::library::LayerTable::Builder layers);
|
||||
void make_cell_specs (stream::library::CellSpecsTable::Builder cell_specs);
|
||||
uint64_t get_cell_id (db::cell_index_type ci);
|
||||
void make_cell_hierarchy_tree (stream::library::CellHierarchyTree::Builder cell_tree);
|
||||
void make_meta_data (const db::Cell *cell, stream::metaData::MetaData::Builder meta_data);
|
||||
|
||||
void write_cell (db::cell_index_type ci, kj::BufferedOutputStream &os);
|
||||
void write_layout_view (db::cell_index_type ci, kj::BufferedOutputStream &os);
|
||||
void write_meta_data_view (db::cell_index_type ci, kj::BufferedOutputStream &os);
|
||||
void make_repetition (const RegularArray &array, stream::repetition::Repetition::Builder builder);
|
||||
void make_repetition (const std::vector<db::Vector> &disp_array, stream::repetition::Repetition::Builder builder);
|
||||
void make_object (const db::SimplePolygon &obj, stream::geometry::SimplePolygon::Builder cpnp_obj);
|
||||
void make_object (const db::Polygon &obj, stream::geometry::Polygon::Builder cpnp_obj);
|
||||
void make_object (const db::Edge &obj, stream::geometry::Edge::Builder cpnp_obj);
|
||||
void make_object (const db::EdgePair &obj, stream::geometry::EdgePair::Builder cpnp_obj);
|
||||
void make_object (const db::Point &obj, stream::geometry::Point::Builder cpnp_obj);
|
||||
void make_object (const db::Box &obj, stream::geometry::Box::Builder cpnp_obj);
|
||||
void make_object (const db::Text &obj, stream::geometry::Label::Builder cpnp_obj);
|
||||
void make_object (const db::Path &obj, stream::geometry::Path::Builder cpnp_obj);
|
||||
void make_object (const db::CellInstArray &obj, stream::layoutView::CellInstance::Builder cpnp_obj);
|
||||
template <class Object, class Builder>
|
||||
void make_objects (const Compressed::compressed_container<Object> &container, Builder builder);
|
||||
stream::geometry::FixPointTransformation make_fixpoint_transformation (const db::Trans &trans);
|
||||
|
||||
// for debugging
|
||||
void replicate_message (const std::string &suffix, capnp::MessageBuilder &builder);
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "lstrReader.h"
|
||||
#include "lstrFormat.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "layLStreamReaderPlugin.h"
|
||||
#include "gsiDecl.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// LStreamReaderPluginDeclaration definition and implementation
|
||||
|
||||
class LStreamReaderPluginDeclaration
|
||||
: public StreamReaderPluginDeclaration
|
||||
{
|
||||
public:
|
||||
LStreamReaderPluginDeclaration ()
|
||||
: StreamReaderPluginDeclaration (lstr::ReaderOptions ().format_name ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
StreamReaderOptionsPage *format_specific_options_page (QWidget *parent) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
db::FormatSpecificReaderOptions *create_specific_options () const
|
||||
{
|
||||
return new lstr::ReaderOptions ();
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl (new lay::LStreamReaderPluginDeclaration (), 10000, "LStreamReader");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_layLStreamReaderPlugin_h
|
||||
#define HDR_layLStreamReaderPlugin_h
|
||||
|
||||
#include "layStream.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
DESTDIR = $$OUT_PWD/../../../../lay_plugins
|
||||
|
||||
include($$PWD/../../../lay_plugin.pri)
|
||||
|
||||
INCLUDEPATH += $$PWD/../db_plugin $$PWD/../db_plugin/capnp
|
||||
DEPENDPATH += $$PWD/../db_plugin
|
||||
LIBS += -L$$DESTDIR/../db_plugins -llstream
|
||||
|
||||
!isEmpty(RPATH) {
|
||||
QMAKE_RPATHDIR += $$RPATH/db_plugins
|
||||
}
|
||||
|
||||
HEADERS = \
|
||||
layLStreamReaderPlugin.h \
|
||||
|
||||
SOURCES = \
|
||||
layLStreamReaderPlugin.cc \
|
||||
|
||||
FORMS = \
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = runtime db_plugin unit_tests
|
||||
db_plugin.depends += runtime
|
||||
unit_tests.depends += db_plugin
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
SUBDIRS += lay_plugin
|
||||
lay_plugin.depends += db_plugin
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
# Cap'n'Proto runtime libraries
|
||||
|
||||
This code reflects version 1.0.1 of the kj and capnp library.
|
||||
|
||||
The "fetch.sh" script is used to populate this folder and to
|
||||
adapt the original project to qmake.
|
||||
|
||||
The original license files are found here:
|
||||
|
||||
capnp/LICENSE
|
||||
kj/LICENSE
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
TEMPLATE = lib
|
||||
DESTDIR = $$OUT_PWD/../../../../..
|
||||
|
||||
include($$PWD/capnp.pri)
|
||||
|
||||
TARGET = xcapnp
|
||||
SOURCES = $$CAPNP_SOURCES
|
||||
HEADERS = $$CAPNP_HEADERS
|
||||
|
||||
DEFINES += CAPNP_LITE
|
||||
INCLUDEPATH =
|
||||
LIBS =
|
||||
QT =
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
The following people have made large code contributions to this repository.
|
||||
Those contributions are copyright the respective authors and licensed by them
|
||||
under the same MIT license terms as the rest of the library.
|
||||
|
||||
Kenton Varda <kenton@sandstorm.io> <kenton@cloudflare.com>: Primary Author
|
||||
Jason Choy <jjwchoy@gmail.com>: kj/threadlocal.h and other iOS tweaks, `name` annotation in C++ code generator
|
||||
Remy Blank <rblank@google.com> (contributions copyright Google Inc.): KJ Timers
|
||||
Joshua Warner <joshuawarner32@gmail.com>: cmake build, AnyStruct/AnyList, other stuff
|
||||
Scott Purdy <scott@fer.io>: kj/std iostream interface
|
||||
Bryan Borham <bjboreham@gmail.com>: Initial MSVC support
|
||||
Philip Quinn <p@partylemon.com>: cmake build and other assorted bits
|
||||
Brian Taylor <el.wubo@gmail.com>: emacs syntax highlighting
|
||||
Ben Laurie <ben@links.org>: discovered and responsibly disclosed security bugs
|
||||
Kamal Marhubi <kamal@marhubi.com>: JSON parser
|
||||
Oliver Kuckertz <oliver.kuckertz@mologie.de>: FdObserver POLLPRI support
|
||||
Harris Hancock <vortrab@gmail.com>: MSVC support
|
||||
Branislav Katreniak <branislav.katreniak@digitalstrom.com>: JSON decode
|
||||
Matthew Maurer <matthew.r.maurer@gmail.com>: Canonicalization Support
|
||||
David Renshaw <david@sandstorm.io>: bugfixes and miscellaneous maintenance
|
||||
Ingvar Stepanyan <me@rreverser.com> <ingvar@cloudflare.com>: Custom handlers for JSON decode
|
||||
|
||||
This file does not list people who maintain their own Cap'n Proto
|
||||
implementations as separate projects. Those people are awesome too! :)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2013-2017 Sandstorm Development Group, Inc.; Cloudflare, Inc.;
|
||||
and other contributors. Each commit is copyright by its respective author or
|
||||
author's employer.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
CAPNP_SOURCES=\
|
||||
capnp/c++.capnp.c++ \
|
||||
capnp/blob.c++ \
|
||||
capnp/arena.c++ \
|
||||
capnp/layout.c++ \
|
||||
capnp/list.c++ \
|
||||
capnp/any.c++ \
|
||||
capnp/message.c++ \
|
||||
capnp/schema.capnp.c++ \
|
||||
capnp/stream.capnp.c++ \
|
||||
capnp/serialize.c++ \
|
||||
capnp/serialize-packed.c++ \
|
||||
|
||||
CAPNP_HEADERS=\
|
||||
capnp/arena.h \
|
||||
capnp/c++.capnp.h \
|
||||
capnp/common.h \
|
||||
capnp/blob.h \
|
||||
capnp/endian.h \
|
||||
capnp/layout.h \
|
||||
capnp/orphan.h \
|
||||
capnp/list.h \
|
||||
capnp/any.h \
|
||||
capnp/message.h \
|
||||
capnp/capability.h \
|
||||
capnp/membrane.h \
|
||||
capnp/dynamic.h \
|
||||
capnp/schema.h \
|
||||
capnp/schema.capnp.h \
|
||||
capnp/stream.capnp.h \
|
||||
capnp/schema-lite.h \
|
||||
capnp/schema-loader.h \
|
||||
capnp/schema-parser.h \
|
||||
capnp/pretty-print.h \
|
||||
capnp/serialize.h \
|
||||
capnp/serialize-async.h \
|
||||
capnp/serialize-packed.h \
|
||||
capnp/serialize-text.h \
|
||||
capnp/pointer-helpers.h \
|
||||
capnp/generated-header-support.h \
|
||||
capnp/raw-schema.h \
|
||||
capnp/compat/std-iterator.h \
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
TEMPLATE = lib
|
||||
DESTDIR = $$OUT_PWD/../../../../..
|
||||
|
||||
include($$PWD/capnp.pri)
|
||||
|
||||
TARGET = xcapnp
|
||||
SOURCES = $$CAPNP_SOURCES
|
||||
HEADERS = $$CAPNP_HEADERS
|
||||
|
||||
DEFINES += CAPNP_LITE
|
||||
INCLUDEPATH =
|
||||
LIBS =
|
||||
QT =
|
||||
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
// 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.
|
||||
|
||||
#include "any.h"
|
||||
|
||||
#include <kj/debug.h>
|
||||
|
||||
#if !CAPNP_LITE
|
||||
#include "capability.h"
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
namespace capnp {
|
||||
|
||||
#if !CAPNP_LITE
|
||||
|
||||
kj::Own<ClientHook> PipelineHook::getPipelinedCap(kj::Array<PipelineOp>&& ops) {
|
||||
return getPipelinedCap(ops.asPtr());
|
||||
}
|
||||
|
||||
kj::Own<ClientHook> AnyPointer::Reader::getPipelinedCap(
|
||||
kj::ArrayPtr<const PipelineOp> ops) const {
|
||||
_::PointerReader pointer = reader;
|
||||
|
||||
for (auto& op: ops) {
|
||||
switch (op.type) {
|
||||
case PipelineOp::Type::NOOP:
|
||||
break;
|
||||
|
||||
case PipelineOp::Type::GET_POINTER_FIELD:
|
||||
pointer = pointer.getStruct(nullptr).getPointerField(bounded(op.pointerIndex) * POINTERS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pointer.getCapability();
|
||||
}
|
||||
|
||||
AnyPointer::Pipeline AnyPointer::Pipeline::noop() {
|
||||
auto newOps = kj::heapArray<PipelineOp>(ops.size());
|
||||
for (auto i: kj::indices(ops)) {
|
||||
newOps[i] = ops[i];
|
||||
}
|
||||
return Pipeline(hook->addRef(), kj::mv(newOps));
|
||||
}
|
||||
|
||||
AnyPointer::Pipeline AnyPointer::Pipeline::getPointerField(uint16_t pointerIndex) {
|
||||
auto newOps = kj::heapArray<PipelineOp>(ops.size() + 1);
|
||||
for (auto i: kj::indices(ops)) {
|
||||
newOps[i] = ops[i];
|
||||
}
|
||||
auto& newOp = newOps[ops.size()];
|
||||
newOp.type = PipelineOp::GET_POINTER_FIELD;
|
||||
newOp.pointerIndex = pointerIndex;
|
||||
|
||||
return Pipeline(hook->addRef(), kj::mv(newOps));
|
||||
}
|
||||
|
||||
kj::Own<ClientHook> AnyPointer::Pipeline::asCap() {
|
||||
return hook->getPipelinedCap(ops);
|
||||
}
|
||||
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
Equality AnyStruct::Reader::equals(AnyStruct::Reader right) const {
|
||||
auto dataL = getDataSection();
|
||||
size_t dataSizeL = dataL.size();
|
||||
while(dataSizeL > 0 && dataL[dataSizeL - 1] == 0) {
|
||||
-- dataSizeL;
|
||||
}
|
||||
|
||||
auto dataR = right.getDataSection();
|
||||
size_t dataSizeR = dataR.size();
|
||||
while(dataSizeR > 0 && dataR[dataSizeR - 1] == 0) {
|
||||
-- dataSizeR;
|
||||
}
|
||||
|
||||
if(dataSizeL != dataSizeR) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
|
||||
if(0 != memcmp(dataL.begin(), dataR.begin(), dataSizeL)) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
|
||||
auto ptrsL = getPointerSection();
|
||||
size_t ptrsSizeL = ptrsL.size();
|
||||
while (ptrsSizeL > 0 && ptrsL[ptrsSizeL - 1].isNull()) {
|
||||
-- ptrsSizeL;
|
||||
}
|
||||
|
||||
auto ptrsR = right.getPointerSection();
|
||||
size_t ptrsSizeR = ptrsR.size();
|
||||
while (ptrsSizeR > 0 && ptrsR[ptrsSizeR - 1].isNull()) {
|
||||
-- ptrsSizeR;
|
||||
}
|
||||
|
||||
if(ptrsSizeL != ptrsSizeR) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
auto eqResult = Equality::EQUAL;
|
||||
for (; i < ptrsSizeL; i++) {
|
||||
auto l = ptrsL[i];
|
||||
auto r = ptrsR[i];
|
||||
switch(l.equals(r)) {
|
||||
case Equality::EQUAL:
|
||||
break;
|
||||
case Equality::NOT_EQUAL:
|
||||
return Equality::NOT_EQUAL;
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
|
||||
break;
|
||||
default:
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return eqResult;
|
||||
}
|
||||
|
||||
kj::StringPtr KJ_STRINGIFY(Equality res) {
|
||||
switch(res) {
|
||||
case Equality::NOT_EQUAL:
|
||||
return "NOT_EQUAL";
|
||||
case Equality::EQUAL:
|
||||
return "EQUAL";
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
return "UNKNOWN_CONTAINS_CAPS";
|
||||
}
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
Equality AnyList::Reader::equals(AnyList::Reader right) const {
|
||||
if(size() != right.size()) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
|
||||
if (getElementSize() != right.getElementSize()) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
|
||||
auto eqResult = Equality::EQUAL;
|
||||
switch(getElementSize()) {
|
||||
case ElementSize::VOID:
|
||||
case ElementSize::BIT:
|
||||
case ElementSize::BYTE:
|
||||
case ElementSize::TWO_BYTES:
|
||||
case ElementSize::FOUR_BYTES:
|
||||
case ElementSize::EIGHT_BYTES: {
|
||||
size_t cmpSize = getRawBytes().size();
|
||||
|
||||
if (getElementSize() == ElementSize::BIT && size() % 8 != 0) {
|
||||
// The list does not end on a byte boundary. We need special handling for the final
|
||||
// byte because we only care about the bits that are actually elements of the list.
|
||||
|
||||
uint8_t mask = (1 << (size() % 8)) - 1; // lowest size() bits set
|
||||
if ((getRawBytes()[cmpSize - 1] & mask) != (right.getRawBytes()[cmpSize - 1] & mask)) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
cmpSize -= 1;
|
||||
}
|
||||
|
||||
if (memcmp(getRawBytes().begin(), right.getRawBytes().begin(), cmpSize) == 0) {
|
||||
return Equality::EQUAL;
|
||||
} else {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
}
|
||||
case ElementSize::POINTER:
|
||||
case ElementSize::INLINE_COMPOSITE: {
|
||||
auto llist = as<List<AnyStruct>>();
|
||||
auto rlist = right.as<List<AnyStruct>>();
|
||||
for(size_t i = 0; i < size(); i++) {
|
||||
switch(llist[i].equals(rlist[i])) {
|
||||
case Equality::EQUAL:
|
||||
break;
|
||||
case Equality::NOT_EQUAL:
|
||||
return Equality::NOT_EQUAL;
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
eqResult = Equality::UNKNOWN_CONTAINS_CAPS;
|
||||
break;
|
||||
default:
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
return eqResult;
|
||||
}
|
||||
}
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
Equality AnyPointer::Reader::equals(AnyPointer::Reader right) const {
|
||||
if(getPointerType() != right.getPointerType()) {
|
||||
return Equality::NOT_EQUAL;
|
||||
}
|
||||
switch(getPointerType()) {
|
||||
case PointerType::NULL_:
|
||||
return Equality::EQUAL;
|
||||
case PointerType::STRUCT:
|
||||
return getAs<AnyStruct>().equals(right.getAs<AnyStruct>());
|
||||
case PointerType::LIST:
|
||||
return getAs<AnyList>().equals(right.getAs<AnyList>());
|
||||
case PointerType::CAPABILITY:
|
||||
return Equality::UNKNOWN_CONTAINS_CAPS;
|
||||
}
|
||||
// There aren't currently any other types of pointers
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
bool AnyPointer::Reader::operator==(AnyPointer::Reader right) const {
|
||||
switch(equals(right)) {
|
||||
case Equality::EQUAL:
|
||||
return true;
|
||||
case Equality::NOT_EQUAL:
|
||||
return false;
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
KJ_FAIL_REQUIRE(
|
||||
"operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
|
||||
}
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
bool AnyStruct::Reader::operator==(AnyStruct::Reader right) const {
|
||||
switch(equals(right)) {
|
||||
case Equality::EQUAL:
|
||||
return true;
|
||||
case Equality::NOT_EQUAL:
|
||||
return false;
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
KJ_FAIL_REQUIRE(
|
||||
"operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
|
||||
}
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
bool AnyList::Reader::operator==(AnyList::Reader right) const {
|
||||
switch(equals(right)) {
|
||||
case Equality::EQUAL:
|
||||
return true;
|
||||
case Equality::NOT_EQUAL:
|
||||
return false;
|
||||
case Equality::UNKNOWN_CONTAINS_CAPS:
|
||||
KJ_FAIL_REQUIRE(
|
||||
"operator== cannot determine equality of capabilities; use equals() instead if you need to handle this case");
|
||||
}
|
||||
KJ_UNREACHABLE;
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,392 @@
|
|||
// 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.
|
||||
|
||||
#define CAPNP_PRIVATE
|
||||
#include "arena.h"
|
||||
#include "message.h"
|
||||
#include <kj/debug.h>
|
||||
#include <kj/refcount.h>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !CAPNP_LITE
|
||||
#include "capability.h"
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
namespace capnp {
|
||||
namespace _ { // private
|
||||
|
||||
Arena::~Arena() noexcept(false) {}
|
||||
|
||||
void ReadLimiter::unread(WordCount64 amount) {
|
||||
// Be careful not to overflow here. Since ReadLimiter has no thread-safety, it's possible that
|
||||
// the limit value was not updated correctly for one or more reads, and therefore unread() could
|
||||
// overflow it even if it is only unreading bytes that were actually read.
|
||||
uint64_t oldValue = readLimit();
|
||||
uint64_t newValue = oldValue + unbound(amount / WORDS);
|
||||
if (newValue > oldValue) {
|
||||
setLimit(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentReader::abortCheckObjectFault() {
|
||||
KJ_LOG(FATAL, "checkObject()'s parameter is not in-range; this would segfault in opt mode",
|
||||
"this is a serious bug in Cap'n Proto; please notify security@sandstorm.io");
|
||||
abort();
|
||||
}
|
||||
|
||||
void SegmentBuilder::throwNotWritable() {
|
||||
KJ_FAIL_REQUIRE(
|
||||
"Tried to form a Builder to an external data segment referenced by the MessageBuilder. "
|
||||
"When you use Orphanage::reference*(), you are not allowed to obtain Builders to the "
|
||||
"referenced data, only Readers, because that data is const.");
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
static SegmentWordCount verifySegmentSize(size_t size) {
|
||||
auto gsize = bounded(size) * WORDS;
|
||||
return assertMaxBits<SEGMENT_WORD_COUNT_BITS>(gsize, [&]() {
|
||||
KJ_FAIL_REQUIRE("segment is too large", size);
|
||||
});
|
||||
}
|
||||
|
||||
static SegmentWordCount verifySegment(kj::ArrayPtr<const word> segment) {
|
||||
#if !CAPNP_ALLOW_UNALIGNED
|
||||
KJ_REQUIRE(reinterpret_cast<uintptr_t>(segment.begin()) % sizeof(void*) == 0,
|
||||
"Detected unaligned data in Cap'n Proto message. Messages must be aligned to the "
|
||||
"architecture's word size. Yes, even on x86: Unaligned access is undefined behavior "
|
||||
"under the C/C++ language standard, and compilers can and do assume alignment for the "
|
||||
"purpose of optimizations. Unaligned access may lead to crashes or subtle corruption. "
|
||||
"For example, GCC will use SIMD instructions in optimizations, and those instrsuctions "
|
||||
"require alignment. If you really insist on taking your changes with unaligned data, "
|
||||
"compile the Cap'n Proto library with -DCAPNP_ALLOW_UNALIGNED to remove this check.") {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return verifySegmentSize(segment.size());
|
||||
}
|
||||
|
||||
inline ReaderArena::ReaderArena(MessageReader* message, const word* firstSegment,
|
||||
SegmentWordCount firstSegmentSize)
|
||||
: message(message),
|
||||
readLimiter(bounded(message->getOptions().traversalLimitInWords) * WORDS),
|
||||
segment0(this, SegmentId(0), firstSegment, firstSegmentSize, &readLimiter) {}
|
||||
|
||||
inline ReaderArena::ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment)
|
||||
: ReaderArena(message, firstSegment.begin(), verifySegment(firstSegment)) {}
|
||||
|
||||
ReaderArena::ReaderArena(MessageReader* message)
|
||||
: ReaderArena(message, message->getSegment(0)) {}
|
||||
|
||||
ReaderArena::~ReaderArena() noexcept(false) {}
|
||||
|
||||
size_t ReaderArena::sizeInWords() {
|
||||
size_t total = segment0.getArray().size();
|
||||
|
||||
for (uint i = 1; ; i++) {
|
||||
SegmentReader* segment = tryGetSegment(SegmentId(i));
|
||||
if (segment == nullptr) return total;
|
||||
total += unboundAs<size_t>(segment->getSize() / WORDS);
|
||||
}
|
||||
}
|
||||
|
||||
SegmentReader* ReaderArena::tryGetSegment(SegmentId id) {
|
||||
if (id == SegmentId(0)) {
|
||||
if (segment0.getArray() == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return &segment0;
|
||||
}
|
||||
}
|
||||
|
||||
auto lock = moreSegments.lockExclusive();
|
||||
|
||||
SegmentMap* segments = nullptr;
|
||||
KJ_IF_MAYBE(s, *lock) {
|
||||
KJ_IF_MAYBE(segment, s->find(id.value)) {
|
||||
return *segment;
|
||||
}
|
||||
segments = s;
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const word> newSegment = message->getSegment(id.value);
|
||||
if (newSegment == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SegmentWordCount newSegmentSize = verifySegment(newSegment);
|
||||
|
||||
if (*lock == nullptr) {
|
||||
// OK, the segment exists, so allocate the map.
|
||||
segments = &lock->emplace();
|
||||
}
|
||||
|
||||
auto segment = kj::heap<SegmentReader>(
|
||||
this, id, newSegment.begin(), newSegmentSize, &readLimiter);
|
||||
SegmentReader* result = segment;
|
||||
segments->insert(id.value, kj::mv(segment));
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReaderArena::reportReadLimitReached() {
|
||||
KJ_FAIL_REQUIRE("Exceeded message traversal limit. See capnp::ReaderOptions.") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
BuilderArena::BuilderArena(MessageBuilder* message)
|
||||
: message(message), segment0(nullptr, SegmentId(0), nullptr, nullptr) {}
|
||||
|
||||
BuilderArena::BuilderArena(MessageBuilder* message,
|
||||
kj::ArrayPtr<MessageBuilder::SegmentInit> segments)
|
||||
: message(message),
|
||||
segment0(this, SegmentId(0), segments[0].space.begin(),
|
||||
verifySegment(segments[0].space),
|
||||
&this->dummyLimiter, verifySegmentSize(segments[0].wordsUsed)) {
|
||||
if (segments.size() > 1) {
|
||||
kj::Vector<kj::Own<SegmentBuilder>> builders(segments.size() - 1);
|
||||
|
||||
uint i = 1;
|
||||
for (auto& segment: segments.slice(1, segments.size())) {
|
||||
builders.add(kj::heap<SegmentBuilder>(
|
||||
this, SegmentId(i++), segment.space.begin(), verifySegment(segment.space),
|
||||
&this->dummyLimiter, verifySegmentSize(segment.wordsUsed)));
|
||||
}
|
||||
|
||||
kj::Vector<kj::ArrayPtr<const word>> forOutput;
|
||||
forOutput.resize(segments.size());
|
||||
|
||||
segmentWithSpace = builders.back();
|
||||
|
||||
this->moreSegments = kj::heap<MultiSegmentState>(
|
||||
MultiSegmentState { kj::mv(builders), kj::mv(forOutput) });
|
||||
|
||||
} else {
|
||||
segmentWithSpace = &segment0;
|
||||
}
|
||||
}
|
||||
|
||||
BuilderArena::~BuilderArena() noexcept(false) {}
|
||||
|
||||
size_t BuilderArena::sizeInWords() {
|
||||
KJ_IF_MAYBE(segmentState, moreSegments) {
|
||||
size_t total = segment0.currentlyAllocated().size();
|
||||
for (auto& builder: segmentState->get()->builders) {
|
||||
total += builder->currentlyAllocated().size();
|
||||
}
|
||||
return total;
|
||||
} else {
|
||||
if (segment0.getArena() == nullptr) {
|
||||
// We haven't actually allocated any segments yet.
|
||||
return 0;
|
||||
} else {
|
||||
// We have only one segment so far.
|
||||
return segment0.currentlyAllocated().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SegmentBuilder* BuilderArena::getSegment(SegmentId id) {
|
||||
// This method is allowed to fail if the segment ID is not valid.
|
||||
if (id == SegmentId(0)) {
|
||||
return &segment0;
|
||||
} else {
|
||||
KJ_IF_MAYBE(s, moreSegments) {
|
||||
KJ_REQUIRE(id.value - 1 < s->get()->builders.size(), "invalid segment id", id.value);
|
||||
return const_cast<SegmentBuilder*>(s->get()->builders[id.value - 1].get());
|
||||
} else {
|
||||
KJ_FAIL_REQUIRE("invalid segment id", id.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuilderArena::AllocateResult BuilderArena::allocate(SegmentWordCount amount) {
|
||||
if (segment0.getArena() == nullptr) {
|
||||
// We're allocating the first segment.
|
||||
kj::ArrayPtr<word> ptr = message->allocateSegment(unbound(amount / WORDS));
|
||||
auto actualSize = verifySegment(ptr);
|
||||
|
||||
// Re-allocate segment0 in-place. This is a bit of a hack, but we have not returned any
|
||||
// pointers to this segment yet, so it should be fine.
|
||||
kj::dtor(segment0);
|
||||
kj::ctor(segment0, this, SegmentId(0), ptr.begin(), actualSize, &this->dummyLimiter);
|
||||
|
||||
segmentWithSpace = &segment0;
|
||||
return AllocateResult { &segment0, segment0.allocate(amount) };
|
||||
} else {
|
||||
if (segmentWithSpace != nullptr) {
|
||||
// Check if there is space in an existing segment.
|
||||
// TODO(perf): Check for available space in more than just the last segment. We don't
|
||||
// want this to be O(n), though, so we'll need to maintain some sort of table. Complicating
|
||||
// matters, we want SegmentBuilders::allocate() to be fast, so we can't update any such
|
||||
// table when allocation actually happens. Instead, we could have a priority queue based
|
||||
// on the last-known available size, and then re-check the size when we pop segments off it
|
||||
// and shove them to the back of the queue if they have become too small.
|
||||
word* attempt = segmentWithSpace->allocate(amount);
|
||||
if (attempt != nullptr) {
|
||||
return AllocateResult { segmentWithSpace, attempt };
|
||||
}
|
||||
}
|
||||
|
||||
// Need to allocate a new segment.
|
||||
SegmentBuilder* result = addSegmentInternal(message->allocateSegment(unbound(amount / WORDS)));
|
||||
|
||||
// Check this new segment first the next time we need to allocate.
|
||||
segmentWithSpace = result;
|
||||
|
||||
// Allocating from the new segment is guaranteed to succeed since we made it big enough.
|
||||
return AllocateResult { result, result->allocate(amount) };
|
||||
}
|
||||
}
|
||||
|
||||
SegmentBuilder* BuilderArena::addExternalSegment(kj::ArrayPtr<const word> content) {
|
||||
return addSegmentInternal(content);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SegmentBuilder* BuilderArena::addSegmentInternal(kj::ArrayPtr<T> content) {
|
||||
// This check should never fail in practice, since you can't get an Orphanage without allocating
|
||||
// the root segment.
|
||||
KJ_REQUIRE(segment0.getArena() != nullptr,
|
||||
"Can't allocate external segments before allocating the root segment.");
|
||||
|
||||
auto contentSize = verifySegmentSize(content.size());
|
||||
|
||||
MultiSegmentState* segmentState;
|
||||
KJ_IF_MAYBE(s, moreSegments) {
|
||||
segmentState = *s;
|
||||
} else {
|
||||
auto newSegmentState = kj::heap<MultiSegmentState>();
|
||||
segmentState = newSegmentState;
|
||||
moreSegments = kj::mv(newSegmentState);
|
||||
}
|
||||
|
||||
kj::Own<SegmentBuilder> newBuilder = kj::heap<SegmentBuilder>(
|
||||
this, SegmentId(segmentState->builders.size() + 1),
|
||||
content.begin(), contentSize, &this->dummyLimiter);
|
||||
SegmentBuilder* result = newBuilder.get();
|
||||
segmentState->builders.add(kj::mv(newBuilder));
|
||||
|
||||
// Keep forOutput the right size so that we don't have to re-allocate during
|
||||
// getSegmentsForOutput(), which callers might reasonably expect is a thread-safe method.
|
||||
segmentState->forOutput.resize(segmentState->builders.size() + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> BuilderArena::getSegmentsForOutput() {
|
||||
// Although this is a read-only method, we shouldn't need to lock a mutex here because if this
|
||||
// is called multiple times simultaneously, we should only be overwriting the array with the
|
||||
// exact same data. If the number or size of segments is actually changing due to an activity
|
||||
// in another thread, then the caller has a problem regardless of locking here.
|
||||
|
||||
KJ_IF_MAYBE(segmentState, moreSegments) {
|
||||
KJ_DASSERT(segmentState->get()->forOutput.size() == segmentState->get()->builders.size() + 1,
|
||||
"segmentState->forOutput wasn't resized correctly when the last builder was added.",
|
||||
segmentState->get()->forOutput.size(), segmentState->get()->builders.size());
|
||||
|
||||
kj::ArrayPtr<kj::ArrayPtr<const word>> result(
|
||||
&segmentState->get()->forOutput[0], segmentState->get()->forOutput.size());
|
||||
uint i = 0;
|
||||
result[i++] = segment0.currentlyAllocated();
|
||||
for (auto& builder: segmentState->get()->builders) {
|
||||
result[i++] = builder->currentlyAllocated();
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if (segment0.getArena() == nullptr) {
|
||||
// We haven't actually allocated any segments yet.
|
||||
return nullptr;
|
||||
} else {
|
||||
// We have only one segment so far.
|
||||
segment0ForOutput = segment0.currentlyAllocated();
|
||||
return kj::arrayPtr(&segment0ForOutput, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SegmentReader* BuilderArena::tryGetSegment(SegmentId id) {
|
||||
if (id == SegmentId(0)) {
|
||||
if (segment0.getArena() == nullptr) {
|
||||
// We haven't allocated any segments yet.
|
||||
return nullptr;
|
||||
} else {
|
||||
return &segment0;
|
||||
}
|
||||
} else {
|
||||
KJ_IF_MAYBE(segmentState, moreSegments) {
|
||||
if (id.value <= segmentState->get()->builders.size()) {
|
||||
// TODO(cleanup): Return a const SegmentReader and tediously constify all SegmentBuilder
|
||||
// pointers throughout the codebase.
|
||||
return const_cast<SegmentReader*>(kj::implicitCast<const SegmentReader*>(
|
||||
segmentState->get()->builders[id.value - 1].get()));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BuilderArena::reportReadLimitReached() {
|
||||
KJ_FAIL_ASSERT("Read limit reached for BuilderArena, but it should have been unlimited.") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
kj::Maybe<kj::Own<ClientHook>> BuilderArena::LocalCapTable::extractCap(uint index) {
|
||||
#if CAPNP_LITE
|
||||
KJ_UNIMPLEMENTED("no cap tables in lite mode");
|
||||
#else
|
||||
if (index < capTable.size()) {
|
||||
return capTable[index].map([](kj::Own<ClientHook>& cap) { return cap->addRef(); });
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint BuilderArena::LocalCapTable::injectCap(kj::Own<ClientHook>&& cap) {
|
||||
#if CAPNP_LITE
|
||||
KJ_UNIMPLEMENTED("no cap tables in lite mode");
|
||||
#else
|
||||
uint result = capTable.size();
|
||||
capTable.add(kj::mv(cap));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BuilderArena::LocalCapTable::dropCap(uint index) {
|
||||
#if CAPNP_LITE
|
||||
KJ_UNIMPLEMENTED("no cap tables in lite mode");
|
||||
#else
|
||||
KJ_ASSERT(index < capTable.size(), "Invalid capability descriptor in message.") {
|
||||
return;
|
||||
}
|
||||
capTable[index] = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,523 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CAPNP_PRIVATE
|
||||
#error "This header is only meant to be included by Cap'n Proto's own source code."
|
||||
#endif
|
||||
|
||||
#include <kj/common.h>
|
||||
#include <kj/mutex.h>
|
||||
#include <kj/exception.h>
|
||||
#include <kj/vector.h>
|
||||
#include <kj/units.h>
|
||||
#include "common.h"
|
||||
#include "message.h"
|
||||
#include "layout.h"
|
||||
#include <kj/map.h>
|
||||
|
||||
#if !CAPNP_LITE
|
||||
#include "capability.h"
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class ClientHook;
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class SegmentReader;
|
||||
class SegmentBuilder;
|
||||
class Arena;
|
||||
class BuilderArena;
|
||||
class ReadLimiter;
|
||||
|
||||
class Segment;
|
||||
typedef kj::Id<uint32_t, Segment> SegmentId;
|
||||
|
||||
class ReadLimiter {
|
||||
// Used to keep track of how much data has been processed from a message, and cut off further
|
||||
// processing if and when a particular limit is reached. This is primarily intended to guard
|
||||
// against maliciously-crafted messages which contain cycles or overlapping structures. Cycles
|
||||
// and overlapping are not permitted by the Cap'n Proto format because in many cases they could
|
||||
// be used to craft a deceptively small message which could consume excessive server resources to
|
||||
// process, perhaps even sending it into an infinite loop. Actually detecting overlaps would be
|
||||
// time-consuming, so instead we just keep track of how many words worth of data structures the
|
||||
// receiver has actually dereferenced and error out if this gets too high.
|
||||
//
|
||||
// This counting takes place as you call getters (for non-primitive values) on the message
|
||||
// readers. If you call the same getter twice, the data it returns may be double-counted. This
|
||||
// should not be a big deal in most cases -- just set the read limit high enough that it will
|
||||
// only trigger in unreasonable cases.
|
||||
//
|
||||
// This class is "safe" to use from multiple threads for its intended use case. Threads may
|
||||
// overwrite each others' changes to the counter, but this is OK because it only means that the
|
||||
// limit is enforced a bit less strictly -- it will still kick in eventually.
|
||||
|
||||
public:
|
||||
inline explicit ReadLimiter(); // No limit.
|
||||
inline explicit ReadLimiter(WordCount64 limit); // Limit to the given number of words.
|
||||
|
||||
inline void reset(WordCount64 limit);
|
||||
|
||||
KJ_ALWAYS_INLINE(bool canRead(WordCount64 amount, Arena* arena));
|
||||
|
||||
void unread(WordCount64 amount);
|
||||
// Adds back some words to the limit. Useful when the caller knows they are double-reading
|
||||
// some data.
|
||||
|
||||
private:
|
||||
alignas(8) volatile uint64_t limit;
|
||||
// Current limit, decremented each time catRead() is called. We modify this variable using atomics
|
||||
// with "relaxed" thread safety to make TSAN happy (on ARM & x86 this is no different from a
|
||||
// regular read/write of the variable). See the class comment for why this is OK (previously we
|
||||
// used a regular volatile variable - this is just to make ASAN happy).
|
||||
//
|
||||
// alignas(8) is the default on 64-bit systems, but needed on 32-bit to avoid an expensive
|
||||
// unaligned atomic operation.
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ReadLimiter);
|
||||
|
||||
KJ_ALWAYS_INLINE(void setLimit(uint64_t newLimit)) {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
__atomic_store_n(&limit, newLimit, __ATOMIC_RELAXED);
|
||||
#else
|
||||
limit = newLimit;
|
||||
#endif
|
||||
}
|
||||
|
||||
KJ_ALWAYS_INLINE(uint64_t readLimit() const) {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __atomic_load_n(&limit, __ATOMIC_RELAXED);
|
||||
#else
|
||||
return limit;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class BrokenCapFactory {
|
||||
// Callback for constructing broken caps. We use this so that we can avoid arena.c++ having a
|
||||
// link-time dependency on capability code that lives in libcapnp-rpc.
|
||||
|
||||
public:
|
||||
virtual kj::Own<ClientHook> newBrokenCap(kj::StringPtr description) = 0;
|
||||
virtual kj::Own<ClientHook> newNullCap() = 0;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class SegmentReader {
|
||||
public:
|
||||
inline SegmentReader(Arena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
|
||||
ReadLimiter* readLimiter);
|
||||
|
||||
KJ_ALWAYS_INLINE(const word* checkOffset(const word* from, ptrdiff_t offset));
|
||||
// Adds the given offset to the given pointer, checks that it is still within the bounds of the
|
||||
// segment, then returns it. Note that the "end" pointer of the segment (which technically points
|
||||
// to the word after the last in the segment) is considered in-bounds for this purpose, so you
|
||||
// can't necessarily dereference it. You must call checkObject() next to check that the object
|
||||
// you want to read is entirely in-bounds.
|
||||
//
|
||||
// If `from + offset` is out-of-range, this returns a pointer to the end of the segment. Thus,
|
||||
// any non-zero-sized object will fail `checkObject()`. We do this instead of throwing to save
|
||||
// some code footprint.
|
||||
|
||||
KJ_ALWAYS_INLINE(bool checkObject(const word* start, WordCountN<31> size));
|
||||
// Assuming that `start` is in-bounds for this segment (probably checked using `checkOffset()`),
|
||||
// check that `start + size` is also in-bounds, and hence the whole area in-between is valid.
|
||||
|
||||
KJ_ALWAYS_INLINE(bool amplifiedRead(WordCount virtualAmount));
|
||||
// Indicates that the reader should pretend that `virtualAmount` additional data was read even
|
||||
// though no actual pointer was traversed. This is used e.g. when reading a struct list pointer
|
||||
// where the element sizes are zero -- the sender could set the list size arbitrarily high and
|
||||
// cause the receiver to iterate over this list even though the message itself is small, so we
|
||||
// need to defend against DoS attacks based on this.
|
||||
|
||||
inline Arena* getArena();
|
||||
inline SegmentId getSegmentId();
|
||||
|
||||
inline const word* getStartPtr();
|
||||
inline SegmentWordCount getOffsetTo(const word* ptr);
|
||||
inline SegmentWordCount getSize();
|
||||
|
||||
inline kj::ArrayPtr<const word> getArray();
|
||||
|
||||
inline void unread(WordCount64 amount);
|
||||
// Add back some words to the ReadLimiter.
|
||||
|
||||
private:
|
||||
Arena* arena;
|
||||
SegmentId id;
|
||||
kj::ArrayPtr<const word> ptr; // size guaranteed to fit in SEGMENT_WORD_COUNT_BITS bits
|
||||
ReadLimiter* readLimiter;
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(SegmentReader);
|
||||
|
||||
friend class SegmentBuilder;
|
||||
|
||||
[[noreturn]] static void abortCheckObjectFault();
|
||||
// Called in debug mode in cases that would segfault in opt mode. (Should be impossible!)
|
||||
};
|
||||
|
||||
class SegmentBuilder: public SegmentReader {
|
||||
public:
|
||||
inline SegmentBuilder(BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
|
||||
ReadLimiter* readLimiter, SegmentWordCount wordsUsed = ZERO * WORDS);
|
||||
inline SegmentBuilder(BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
|
||||
ReadLimiter* readLimiter);
|
||||
inline SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
|
||||
ReadLimiter* readLimiter);
|
||||
|
||||
KJ_ALWAYS_INLINE(word* allocate(SegmentWordCount amount));
|
||||
|
||||
KJ_ALWAYS_INLINE(void checkWritable());
|
||||
// Throw an exception if the segment is read-only (meaning it is a reference to external data).
|
||||
|
||||
KJ_ALWAYS_INLINE(word* getPtrUnchecked(SegmentWordCount offset));
|
||||
// Get a writable pointer into the segment. Throws an exception if the segment is read-only (i.e.
|
||||
// a reference to external immutable data).
|
||||
|
||||
inline BuilderArena* getArena();
|
||||
|
||||
inline kj::ArrayPtr<const word> currentlyAllocated();
|
||||
|
||||
inline void reset();
|
||||
|
||||
inline bool isWritable() { return !readOnly; }
|
||||
|
||||
inline void tryTruncate(word* from, word* to);
|
||||
// If `from` points just past the current end of the segment, then move the end back to `to`.
|
||||
// Otherwise, do nothing.
|
||||
|
||||
inline bool tryExtend(word* from, word* to);
|
||||
// If `from` points just past the current end of the segment, and `to` is within the segment
|
||||
// boundaries, then move the end up to `to` and return true. Otherwise, do nothing and return
|
||||
// false.
|
||||
|
||||
private:
|
||||
word* pos;
|
||||
// Pointer to a pointer to the current end point of the segment, i.e. the location where the
|
||||
// next object should be allocated.
|
||||
|
||||
bool readOnly;
|
||||
|
||||
[[noreturn]] void throwNotWritable();
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(SegmentBuilder);
|
||||
};
|
||||
|
||||
class Arena {
|
||||
public:
|
||||
virtual ~Arena() noexcept(false);
|
||||
|
||||
virtual SegmentReader* tryGetSegment(SegmentId id) = 0;
|
||||
// Gets the segment with the given ID, or return nullptr if no such segment exists.
|
||||
|
||||
virtual void reportReadLimitReached() = 0;
|
||||
// Called to report that the read limit has been reached. See ReadLimiter, below. This invokes
|
||||
// the VALIDATE_INPUT() macro which may throw an exception; if it returns normally, the caller
|
||||
// will need to continue with default values.
|
||||
};
|
||||
|
||||
class ReaderArena final: public Arena {
|
||||
public:
|
||||
explicit ReaderArena(MessageReader* message);
|
||||
~ReaderArena() noexcept(false);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ReaderArena);
|
||||
|
||||
size_t sizeInWords();
|
||||
|
||||
// implements Arena ------------------------------------------------
|
||||
SegmentReader* tryGetSegment(SegmentId id) override;
|
||||
void reportReadLimitReached() override;
|
||||
|
||||
private:
|
||||
MessageReader* message;
|
||||
ReadLimiter readLimiter;
|
||||
|
||||
// Optimize for single-segment messages so that small messages are handled quickly.
|
||||
SegmentReader segment0;
|
||||
|
||||
typedef kj::HashMap<uint, kj::Own<SegmentReader>> SegmentMap;
|
||||
kj::MutexGuarded<kj::Maybe<SegmentMap>> moreSegments;
|
||||
// We need to mutex-guard the segment map because we lazily initialize segments when they are
|
||||
// first requested, but a Reader is allowed to be used concurrently in multiple threads. Luckily
|
||||
// this only applies to large messages.
|
||||
//
|
||||
// TODO(perf): Thread-local thing instead? Some kind of lockless map? Or do sharing of data
|
||||
// in a different way, where you have to construct a new MessageReader in each thread (but
|
||||
// possibly backed by the same data)?
|
||||
|
||||
ReaderArena(MessageReader* message, kj::ArrayPtr<const word> firstSegment);
|
||||
ReaderArena(MessageReader* message, const word* firstSegment, SegmentWordCount firstSegmentSize);
|
||||
};
|
||||
|
||||
class BuilderArena final: public Arena {
|
||||
// A BuilderArena that does not allow the injection of capabilities.
|
||||
|
||||
public:
|
||||
explicit BuilderArena(MessageBuilder* message);
|
||||
BuilderArena(MessageBuilder* message, kj::ArrayPtr<MessageBuilder::SegmentInit> segments);
|
||||
~BuilderArena() noexcept(false);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(BuilderArena);
|
||||
|
||||
size_t sizeInWords();
|
||||
|
||||
inline SegmentBuilder* getRootSegment() { return &segment0; }
|
||||
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> getSegmentsForOutput();
|
||||
// Get an array of all the segments, suitable for writing out. This only returns the allocated
|
||||
// portion of each segment, whereas tryGetSegment() returns something that includes
|
||||
// not-yet-allocated space.
|
||||
|
||||
inline CapTableBuilder* getLocalCapTable() {
|
||||
// Return a CapTableBuilder that merely implements local loopback. That is, you can set
|
||||
// capabilities, then read the same capabilities back, but there is no intent ever to transmit
|
||||
// these capabilities. A MessageBuilder that isn't imbued with some other CapTable uses this
|
||||
// by default.
|
||||
//
|
||||
// TODO(cleanup): It's sort of a hack that this exists. In theory, perhaps, unimbued
|
||||
// MessageBuilders should throw exceptions on any attempt to access capability fields, like
|
||||
// unimbued MessageReaders do. However, lots of code exists which uses MallocMessageBuilder
|
||||
// as a temporary holder for data to be copied in and out (without being serialized), and it
|
||||
// is expected that such data can include capabilities, which is admittedly reasonable.
|
||||
// Therefore, all MessageBuilders must have a cap table by default. Arguably we should
|
||||
// deprecate this usage and instead define a new helper type for this exact purpose.
|
||||
|
||||
return &localCapTable;
|
||||
}
|
||||
|
||||
kj::Own<_::CapTableBuilder> releaseLocalCapTable() {
|
||||
return kj::heap<LocalCapTable>(kj::mv(localCapTable));
|
||||
}
|
||||
|
||||
SegmentBuilder* getSegment(SegmentId id);
|
||||
// Get the segment with the given id. Crashes or throws an exception if no such segment exists.
|
||||
|
||||
struct AllocateResult {
|
||||
SegmentBuilder* segment;
|
||||
word* words;
|
||||
};
|
||||
|
||||
AllocateResult allocate(SegmentWordCount amount);
|
||||
// Find a segment with at least the given amount of space available and allocate the space.
|
||||
// Note that allocating directly from a particular segment is much faster, but allocating from
|
||||
// the arena is guaranteed to succeed. Therefore callers should try to allocate from a specific
|
||||
// segment first if there is one, then fall back to the arena.
|
||||
|
||||
SegmentBuilder* addExternalSegment(kj::ArrayPtr<const word> content);
|
||||
// Add a new segment to the arena which points to some existing memory region. The segment is
|
||||
// assumed to be completley full; the arena will never allocate from it. In fact, the segment
|
||||
// is considered read-only. Any attempt to get a Builder pointing into this segment will throw
|
||||
// an exception. Readers are allowed, however.
|
||||
//
|
||||
// This can be used to inject some external data into a message without a copy, e.g. embedding a
|
||||
// large mmap'd file into a message as `Data` without forcing that data to actually be read in
|
||||
// from disk (until the message itself is written out). `Orphanage` provides the public API for
|
||||
// this feature.
|
||||
|
||||
// implements Arena ------------------------------------------------
|
||||
SegmentReader* tryGetSegment(SegmentId id) override;
|
||||
void reportReadLimitReached() override;
|
||||
|
||||
private:
|
||||
MessageBuilder* message;
|
||||
ReadLimiter dummyLimiter;
|
||||
|
||||
class LocalCapTable final: public CapTableBuilder {
|
||||
public:
|
||||
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
|
||||
uint injectCap(kj::Own<ClientHook>&& cap) override;
|
||||
void dropCap(uint index) override;
|
||||
|
||||
#if !CAPNP_LITE
|
||||
private:
|
||||
kj::Vector<kj::Maybe<kj::Own<ClientHook>>> capTable;
|
||||
#endif // ! CAPNP_LITE
|
||||
};
|
||||
|
||||
LocalCapTable localCapTable;
|
||||
|
||||
SegmentBuilder segment0;
|
||||
kj::ArrayPtr<const word> segment0ForOutput;
|
||||
|
||||
struct MultiSegmentState {
|
||||
kj::Vector<kj::Own<SegmentBuilder>> builders;
|
||||
kj::Vector<kj::ArrayPtr<const word>> forOutput;
|
||||
};
|
||||
kj::Maybe<kj::Own<MultiSegmentState>> moreSegments;
|
||||
|
||||
SegmentBuilder* segmentWithSpace = nullptr;
|
||||
// When allocating, look for space in this segment first before resorting to allocating a new
|
||||
// segment. This is not necessarily the last segment because addExternalSegment() may add a
|
||||
// segment that is already-full, in which case we don't update this pointer.
|
||||
|
||||
template <typename T> // Can be `word` or `const word`.
|
||||
SegmentBuilder* addSegmentInternal(kj::ArrayPtr<T> content);
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
inline ReadLimiter::ReadLimiter()
|
||||
: limit(kj::maxValue) {}
|
||||
|
||||
inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(unbound(limit / WORDS)) {}
|
||||
|
||||
inline void ReadLimiter::reset(WordCount64 limit) {
|
||||
setLimit(unbound(limit / WORDS));
|
||||
}
|
||||
|
||||
inline bool ReadLimiter::canRead(WordCount64 amount, Arena* arena) {
|
||||
// Be careful not to store an underflowed value into `limit`, even if multiple threads are
|
||||
// decrementing it.
|
||||
uint64_t current = readLimit();
|
||||
if (KJ_UNLIKELY(unbound(amount / WORDS) > current)) {
|
||||
arena->reportReadLimitReached();
|
||||
return false;
|
||||
} else {
|
||||
setLimit(current - unbound(amount / WORDS));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
inline SegmentReader::SegmentReader(Arena* arena, SegmentId id, const word* ptr,
|
||||
SegmentWordCount size, ReadLimiter* readLimiter)
|
||||
: arena(arena), id(id), ptr(kj::arrayPtr(ptr, unbound(size / WORDS))),
|
||||
readLimiter(readLimiter) {}
|
||||
|
||||
inline const word* SegmentReader::checkOffset(const word* from, ptrdiff_t offset) {
|
||||
ptrdiff_t min = ptr.begin() - from;
|
||||
ptrdiff_t max = ptr.end() - from;
|
||||
if (offset >= min && offset <= max) {
|
||||
return from + offset;
|
||||
} else {
|
||||
return ptr.end();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SegmentReader::checkObject(const word* start, WordCountN<31> size) {
|
||||
auto startOffset = intervalLength(ptr.begin(), start, MAX_SEGMENT_WORDS);
|
||||
#ifdef KJ_DEBUG
|
||||
if (startOffset > bounded(ptr.size()) * WORDS) {
|
||||
abortCheckObjectFault();
|
||||
}
|
||||
#endif
|
||||
return startOffset + size <= bounded(ptr.size()) * WORDS &&
|
||||
readLimiter->canRead(size, arena);
|
||||
}
|
||||
|
||||
inline bool SegmentReader::amplifiedRead(WordCount virtualAmount) {
|
||||
return readLimiter->canRead(virtualAmount, arena);
|
||||
}
|
||||
|
||||
inline Arena* SegmentReader::getArena() { return arena; }
|
||||
inline SegmentId SegmentReader::getSegmentId() { return id; }
|
||||
inline const word* SegmentReader::getStartPtr() { return ptr.begin(); }
|
||||
inline SegmentWordCount SegmentReader::getOffsetTo(const word* ptr) {
|
||||
KJ_IREQUIRE(this->ptr.begin() <= ptr && ptr <= this->ptr.end());
|
||||
return intervalLength(this->ptr.begin(), ptr, MAX_SEGMENT_WORDS);
|
||||
}
|
||||
inline SegmentWordCount SegmentReader::getSize() {
|
||||
return assumeBits<SEGMENT_WORD_COUNT_BITS>(ptr.size()) * WORDS;
|
||||
}
|
||||
inline kj::ArrayPtr<const word> SegmentReader::getArray() { return ptr; }
|
||||
inline void SegmentReader::unread(WordCount64 amount) { readLimiter->unread(amount); }
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
inline SegmentBuilder::SegmentBuilder(
|
||||
BuilderArena* arena, SegmentId id, word* ptr, SegmentWordCount size,
|
||||
ReadLimiter* readLimiter, SegmentWordCount wordsUsed)
|
||||
: SegmentReader(arena, id, ptr, size, readLimiter),
|
||||
pos(ptr + wordsUsed), readOnly(false) {}
|
||||
inline SegmentBuilder::SegmentBuilder(
|
||||
BuilderArena* arena, SegmentId id, const word* ptr, SegmentWordCount size,
|
||||
ReadLimiter* readLimiter)
|
||||
: SegmentReader(arena, id, ptr, size, readLimiter),
|
||||
// const_cast is safe here because the member won't ever be dereferenced because it appears
|
||||
// to point to the end of the segment anyway.
|
||||
pos(const_cast<word*>(ptr + size)), readOnly(true) {}
|
||||
inline SegmentBuilder::SegmentBuilder(BuilderArena* arena, SegmentId id, decltype(nullptr),
|
||||
ReadLimiter* readLimiter)
|
||||
: SegmentReader(arena, id, nullptr, ZERO * WORDS, readLimiter),
|
||||
pos(nullptr), readOnly(false) {}
|
||||
|
||||
inline word* SegmentBuilder::allocate(SegmentWordCount amount) {
|
||||
if (intervalLength(pos, ptr.end(), MAX_SEGMENT_WORDS) < amount) {
|
||||
// Not enough space in the segment for this allocation.
|
||||
return nullptr;
|
||||
} else {
|
||||
// Success.
|
||||
word* result = pos;
|
||||
pos = pos + amount;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SegmentBuilder::checkWritable() {
|
||||
if (KJ_UNLIKELY(readOnly)) throwNotWritable();
|
||||
}
|
||||
|
||||
inline word* SegmentBuilder::getPtrUnchecked(SegmentWordCount offset) {
|
||||
return const_cast<word*>(ptr.begin() + offset);
|
||||
}
|
||||
|
||||
inline BuilderArena* SegmentBuilder::getArena() {
|
||||
// Down-cast safe because SegmentBuilder's constructor always initializes its SegmentReader base
|
||||
// class with an Arena pointer that actually points to a BuilderArena.
|
||||
return static_cast<BuilderArena*>(arena);
|
||||
}
|
||||
|
||||
inline kj::ArrayPtr<const word> SegmentBuilder::currentlyAllocated() {
|
||||
return kj::arrayPtr(ptr.begin(), pos - ptr.begin());
|
||||
}
|
||||
|
||||
inline void SegmentBuilder::reset() {
|
||||
word* start = getPtrUnchecked(ZERO * WORDS);
|
||||
memset(start, 0, (pos - start) * sizeof(word));
|
||||
pos = start;
|
||||
}
|
||||
|
||||
inline void SegmentBuilder::tryTruncate(word* from, word* to) {
|
||||
if (pos == from) pos = to;
|
||||
}
|
||||
|
||||
inline bool SegmentBuilder::tryExtend(word* from, word* to) {
|
||||
// Careful about overflow.
|
||||
if (pos == from && to <= ptr.end() && to >= from) {
|
||||
pos = to;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.
|
||||
|
||||
#include "blob.h"
|
||||
|
||||
namespace capnp {
|
||||
|
||||
char Text::Builder::nulstr[1] = "";
|
||||
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kj/common.h>
|
||||
#include <kj/string.h>
|
||||
#include "common.h"
|
||||
#include <string.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
struct Data {
|
||||
Data() = delete;
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline {};
|
||||
};
|
||||
|
||||
struct Text {
|
||||
Text() = delete;
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline {};
|
||||
};
|
||||
|
||||
class Data::Reader: public kj::ArrayPtr<const byte> {
|
||||
// Points to a blob of bytes. The usual Reader rules apply -- Data::Reader behaves like a simple
|
||||
// pointer which does not own its target, can be passed by value, etc.
|
||||
|
||||
public:
|
||||
typedef Data Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline Reader(decltype(nullptr)): ArrayPtr<const byte>(nullptr) {}
|
||||
inline Reader(const byte* value, size_t size): ArrayPtr<const byte>(value, size) {}
|
||||
inline Reader(const kj::Array<const byte>& value): ArrayPtr<const byte>(value) {}
|
||||
inline Reader(const ArrayPtr<const byte>& value): ArrayPtr<const byte>(value) {}
|
||||
inline Reader(const kj::Array<byte>& value): ArrayPtr<const byte>(value) {}
|
||||
inline Reader(const ArrayPtr<byte>& value): ArrayPtr<const byte>(value) {}
|
||||
};
|
||||
|
||||
class Text::Reader: public kj::StringPtr {
|
||||
// Like Data::Reader, but points at NUL-terminated UTF-8 text. The NUL terminator is not counted
|
||||
// in the size but must be present immediately after the last byte.
|
||||
//
|
||||
// Text::Reader's interface contract is that its data MUST be NUL-terminated. The producer of
|
||||
// the Text::Reader must guarantee this, so that the consumer need not check. The data SHOULD
|
||||
// also be valid UTF-8, but this is NOT guaranteed -- the consumer must verify if it cares.
|
||||
|
||||
public:
|
||||
typedef Text Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline Reader(decltype(nullptr)): StringPtr(nullptr) {}
|
||||
inline Reader(const char* value): StringPtr(value) {}
|
||||
inline Reader(const char* value, size_t size): StringPtr(value, size) {}
|
||||
inline Reader(const kj::String& value): StringPtr(value) {}
|
||||
inline Reader(const StringPtr& value): StringPtr(value) {}
|
||||
|
||||
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP
|
||||
template <typename T, typename = decltype(kj::instance<T>().c_str())>
|
||||
inline Reader(const T& t): StringPtr(t) {}
|
||||
// Allow implicit conversion from any class that has a c_str() method (namely, std::string).
|
||||
// We use a template trick to detect std::string in order to avoid including the header for
|
||||
// those who don't want it.
|
||||
#endif
|
||||
};
|
||||
|
||||
class Data::Builder: public kj::ArrayPtr<byte> {
|
||||
// Like Data::Reader except the pointers aren't const.
|
||||
|
||||
public:
|
||||
typedef Data Builds;
|
||||
|
||||
Builder() = default;
|
||||
inline Builder(decltype(nullptr)): ArrayPtr<byte>(nullptr) {}
|
||||
inline Builder(byte* value, size_t size): ArrayPtr<byte>(value, size) {}
|
||||
inline Builder(kj::Array<byte>& value): ArrayPtr<byte>(value) {}
|
||||
inline Builder(ArrayPtr<byte> value): ArrayPtr<byte>(value) {}
|
||||
|
||||
inline Data::Reader asReader() const {
|
||||
return Data::Reader(kj::implicitCast<const kj::ArrayPtr<byte>&>(*this));
|
||||
}
|
||||
inline operator Reader() const { return asReader(); }
|
||||
};
|
||||
|
||||
class Text::Builder: public kj::DisallowConstCopy {
|
||||
// Basically identical to kj::StringPtr, except that the contents are non-const.
|
||||
|
||||
public:
|
||||
inline Builder(): content(nulstr, 1) {}
|
||||
inline Builder(decltype(nullptr)): content(nulstr, 1) {}
|
||||
inline Builder(char* value): content(value, strlen(value) + 1) {}
|
||||
inline Builder(char* value, size_t size): content(value, size + 1) {
|
||||
KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated.");
|
||||
}
|
||||
|
||||
inline Reader asReader() const { return Reader(content.begin(), content.size() - 1); }
|
||||
inline operator Reader() const { return asReader(); }
|
||||
|
||||
inline operator kj::ArrayPtr<char>();
|
||||
inline kj::ArrayPtr<char> asArray();
|
||||
inline operator kj::ArrayPtr<const char>() const;
|
||||
inline kj::ArrayPtr<const char> asArray() const;
|
||||
inline kj::ArrayPtr<byte> asBytes() { return asArray().asBytes(); }
|
||||
inline kj::ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline operator kj::StringPtr() const;
|
||||
inline kj::StringPtr asString() const;
|
||||
|
||||
inline const char* cStr() const { return content.begin(); }
|
||||
// Returns NUL-terminated string.
|
||||
|
||||
inline size_t size() const { return content.size() - 1; }
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline char operator[](size_t index) const { return content[index]; }
|
||||
inline char& operator[](size_t index) { return content[index]; }
|
||||
|
||||
inline char* begin() { return content.begin(); }
|
||||
inline char* end() { return content.end() - 1; }
|
||||
inline const char* begin() const { return content.begin(); }
|
||||
inline const char* end() const { return content.end() - 1; }
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
|
||||
|
||||
inline bool operator==(Builder other) const { return asString() == other.asString(); }
|
||||
inline bool operator!=(Builder other) const { return asString() != other.asString(); }
|
||||
inline bool operator< (Builder other) const { return asString() < other.asString(); }
|
||||
inline bool operator> (Builder other) const { return asString() > other.asString(); }
|
||||
inline bool operator<=(Builder other) const { return asString() <= other.asString(); }
|
||||
inline bool operator>=(Builder other) const { return asString() >= other.asString(); }
|
||||
|
||||
inline kj::StringPtr slice(size_t start) const;
|
||||
inline kj::ArrayPtr<const char> slice(size_t start, size_t end) const;
|
||||
inline Builder slice(size_t start);
|
||||
inline kj::ArrayPtr<char> slice(size_t start, size_t end);
|
||||
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
|
||||
// version that assumes end = size().
|
||||
|
||||
private:
|
||||
inline explicit Builder(kj::ArrayPtr<char> content): content(content) {}
|
||||
|
||||
kj::ArrayPtr<char> content;
|
||||
|
||||
static char nulstr[1];
|
||||
};
|
||||
|
||||
inline kj::StringPtr KJ_STRINGIFY(Text::Builder builder) {
|
||||
return builder.asString();
|
||||
}
|
||||
|
||||
inline bool operator==(const char* a, const Text::Builder& b) { return b.asString() == a; }
|
||||
inline bool operator!=(const char* a, const Text::Builder& b) { return b.asString() != a; }
|
||||
|
||||
inline Text::Builder::operator kj::StringPtr() const {
|
||||
return kj::StringPtr(content.begin(), content.size() - 1);
|
||||
}
|
||||
|
||||
inline kj::StringPtr Text::Builder::asString() const {
|
||||
return kj::StringPtr(content.begin(), content.size() - 1);
|
||||
}
|
||||
|
||||
inline Text::Builder::operator kj::ArrayPtr<char>() {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline kj::ArrayPtr<char> Text::Builder::asArray() {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline Text::Builder::operator kj::ArrayPtr<const char>() const {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline kj::ArrayPtr<const char> Text::Builder::asArray() const {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline kj::StringPtr Text::Builder::slice(size_t start) const {
|
||||
return asReader().slice(start);
|
||||
}
|
||||
inline kj::ArrayPtr<const char> Text::Builder::slice(size_t start, size_t end) const {
|
||||
return content.slice(start, end);
|
||||
}
|
||||
|
||||
inline Text::Builder Text::Builder::slice(size_t start) {
|
||||
return Text::Builder(content.slice(start, content.size()));
|
||||
}
|
||||
inline kj::ArrayPtr<char> Text::Builder::slice(size_t start, size_t end) {
|
||||
return content.slice(start, end);
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: c++.capnp
|
||||
|
||||
#include "c++.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<21> b_b9c6f99ebf805f2c = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
44, 95, 128, 191, 158, 249, 198, 185,
|
||||
16, 0, 0, 0, 5, 0, 1, 0,
|
||||
129, 78, 48, 184, 123, 125, 248, 189,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 210, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
28, 0, 0, 0, 3, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 97, 112, 110, 112, 47, 99, 43,
|
||||
43, 46, 99, 97, 112, 110, 112, 58,
|
||||
110, 97, 109, 101, 115, 112, 97, 99,
|
||||
101, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_b9c6f99ebf805f2c = b_b9c6f99ebf805f2c.words;
|
||||
#if !CAPNP_LITE
|
||||
const ::capnp::_::RawSchema s_b9c6f99ebf805f2c = {
|
||||
0xb9c6f99ebf805f2c, b_b9c6f99ebf805f2c.words, 21, nullptr, nullptr,
|
||||
0, 0, nullptr, nullptr, nullptr, { &s_b9c6f99ebf805f2c, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<20> b_f264a779fef191ce = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
206, 145, 241, 254, 121, 167, 100, 242,
|
||||
16, 0, 0, 0, 5, 0, 252, 7,
|
||||
129, 78, 48, 184, 123, 125, 248, 189,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 170, 0, 0, 0,
|
||||
29, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
24, 0, 0, 0, 3, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 97, 112, 110, 112, 47, 99, 43,
|
||||
43, 46, 99, 97, 112, 110, 112, 58,
|
||||
110, 97, 109, 101, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_f264a779fef191ce = b_f264a779fef191ce.words;
|
||||
#if !CAPNP_LITE
|
||||
const ::capnp::_::RawSchema s_f264a779fef191ce = {
|
||||
0xf264a779fef191ce, b_f264a779fef191ce.words, 20, nullptr, nullptr,
|
||||
0, 0, nullptr, nullptr, nullptr, { &s_f264a779fef191ce, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<22> b_ac7096ff8cfc9dce = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
206, 157, 252, 140, 255, 150, 112, 172,
|
||||
16, 0, 0, 0, 5, 0, 1, 3,
|
||||
129, 78, 48, 184, 123, 125, 248, 189,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 18, 1, 0, 0,
|
||||
37, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 0, 0, 0, 3, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 97, 112, 110, 112, 47, 99, 43,
|
||||
43, 46, 99, 97, 112, 110, 112, 58,
|
||||
97, 108, 108, 111, 119, 67, 97, 110,
|
||||
99, 101, 108, 108, 97, 116, 105, 111,
|
||||
110, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_ac7096ff8cfc9dce = b_ac7096ff8cfc9dce.words;
|
||||
#if !CAPNP_LITE
|
||||
const ::capnp::_::RawSchema s_ac7096ff8cfc9dce = {
|
||||
0xac7096ff8cfc9dce, b_ac7096ff8cfc9dce.words, 22, nullptr, nullptr,
|
||||
0, 0, nullptr, nullptr, nullptr, { &s_ac7096ff8cfc9dce, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: c++.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(b9c6f99ebf805f2c);
|
||||
CAPNP_DECLARE_SCHEMA(f264a779fef191ce);
|
||||
CAPNP_DECLARE_SCHEMA(ac7096ff8cfc9dce);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace capnp {
|
||||
namespace annotations {
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,751 @@
|
|||
// 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.
|
||||
|
||||
// This file contains types which are intended to help detect incorrect usage at compile
|
||||
// time, but should then be optimized down to basic primitives (usually, integers) by the
|
||||
// compiler.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <kj/string.h>
|
||||
#include <kj/memory.h>
|
||||
#include <kj/windows-sanity.h> // work-around macro conflict with `VOID`
|
||||
|
||||
#if CAPNP_DEBUG_TYPES
|
||||
#include <kj/units.h>
|
||||
#endif
|
||||
|
||||
#if !defined(CAPNP_HEADER_WARNINGS) || !CAPNP_HEADER_WARNINGS
|
||||
#define CAPNP_BEGIN_HEADER KJ_BEGIN_SYSTEM_HEADER
|
||||
#define CAPNP_END_HEADER KJ_END_SYSTEM_HEADER
|
||||
#else
|
||||
#define CAPNP_BEGIN_HEADER
|
||||
#define CAPNP_END_HEADER
|
||||
#endif
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
#define CAPNP_VERSION_MAJOR 1
|
||||
#define CAPNP_VERSION_MINOR 0
|
||||
#define CAPNP_VERSION_MICRO 1
|
||||
|
||||
#define CAPNP_VERSION \
|
||||
(CAPNP_VERSION_MAJOR * 1000000 + CAPNP_VERSION_MINOR * 1000 + CAPNP_VERSION_MICRO)
|
||||
|
||||
#ifndef CAPNP_LITE
|
||||
#define CAPNP_LITE 0
|
||||
#endif
|
||||
|
||||
#if CAPNP_TESTING_CAPNP // defined in Cap'n Proto's own unit tests; others should not define this
|
||||
#define CAPNP_DEPRECATED(reason)
|
||||
#else
|
||||
#define CAPNP_DEPRECATED KJ_DEPRECATED
|
||||
#endif
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
struct Void {
|
||||
// Type used for Void fields. Using C++'s "void" type creates a bunch of issues since it behaves
|
||||
// differently from other types.
|
||||
|
||||
inline constexpr bool operator==(Void other) const { return true; }
|
||||
inline constexpr bool operator!=(Void other) const { return false; }
|
||||
};
|
||||
|
||||
static constexpr Void VOID = Void();
|
||||
// Constant value for `Void`, which is an empty struct.
|
||||
|
||||
inline kj::StringPtr KJ_STRINGIFY(Void) { return "void"; }
|
||||
|
||||
struct Text;
|
||||
struct Data;
|
||||
|
||||
enum class Kind: uint8_t {
|
||||
PRIMITIVE,
|
||||
BLOB,
|
||||
ENUM,
|
||||
STRUCT,
|
||||
UNION,
|
||||
INTERFACE,
|
||||
LIST,
|
||||
|
||||
OTHER
|
||||
// Some other type which is often a type parameter to Cap'n Proto templates, but which needs
|
||||
// special handling. This includes types like AnyPointer, Dynamic*, etc.
|
||||
};
|
||||
|
||||
enum class Style: uint8_t {
|
||||
PRIMITIVE,
|
||||
POINTER, // other than struct
|
||||
STRUCT,
|
||||
CAPABILITY
|
||||
};
|
||||
|
||||
enum class ElementSize: uint8_t {
|
||||
// Size of a list element.
|
||||
|
||||
VOID = 0,
|
||||
BIT = 1,
|
||||
BYTE = 2,
|
||||
TWO_BYTES = 3,
|
||||
FOUR_BYTES = 4,
|
||||
EIGHT_BYTES = 5,
|
||||
|
||||
POINTER = 6,
|
||||
|
||||
INLINE_COMPOSITE = 7
|
||||
};
|
||||
|
||||
enum class PointerType {
|
||||
// Various wire types a pointer field can take
|
||||
|
||||
NULL_,
|
||||
// Should be NULL, but that's #defined in stddef.h
|
||||
|
||||
STRUCT,
|
||||
LIST,
|
||||
CAPABILITY
|
||||
};
|
||||
|
||||
namespace schemas {
|
||||
|
||||
template <typename T>
|
||||
struct EnumInfo;
|
||||
|
||||
} // namespace schemas
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T, typename = void> struct Kind_;
|
||||
|
||||
template <> struct Kind_<Void> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<bool> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<int8_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<int16_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<int32_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<int64_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<uint8_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<uint16_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<uint32_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<uint64_t> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<float> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<double> { static constexpr Kind kind = Kind::PRIMITIVE; };
|
||||
template <> struct Kind_<Text> { static constexpr Kind kind = Kind::BLOB; };
|
||||
template <> struct Kind_<Data> { static constexpr Kind kind = Kind::BLOB; };
|
||||
|
||||
template <typename T> struct Kind_<T, kj::VoidSfinae<typename T::_capnpPrivate::IsStruct>> {
|
||||
static constexpr Kind kind = Kind::STRUCT;
|
||||
};
|
||||
template <typename T> struct Kind_<T, kj::VoidSfinae<typename T::_capnpPrivate::IsInterface>> {
|
||||
static constexpr Kind kind = Kind::INTERFACE;
|
||||
};
|
||||
template <typename T> struct Kind_<T, kj::VoidSfinae<typename schemas::EnumInfo<T>::IsEnum>> {
|
||||
static constexpr Kind kind = Kind::ENUM;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T, Kind k = _::Kind_<T>::kind>
|
||||
inline constexpr Kind kind() {
|
||||
// This overload of kind() matches types which have a Kind_ specialization.
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
|
||||
#define CAPNP_KIND(T) ::capnp::_::Kind_<T>::kind
|
||||
// Avoid constexpr methods in MSVC (it remains buggy in many situations).
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#define CAPNP_KIND(T) ::capnp::kind<T>()
|
||||
// Use this macro rather than kind<T>() in any code which must work in MSVC.
|
||||
|
||||
#endif // _MSC_VER, else
|
||||
|
||||
#if !CAPNP_LITE
|
||||
|
||||
template <typename T, Kind k = kind<T>()>
|
||||
inline constexpr Style style() {
|
||||
return k == Kind::PRIMITIVE || k == Kind::ENUM ? Style::PRIMITIVE
|
||||
: k == Kind::STRUCT ? Style::STRUCT
|
||||
: k == Kind::INTERFACE ? Style::CAPABILITY : Style::POINTER;
|
||||
}
|
||||
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)>
|
||||
struct List;
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
|
||||
template <typename T, Kind k>
|
||||
struct List {};
|
||||
// For some reason, without this declaration, MSVC will error out on some uses of List
|
||||
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
|
||||
// is not defined. I do not understand this error, but adding this empty default declaration fixes
|
||||
// it.
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T> struct ListElementType_;
|
||||
template <typename T> struct ListElementType_<List<T>> { typedef T Type; };
|
||||
template <typename T> using ListElementType = typename ListElementType_<T>::Type;
|
||||
|
||||
namespace _ { // private
|
||||
template <typename T, Kind k> struct Kind_<List<T, k>> {
|
||||
static constexpr Kind kind = Kind::LIST;
|
||||
};
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)> struct ReaderFor_ { typedef typename T::Reader Type; };
|
||||
template <typename T> struct ReaderFor_<T, Kind::PRIMITIVE> { typedef T Type; };
|
||||
template <typename T> struct ReaderFor_<T, Kind::ENUM> { typedef T Type; };
|
||||
template <typename T> struct ReaderFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
|
||||
template <typename T> using ReaderFor = typename ReaderFor_<T>::Type;
|
||||
// The type returned by List<T>::Reader::operator[].
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)> struct BuilderFor_ { typedef typename T::Builder Type; };
|
||||
template <typename T> struct BuilderFor_<T, Kind::PRIMITIVE> { typedef T Type; };
|
||||
template <typename T> struct BuilderFor_<T, Kind::ENUM> { typedef T Type; };
|
||||
template <typename T> struct BuilderFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
|
||||
template <typename T> using BuilderFor = typename BuilderFor_<T>::Type;
|
||||
// The type returned by List<T>::Builder::operator[].
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)> struct PipelineFor_ { typedef typename T::Pipeline Type;};
|
||||
template <typename T> struct PipelineFor_<T, Kind::INTERFACE> { typedef typename T::Client Type; };
|
||||
template <typename T> using PipelineFor = typename PipelineFor_<T>::Type;
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)> struct TypeIfEnum_;
|
||||
template <typename T> struct TypeIfEnum_<T, Kind::ENUM> { typedef T Type; };
|
||||
|
||||
template <typename T>
|
||||
using TypeIfEnum = typename TypeIfEnum_<kj::Decay<T>>::Type;
|
||||
|
||||
template <typename T>
|
||||
using FromReader = typename kj::Decay<T>::Reads;
|
||||
// FromReader<MyType::Reader> = MyType (for any Cap'n Proto type).
|
||||
|
||||
template <typename T>
|
||||
using FromBuilder = typename kj::Decay<T>::Builds;
|
||||
// FromBuilder<MyType::Builder> = MyType (for any Cap'n Proto type).
|
||||
|
||||
template <typename T>
|
||||
using FromPipeline = typename kj::Decay<T>::Pipelines;
|
||||
// FromBuilder<MyType::Pipeline> = MyType (for any Cap'n Proto type).
|
||||
|
||||
template <typename T>
|
||||
using FromClient = typename kj::Decay<T>::Calls;
|
||||
// FromReader<MyType::Client> = MyType (for any Cap'n Proto interface type).
|
||||
|
||||
template <typename T>
|
||||
using FromServer = typename kj::Decay<T>::Serves;
|
||||
// FromBuilder<MyType::Server> = MyType (for any Cap'n Proto interface type).
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct FromAny_;
|
||||
|
||||
template <typename T>
|
||||
struct FromAny_<T, kj::VoidSfinae<FromReader<T>>> {
|
||||
using Type = FromReader<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FromAny_<T, kj::VoidSfinae<FromBuilder<T>>> {
|
||||
using Type = FromBuilder<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FromAny_<T, kj::VoidSfinae<FromPipeline<T>>> {
|
||||
using Type = FromPipeline<T>;
|
||||
};
|
||||
|
||||
// Note that T::Client is covered by FromReader
|
||||
|
||||
template <typename T>
|
||||
struct FromAny_<kj::Own<T>, kj::VoidSfinae<FromServer<T>>> {
|
||||
using Type = FromServer<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FromAny_<T,
|
||||
kj::EnableIf<_::Kind_<T>::kind == Kind::PRIMITIVE || _::Kind_<T>::kind == Kind::ENUM>> {
|
||||
// TODO(msvc): Ideally the EnableIf condition would be `style<T>() == Style::PRIMITIVE`, but MSVC
|
||||
// cannot yet use style<T>() in this constexpr context.
|
||||
|
||||
using Type = kj::Decay<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using FromAny = typename FromAny_<T>::Type;
|
||||
// Given any Cap'n Proto value type as an input, return the Cap'n Proto base type. That is:
|
||||
//
|
||||
// Foo::Reader -> Foo
|
||||
// Foo::Builder -> Foo
|
||||
// Foo::Pipeline -> Foo
|
||||
// Foo::Client -> Foo
|
||||
// Own<Foo::Server> -> Foo
|
||||
// uint32_t -> uint32_t
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)>
|
||||
struct PointerHelpers;
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
|
||||
template <typename T, Kind k>
|
||||
struct PointerHelpers {};
|
||||
// For some reason, without this declaration, MSVC will error out on some uses of PointerHelpers
|
||||
// claiming that "T" -- as used in the default initializer for the second template param, "k" --
|
||||
// is not defined. I do not understand this error, but adding this empty default declaration fixes
|
||||
// it.
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
struct MessageSize {
|
||||
// Size of a message. Every struct and list type has a method `.totalSize()` that returns this.
|
||||
uint64_t wordCount;
|
||||
uint capCount;
|
||||
|
||||
inline constexpr MessageSize operator+(const MessageSize& other) const {
|
||||
return { wordCount + other.wordCount, capCount + other.capCount };
|
||||
}
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Raw memory types and measures
|
||||
|
||||
using kj::byte;
|
||||
|
||||
class word {
|
||||
// word is an opaque type with size of 64 bits. This type is useful only to make pointer
|
||||
// arithmetic clearer. Since the contents are private, the only way to access them is to first
|
||||
// reinterpret_cast to some other pointer type.
|
||||
//
|
||||
// Copying is disallowed because you should always use memcpy(). Otherwise, you may run afoul of
|
||||
// aliasing rules.
|
||||
//
|
||||
// A pointer of type word* should always be word-aligned even if won't actually be dereferenced
|
||||
// as that type.
|
||||
public:
|
||||
word() = default;
|
||||
private:
|
||||
uint64_t content KJ_UNUSED_MEMBER;
|
||||
#if __GNUC__ < 8 || __clang__
|
||||
// GCC 8's -Wclass-memaccess complains whenever we try to memcpy() a `word` if we've disallowed
|
||||
// the copy constructor. We don't want to disable the warning because it's a useful warning and
|
||||
// we'd have to disable it for all applications that include this header. Instead we allow `word`
|
||||
// to be copyable on GCC.
|
||||
KJ_DISALLOW_COPY_AND_MOVE(word);
|
||||
#endif
|
||||
};
|
||||
|
||||
static_assert(sizeof(byte) == 1, "uint8_t is not one byte?");
|
||||
static_assert(sizeof(word) == 8, "uint64_t is not 8 bytes?");
|
||||
|
||||
#if CAPNP_DEBUG_TYPES
|
||||
// Set CAPNP_DEBUG_TYPES to 1 to use kj::Quantity for "count" types. Otherwise, plain integers are
|
||||
// used. All the code should still operate exactly the same, we just lose compile-time checking.
|
||||
// Note that this will also change symbol names, so it's important that the library and any clients
|
||||
// be compiled with the same setting here.
|
||||
//
|
||||
// We disable this by default to reduce symbol name size and avoid any possibility of the compiler
|
||||
// failing to fully-optimize the types, but anyone modifying Cap'n Proto itself should enable this
|
||||
// during development and testing.
|
||||
|
||||
namespace _ { class BitLabel; class ElementLabel; struct WirePointer; }
|
||||
|
||||
template <uint width, typename T = uint>
|
||||
using BitCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::BitLabel>;
|
||||
template <uint width, typename T = uint>
|
||||
using ByteCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, byte>;
|
||||
template <uint width, typename T = uint>
|
||||
using WordCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, word>;
|
||||
template <uint width, typename T = uint>
|
||||
using ElementCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::ElementLabel>;
|
||||
template <uint width, typename T = uint>
|
||||
using WirePointerCountN = kj::Quantity<kj::Bounded<kj::maxValueForBits<width>(), T>, _::WirePointer>;
|
||||
|
||||
typedef BitCountN<8, uint8_t> BitCount8;
|
||||
typedef BitCountN<16, uint16_t> BitCount16;
|
||||
typedef BitCountN<32, uint32_t> BitCount32;
|
||||
typedef BitCountN<64, uint64_t> BitCount64;
|
||||
typedef BitCountN<sizeof(uint) * 8, uint> BitCount;
|
||||
|
||||
typedef ByteCountN<8, uint8_t> ByteCount8;
|
||||
typedef ByteCountN<16, uint16_t> ByteCount16;
|
||||
typedef ByteCountN<32, uint32_t> ByteCount32;
|
||||
typedef ByteCountN<64, uint64_t> ByteCount64;
|
||||
typedef ByteCountN<sizeof(uint) * 8, uint> ByteCount;
|
||||
|
||||
typedef WordCountN<8, uint8_t> WordCount8;
|
||||
typedef WordCountN<16, uint16_t> WordCount16;
|
||||
typedef WordCountN<32, uint32_t> WordCount32;
|
||||
typedef WordCountN<64, uint64_t> WordCount64;
|
||||
typedef WordCountN<sizeof(uint) * 8, uint> WordCount;
|
||||
|
||||
typedef ElementCountN<8, uint8_t> ElementCount8;
|
||||
typedef ElementCountN<16, uint16_t> ElementCount16;
|
||||
typedef ElementCountN<32, uint32_t> ElementCount32;
|
||||
typedef ElementCountN<64, uint64_t> ElementCount64;
|
||||
typedef ElementCountN<sizeof(uint) * 8, uint> ElementCount;
|
||||
|
||||
typedef WirePointerCountN<8, uint8_t> WirePointerCount8;
|
||||
typedef WirePointerCountN<16, uint16_t> WirePointerCount16;
|
||||
typedef WirePointerCountN<32, uint32_t> WirePointerCount32;
|
||||
typedef WirePointerCountN<64, uint64_t> WirePointerCount64;
|
||||
typedef WirePointerCountN<sizeof(uint) * 8, uint> WirePointerCount;
|
||||
|
||||
template <uint width>
|
||||
using BitsPerElementN = decltype(BitCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using BytesPerElementN = decltype(ByteCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using WordsPerElementN = decltype(WordCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using PointersPerElementN = decltype(WirePointerCountN<width>() / ElementCountN<width>());
|
||||
|
||||
using kj::bounded;
|
||||
using kj::unbound;
|
||||
using kj::unboundAs;
|
||||
using kj::unboundMax;
|
||||
using kj::unboundMaxBits;
|
||||
using kj::assertMax;
|
||||
using kj::assertMaxBits;
|
||||
using kj::upgradeBound;
|
||||
using kj::ThrowOverflow;
|
||||
using kj::assumeBits;
|
||||
using kj::assumeMax;
|
||||
using kj::subtractChecked;
|
||||
using kj::trySubtract;
|
||||
|
||||
template <typename T, typename U>
|
||||
inline constexpr U* operator+(U* ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr const U* operator+(const U* ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr U* operator+=(U*& ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr = ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr const U* operator+=(const U*& ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr = ptr + unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline constexpr U* operator-(U* ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr const U* operator-(const U* ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr U* operator-=(U*& ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr = ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr const U* operator-=(const U*& ptr, kj::Quantity<T, U> offset) {
|
||||
return ptr = ptr - unbound(offset / kj::unit<kj::Quantity<T, U>>());
|
||||
}
|
||||
|
||||
constexpr auto BITS = kj::unit<BitCountN<1>>();
|
||||
constexpr auto BYTES = kj::unit<ByteCountN<1>>();
|
||||
constexpr auto WORDS = kj::unit<WordCountN<1>>();
|
||||
constexpr auto ELEMENTS = kj::unit<ElementCountN<1>>();
|
||||
constexpr auto POINTERS = kj::unit<WirePointerCountN<1>>();
|
||||
|
||||
constexpr auto ZERO = kj::bounded<0>();
|
||||
constexpr auto ONE = kj::bounded<1>();
|
||||
|
||||
// GCC 4.7 actually gives unused warnings on these constants in opt mode...
|
||||
constexpr auto BITS_PER_BYTE KJ_UNUSED = bounded<8>() * BITS / BYTES;
|
||||
constexpr auto BITS_PER_WORD KJ_UNUSED = bounded<64>() * BITS / WORDS;
|
||||
constexpr auto BYTES_PER_WORD KJ_UNUSED = bounded<8>() * BYTES / WORDS;
|
||||
|
||||
constexpr auto BITS_PER_POINTER KJ_UNUSED = bounded<64>() * BITS / POINTERS;
|
||||
constexpr auto BYTES_PER_POINTER KJ_UNUSED = bounded<8>() * BYTES / POINTERS;
|
||||
constexpr auto WORDS_PER_POINTER KJ_UNUSED = ONE * WORDS / POINTERS;
|
||||
|
||||
constexpr auto POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER;
|
||||
|
||||
constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment.
|
||||
constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list.
|
||||
constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section.
|
||||
constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section.
|
||||
constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob.
|
||||
|
||||
typedef WordCountN<SEGMENT_WORD_COUNT_BITS> SegmentWordCount;
|
||||
typedef ElementCountN<LIST_ELEMENT_COUNT_BITS> ListElementCount;
|
||||
typedef WordCountN<STRUCT_DATA_WORD_COUNT_BITS, uint16_t> StructDataWordCount;
|
||||
typedef WirePointerCountN<STRUCT_POINTER_COUNT_BITS, uint16_t> StructPointerCount;
|
||||
typedef ByteCountN<BLOB_SIZE_BITS> BlobSize;
|
||||
|
||||
constexpr auto MAX_SEGMENT_WORDS =
|
||||
bounded<kj::maxValueForBits<SEGMENT_WORD_COUNT_BITS>()>() * WORDS;
|
||||
constexpr auto MAX_LIST_ELEMENTS =
|
||||
bounded<kj::maxValueForBits<LIST_ELEMENT_COUNT_BITS>()>() * ELEMENTS;
|
||||
constexpr auto MAX_STUCT_DATA_WORDS =
|
||||
bounded<kj::maxValueForBits<STRUCT_DATA_WORD_COUNT_BITS>()>() * WORDS;
|
||||
constexpr auto MAX_STRUCT_POINTER_COUNT =
|
||||
bounded<kj::maxValueForBits<STRUCT_POINTER_COUNT_BITS>()>() * POINTERS;
|
||||
|
||||
using StructDataBitCount = decltype(WordCountN<STRUCT_POINTER_COUNT_BITS>() * BITS_PER_WORD);
|
||||
// Number of bits in a Struct data segment (should come out to BitCountN<22>).
|
||||
|
||||
using StructDataOffset = decltype(StructDataBitCount() * (ONE * ELEMENTS / BITS));
|
||||
using StructPointerOffset = StructPointerCount;
|
||||
// Type of a field offset.
|
||||
|
||||
inline StructDataOffset assumeDataOffset(uint32_t offset) {
|
||||
return assumeMax(MAX_STUCT_DATA_WORDS * BITS_PER_WORD * (ONE * ELEMENTS / BITS),
|
||||
bounded(offset) * ELEMENTS);
|
||||
}
|
||||
|
||||
inline StructPointerOffset assumePointerOffset(uint32_t offset) {
|
||||
return assumeMax(MAX_STRUCT_POINTER_COUNT, bounded(offset) * POINTERS);
|
||||
}
|
||||
|
||||
constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits<BLOB_SIZE_BITS>() - 1;
|
||||
typedef kj::Quantity<kj::Bounded<MAX_TEXT_SIZE, uint>, byte> TextSize;
|
||||
// Not including NUL terminator.
|
||||
|
||||
template <typename T>
|
||||
inline KJ_CONSTEXPR() decltype(bounded<sizeof(T)>() * BYTES / ELEMENTS) bytesPerElement() {
|
||||
return bounded<sizeof(T)>() * BYTES / ELEMENTS;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline KJ_CONSTEXPR() decltype(bounded<sizeof(T) * 8>() * BITS / ELEMENTS) bitsPerElement() {
|
||||
return bounded<sizeof(T) * 8>() * BITS / ELEMENTS;
|
||||
}
|
||||
|
||||
template <typename T, uint maxN>
|
||||
inline constexpr kj::Quantity<kj::Bounded<maxN, size_t>, T>
|
||||
intervalLength(const T* a, const T* b, kj::Quantity<kj::BoundedConst<maxN>, T>) {
|
||||
return kj::assumeMax<maxN>(b - a) * kj::unit<kj::Quantity<kj::BoundedConst<1u>, T>>();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline constexpr kj::ArrayPtr<const U> arrayPtr(const U* ptr, kj::Quantity<T, U> size) {
|
||||
return kj::ArrayPtr<const U>(ptr, unbound(size / kj::unit<kj::Quantity<T, U>>()));
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr kj::ArrayPtr<U> arrayPtr(U* ptr, kj::Quantity<T, U> size) {
|
||||
return kj::ArrayPtr<U>(ptr, unbound(size / kj::unit<kj::Quantity<T, U>>()));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <uint width, typename T = uint>
|
||||
using BitCountN = T;
|
||||
template <uint width, typename T = uint>
|
||||
using ByteCountN = T;
|
||||
template <uint width, typename T = uint>
|
||||
using WordCountN = T;
|
||||
template <uint width, typename T = uint>
|
||||
using ElementCountN = T;
|
||||
template <uint width, typename T = uint>
|
||||
using WirePointerCountN = T;
|
||||
|
||||
|
||||
// XXX
|
||||
typedef BitCountN<8, uint8_t> BitCount8;
|
||||
typedef BitCountN<16, uint16_t> BitCount16;
|
||||
typedef BitCountN<32, uint32_t> BitCount32;
|
||||
typedef BitCountN<64, uint64_t> BitCount64;
|
||||
typedef BitCountN<sizeof(uint) * 8, uint> BitCount;
|
||||
|
||||
typedef ByteCountN<8, uint8_t> ByteCount8;
|
||||
typedef ByteCountN<16, uint16_t> ByteCount16;
|
||||
typedef ByteCountN<32, uint32_t> ByteCount32;
|
||||
typedef ByteCountN<64, uint64_t> ByteCount64;
|
||||
typedef ByteCountN<sizeof(uint) * 8, uint> ByteCount;
|
||||
|
||||
typedef WordCountN<8, uint8_t> WordCount8;
|
||||
typedef WordCountN<16, uint16_t> WordCount16;
|
||||
typedef WordCountN<32, uint32_t> WordCount32;
|
||||
typedef WordCountN<64, uint64_t> WordCount64;
|
||||
typedef WordCountN<sizeof(uint) * 8, uint> WordCount;
|
||||
|
||||
typedef ElementCountN<8, uint8_t> ElementCount8;
|
||||
typedef ElementCountN<16, uint16_t> ElementCount16;
|
||||
typedef ElementCountN<32, uint32_t> ElementCount32;
|
||||
typedef ElementCountN<64, uint64_t> ElementCount64;
|
||||
typedef ElementCountN<sizeof(uint) * 8, uint> ElementCount;
|
||||
|
||||
typedef WirePointerCountN<8, uint8_t> WirePointerCount8;
|
||||
typedef WirePointerCountN<16, uint16_t> WirePointerCount16;
|
||||
typedef WirePointerCountN<32, uint32_t> WirePointerCount32;
|
||||
typedef WirePointerCountN<64, uint64_t> WirePointerCount64;
|
||||
typedef WirePointerCountN<sizeof(uint) * 8, uint> WirePointerCount;
|
||||
|
||||
template <uint width>
|
||||
using BitsPerElementN = decltype(BitCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using BytesPerElementN = decltype(ByteCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using WordsPerElementN = decltype(WordCountN<width>() / ElementCountN<width>());
|
||||
template <uint width>
|
||||
using PointersPerElementN = decltype(WirePointerCountN<width>() / ElementCountN<width>());
|
||||
|
||||
using kj::ThrowOverflow;
|
||||
// YYY
|
||||
|
||||
template <uint i> inline constexpr uint bounded() { return i; }
|
||||
template <typename T> inline constexpr T bounded(T i) { return i; }
|
||||
template <typename T> inline constexpr T unbound(T i) { return i; }
|
||||
|
||||
template <typename T, typename U> inline constexpr T unboundAs(U i) { return i; }
|
||||
|
||||
template <uint64_t requestedMax, typename T> inline constexpr uint unboundMax(T i) { return i; }
|
||||
template <uint bits, typename T> inline constexpr uint unboundMaxBits(T i) { return i; }
|
||||
|
||||
template <uint newMax, typename T, typename ErrorFunc>
|
||||
inline T assertMax(T value, ErrorFunc&& func) {
|
||||
if (KJ_UNLIKELY(value > newMax)) func();
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename ErrorFunc>
|
||||
inline T assertMax(uint newMax, T value, ErrorFunc&& func) {
|
||||
if (KJ_UNLIKELY(value > newMax)) func();
|
||||
return value;
|
||||
}
|
||||
|
||||
template <uint bits, typename T, typename ErrorFunc = ThrowOverflow>
|
||||
inline T assertMaxBits(T value, ErrorFunc&& func = ErrorFunc()) {
|
||||
if (KJ_UNLIKELY(value > kj::maxValueForBits<bits>())) func();
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename ErrorFunc = ThrowOverflow>
|
||||
inline T assertMaxBits(uint bits, T value, ErrorFunc&& func = ErrorFunc()) {
|
||||
if (KJ_UNLIKELY(value > (1ull << bits) - 1)) func();
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename U> inline constexpr T upgradeBound(U i) { return i; }
|
||||
|
||||
template <uint bits, typename T> inline constexpr T assumeBits(T i) { return i; }
|
||||
template <uint64_t max, typename T> inline constexpr T assumeMax(T i) { return i; }
|
||||
|
||||
template <typename T, typename U, typename ErrorFunc = ThrowOverflow>
|
||||
inline auto subtractChecked(T a, U b, ErrorFunc&& errorFunc = ErrorFunc())
|
||||
-> decltype(a - b) {
|
||||
if (b > a) errorFunc();
|
||||
return a - b;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline auto trySubtract(T a, U b) -> kj::Maybe<decltype(a - b)> {
|
||||
if (b > a) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint BITS = 1;
|
||||
constexpr uint BYTES = 1;
|
||||
constexpr uint WORDS = 1;
|
||||
constexpr uint ELEMENTS = 1;
|
||||
constexpr uint POINTERS = 1;
|
||||
|
||||
constexpr uint ZERO = 0;
|
||||
constexpr uint ONE = 1;
|
||||
|
||||
// GCC 4.7 actually gives unused warnings on these constants in opt mode...
|
||||
constexpr uint BITS_PER_BYTE KJ_UNUSED = 8;
|
||||
constexpr uint BITS_PER_WORD KJ_UNUSED = 64;
|
||||
constexpr uint BYTES_PER_WORD KJ_UNUSED = 8;
|
||||
|
||||
constexpr uint BITS_PER_POINTER KJ_UNUSED = 64;
|
||||
constexpr uint BYTES_PER_POINTER KJ_UNUSED = 8;
|
||||
constexpr uint WORDS_PER_POINTER KJ_UNUSED = 1;
|
||||
|
||||
// XXX
|
||||
constexpr uint POINTER_SIZE_IN_WORDS = ONE * POINTERS * WORDS_PER_POINTER;
|
||||
|
||||
constexpr uint SEGMENT_WORD_COUNT_BITS = 29; // Number of words in a segment.
|
||||
constexpr uint LIST_ELEMENT_COUNT_BITS = 29; // Number of elements in a list.
|
||||
constexpr uint STRUCT_DATA_WORD_COUNT_BITS = 16; // Number of words in a Struct data section.
|
||||
constexpr uint STRUCT_POINTER_COUNT_BITS = 16; // Number of pointers in a Struct pointer section.
|
||||
constexpr uint BLOB_SIZE_BITS = 29; // Number of bytes in a blob.
|
||||
|
||||
typedef WordCountN<SEGMENT_WORD_COUNT_BITS> SegmentWordCount;
|
||||
typedef ElementCountN<LIST_ELEMENT_COUNT_BITS> ListElementCount;
|
||||
typedef WordCountN<STRUCT_DATA_WORD_COUNT_BITS, uint16_t> StructDataWordCount;
|
||||
typedef WirePointerCountN<STRUCT_POINTER_COUNT_BITS, uint16_t> StructPointerCount;
|
||||
typedef ByteCountN<BLOB_SIZE_BITS> BlobSize;
|
||||
// YYY
|
||||
|
||||
constexpr auto MAX_SEGMENT_WORDS = kj::maxValueForBits<SEGMENT_WORD_COUNT_BITS>();
|
||||
constexpr auto MAX_LIST_ELEMENTS = kj::maxValueForBits<LIST_ELEMENT_COUNT_BITS>();
|
||||
constexpr auto MAX_STUCT_DATA_WORDS = kj::maxValueForBits<STRUCT_DATA_WORD_COUNT_BITS>();
|
||||
constexpr auto MAX_STRUCT_POINTER_COUNT = kj::maxValueForBits<STRUCT_POINTER_COUNT_BITS>();
|
||||
|
||||
typedef uint StructDataBitCount;
|
||||
typedef uint StructDataOffset;
|
||||
typedef uint StructPointerOffset;
|
||||
|
||||
inline StructDataOffset assumeDataOffset(uint32_t offset) { return offset; }
|
||||
inline StructPointerOffset assumePointerOffset(uint32_t offset) { return offset; }
|
||||
|
||||
constexpr uint MAX_TEXT_SIZE = kj::maxValueForBits<BLOB_SIZE_BITS>() - 1;
|
||||
typedef uint TextSize;
|
||||
|
||||
template <typename T>
|
||||
inline KJ_CONSTEXPR() size_t bytesPerElement() { return sizeof(T); }
|
||||
|
||||
template <typename T>
|
||||
inline KJ_CONSTEXPR() size_t bitsPerElement() { return sizeof(T) * 8; }
|
||||
|
||||
template <typename T>
|
||||
inline constexpr ptrdiff_t intervalLength(const T* a, const T* b, uint) {
|
||||
return b - a;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline constexpr kj::ArrayPtr<const U> arrayPtr(const U* ptr, T size) {
|
||||
return kj::arrayPtr(ptr, size);
|
||||
}
|
||||
template <typename T, typename U>
|
||||
inline constexpr kj::ArrayPtr<U> arrayPtr(U* ptr, T size) {
|
||||
return kj::arrayPtr(ptr, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
// This exposes IndexingIterator as something compatible with std::iterator so that things like
|
||||
// std::copy work with List::begin/List::end.
|
||||
|
||||
// Make sure that if this header is before list.h by the user it includes it to make
|
||||
// IndexingIterator visible to avoid brittle header problems.
|
||||
#include "../list.h"
|
||||
#include <iterator>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename Container, typename Element>
|
||||
struct iterator_traits<capnp::_::IndexingIterator<Container, Element>> {
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = Element;
|
||||
using difference_type = int;
|
||||
using pointer = Element*;
|
||||
using reference = Element&;
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
CAPNP_END_HEADER
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,306 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <inttypes.h>
|
||||
#include <string.h> // memcpy
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace _ { // private
|
||||
|
||||
// WireValue
|
||||
//
|
||||
// Wraps a primitive value as it appears on the wire. Namely, values are little-endian on the
|
||||
// wire, because little-endian is the most common endianness in modern CPUs.
|
||||
//
|
||||
// Note: In general, code that depends cares about byte ordering is bad. See:
|
||||
// http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
|
||||
// Cap'n Proto is special because it is essentially doing compiler-like things, fussing over
|
||||
// allocation and layout of memory, in order to squeeze out every last drop of performance.
|
||||
|
||||
#if _MSC_VER
|
||||
// Assume Windows is little-endian.
|
||||
//
|
||||
// TODO(msvc): This is ugly. Maybe refactor later checks to be based on CAPNP_BYTE_ORDER or
|
||||
// CAPNP_SWAP_BYTES or something, and define that in turn based on _MSC_VER or the GCC
|
||||
// intrinsics.
|
||||
|
||||
#ifndef __ORDER_BIG_ENDIAN__
|
||||
#define __ORDER_BIG_ENDIAN__ 4321
|
||||
#endif
|
||||
#ifndef __ORDER_LITTLE_ENDIAN__
|
||||
#define __ORDER_LITTLE_ENDIAN__ 1234
|
||||
#endif
|
||||
#ifndef __BYTE_ORDER__
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CAPNP_REVERSE_ENDIAN
|
||||
#define CAPNP_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
|
||||
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
|
||||
#else
|
||||
#define CAPNP_WIRE_BYTE_ORDER __ORDER_LITTLE_ENDIAN__
|
||||
#define CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER __ORDER_BIG_ENDIAN__
|
||||
#endif
|
||||
|
||||
#if defined(__BYTE_ORDER__) && \
|
||||
__BYTE_ORDER__ == CAPNP_WIRE_BYTE_ORDER && \
|
||||
!CAPNP_DISABLE_ENDIAN_DETECTION
|
||||
// CPU is little-endian. We can just read/write the memory directly.
|
||||
|
||||
template <typename T>
|
||||
class DirectWireValue {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) { return value; }
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using WireValue = DirectWireValue<T>;
|
||||
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
|
||||
// linked together, we define each implementation with a different name and define an alias to the
|
||||
// one we want to use.
|
||||
|
||||
#elif defined(__BYTE_ORDER__) && \
|
||||
__BYTE_ORDER__ == CAPNP_OPPOSITE_OF_WIRE_BYTE_ORDER && \
|
||||
defined(__GNUC__) && !CAPNP_DISABLE_ENDIAN_DETECTION
|
||||
// Big-endian, but GCC's __builtin_bswap() is available.
|
||||
|
||||
// TODO(perf): Use dedicated instructions to read little-endian data on big-endian CPUs that have
|
||||
// them.
|
||||
|
||||
// TODO(perf): Verify that this code optimizes reasonably. In particular, ensure that the
|
||||
// compiler optimizes away the memcpy()s and keeps everything in registers.
|
||||
|
||||
template <typename T, size_t size = sizeof(T)>
|
||||
class SwappingWireValue;
|
||||
|
||||
template <typename T>
|
||||
class SwappingWireValue<T, 1> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) { return value; }
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SwappingWireValue<T, 2> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
// Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
|
||||
// on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
|
||||
uint16_t swapped = (value << 8) | (value >> 8);
|
||||
T result;
|
||||
memcpy(&result, &swapped, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint16_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
// Not all platforms have __builtin_bswap16() for some reason. In particular, it is missing
|
||||
// on gcc-4.7.3-cygwin32 (but present on gcc-4.8.1-cygwin64).
|
||||
value = (raw << 8) | (raw >> 8);
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SwappingWireValue<T, 4> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
uint32_t swapped = __builtin_bswap32(value);
|
||||
T result;
|
||||
memcpy(&result, &swapped, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint32_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
value = __builtin_bswap32(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SwappingWireValue<T, 8> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
uint64_t swapped = __builtin_bswap64(value);
|
||||
T result;
|
||||
memcpy(&result, &swapped, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint64_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
value = __builtin_bswap64(raw);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using WireValue = SwappingWireValue<T>;
|
||||
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
|
||||
// linked together, we define each implementation with a different name and define an alias to the
|
||||
// one we want to use.
|
||||
|
||||
#else
|
||||
// Unknown endianness. Fall back to bit shifts.
|
||||
|
||||
#if !CAPNP_DISABLE_ENDIAN_DETECTION
|
||||
#if _MSC_VER
|
||||
#pragma message("Couldn't detect endianness of your platform. Using unoptimized fallback implementation.")
|
||||
#pragma message("Consider changing this code to detect your platform and send us a patch!")
|
||||
#else
|
||||
#warning "Couldn't detect endianness of your platform. Using unoptimized fallback implementation."
|
||||
#warning "Consider changing this code to detect your platform and send us a patch!"
|
||||
#endif
|
||||
#endif // !CAPNP_DISABLE_ENDIAN_DETECTION
|
||||
|
||||
template <typename T, size_t size = sizeof(T)>
|
||||
class ShiftingWireValue;
|
||||
|
||||
template <typename T>
|
||||
class ShiftingWireValue<T, 1> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) { return value; }
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) { value = newValue; }
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ShiftingWireValue<T, 2> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
uint16_t raw = (static_cast<uint16_t>(bytes[0]) ) |
|
||||
(static_cast<uint16_t>(bytes[1]) << 8);
|
||||
T result;
|
||||
memcpy(&result, &raw, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint16_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
bytes[0] = raw;
|
||||
bytes[1] = raw >> 8;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
byte bytes[2];
|
||||
uint16_t align;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ShiftingWireValue<T, 4> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
uint32_t raw = (static_cast<uint32_t>(bytes[0]) ) |
|
||||
(static_cast<uint32_t>(bytes[1]) << 8) |
|
||||
(static_cast<uint32_t>(bytes[2]) << 16) |
|
||||
(static_cast<uint32_t>(bytes[3]) << 24);
|
||||
T result;
|
||||
memcpy(&result, &raw, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint32_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
bytes[0] = raw;
|
||||
bytes[1] = raw >> 8;
|
||||
bytes[2] = raw >> 16;
|
||||
bytes[3] = raw >> 24;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
byte bytes[4];
|
||||
uint32_t align;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ShiftingWireValue<T, 8> {
|
||||
public:
|
||||
KJ_ALWAYS_INLINE(T get() const) {
|
||||
uint64_t raw = (static_cast<uint64_t>(bytes[0]) ) |
|
||||
(static_cast<uint64_t>(bytes[1]) << 8) |
|
||||
(static_cast<uint64_t>(bytes[2]) << 16) |
|
||||
(static_cast<uint64_t>(bytes[3]) << 24) |
|
||||
(static_cast<uint64_t>(bytes[4]) << 32) |
|
||||
(static_cast<uint64_t>(bytes[5]) << 40) |
|
||||
(static_cast<uint64_t>(bytes[6]) << 48) |
|
||||
(static_cast<uint64_t>(bytes[7]) << 56);
|
||||
T result;
|
||||
memcpy(&result, &raw, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
KJ_ALWAYS_INLINE(void set(T newValue)) {
|
||||
uint64_t raw;
|
||||
memcpy(&raw, &newValue, sizeof(T));
|
||||
bytes[0] = raw;
|
||||
bytes[1] = raw >> 8;
|
||||
bytes[2] = raw >> 16;
|
||||
bytes[3] = raw >> 24;
|
||||
bytes[4] = raw >> 32;
|
||||
bytes[5] = raw >> 40;
|
||||
bytes[6] = raw >> 48;
|
||||
bytes[7] = raw >> 56;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
byte bytes[8];
|
||||
uint64_t align;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using WireValue = ShiftingWireValue<T>;
|
||||
// To prevent ODR problems when endian-test, endian-reverse-test, and endian-fallback-test are
|
||||
// linked together, we define each implementation with a different name and define an alias to the
|
||||
// one we want to use.
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
// 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.
|
||||
|
||||
// This file is included from all generated headers.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "raw-schema.h"
|
||||
#include "layout.h"
|
||||
#include "list.h"
|
||||
#include "orphan.h"
|
||||
#include "pointer-helpers.h"
|
||||
#include "any.h"
|
||||
#include <kj/string.h>
|
||||
#include <kj/string-tree.h>
|
||||
#include <kj/hash.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class MessageBuilder; // So that it can be declared a friend.
|
||||
|
||||
template <typename T, Kind k = CAPNP_KIND(T)>
|
||||
struct ToDynamic_; // Defined in dynamic.h, needs to be declared as everyone's friend.
|
||||
|
||||
struct DynamicStruct; // So that it can be declared a friend.
|
||||
|
||||
struct Capability; // To declare brandBindingFor<Capability>()
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
#if !CAPNP_LITE
|
||||
|
||||
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate, bool = false>
|
||||
inline const RawSchema& rawSchema() {
|
||||
return *CapnpPrivate::schema;
|
||||
}
|
||||
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
|
||||
inline const RawSchema& rawSchema() {
|
||||
return *schemas::EnumInfo<T>::schema;
|
||||
}
|
||||
|
||||
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
|
||||
inline const RawBrandedSchema& rawBrandedSchema() {
|
||||
return *CapnpPrivate::brand();
|
||||
}
|
||||
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
|
||||
inline const RawBrandedSchema& rawBrandedSchema() {
|
||||
return schemas::EnumInfo<T>::schema->defaultBrand;
|
||||
}
|
||||
|
||||
template <typename TypeTag, typename... Params>
|
||||
struct ChooseBrand;
|
||||
// If all of `Params` are `AnyPointer`, return the type's default brand. Otherwise, return a
|
||||
// specific brand instance. TypeTag is the _capnpPrivate struct for the type in question.
|
||||
|
||||
template <typename TypeTag>
|
||||
struct ChooseBrand<TypeTag> {
|
||||
// All params were AnyPointer. No specific brand needed.
|
||||
static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::schema->defaultBrand; }
|
||||
};
|
||||
|
||||
template <typename TypeTag, typename... Rest>
|
||||
struct ChooseBrand<TypeTag, AnyPointer, Rest...>: public ChooseBrand<TypeTag, Rest...> {};
|
||||
// The first parameter is AnyPointer, so recurse to check the rest.
|
||||
|
||||
template <typename TypeTag, typename First, typename... Rest>
|
||||
struct ChooseBrand<TypeTag, First, Rest...> {
|
||||
// At least one parameter is not AnyPointer, so use the specificBrand constant.
|
||||
static constexpr _::RawBrandedSchema const* brand() { return &TypeTag::specificBrand; }
|
||||
};
|
||||
|
||||
template <typename T, Kind k = kind<T>()>
|
||||
struct BrandBindingFor_;
|
||||
|
||||
#define HANDLE_TYPE(Type, which) \
|
||||
template <> \
|
||||
struct BrandBindingFor_<Type, Kind::PRIMITIVE> { \
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) { \
|
||||
return { which, listDepth, nullptr }; \
|
||||
} \
|
||||
}
|
||||
HANDLE_TYPE(Void, 0);
|
||||
HANDLE_TYPE(bool, 1);
|
||||
HANDLE_TYPE(int8_t, 2);
|
||||
HANDLE_TYPE(int16_t, 3);
|
||||
HANDLE_TYPE(int32_t, 4);
|
||||
HANDLE_TYPE(int64_t, 5);
|
||||
HANDLE_TYPE(uint8_t, 6);
|
||||
HANDLE_TYPE(uint16_t, 7);
|
||||
HANDLE_TYPE(uint32_t, 8);
|
||||
HANDLE_TYPE(uint64_t, 9);
|
||||
HANDLE_TYPE(float, 10);
|
||||
HANDLE_TYPE(double, 11);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<Text, Kind::BLOB> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 12, listDepth, nullptr };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<Data, Kind::BLOB> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 13, listDepth, nullptr };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BrandBindingFor_<List<T>, Kind::LIST> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return BrandBindingFor_<T>::get(listDepth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BrandBindingFor_<T, Kind::ENUM> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 15, listDepth, &rawSchema<T>().defaultBrand };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BrandBindingFor_<T, Kind::STRUCT> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 16, listDepth, T::_capnpPrivate::brand() };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BrandBindingFor_<T, Kind::INTERFACE> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 17, listDepth, T::_capnpPrivate::brand() };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<AnyPointer, Kind::OTHER> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 18, listDepth, 0, 0 };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<AnyStruct, Kind::OTHER> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 18, listDepth, 0, 1 };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<AnyList, Kind::OTHER> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 18, listDepth, 0, 2 };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct BrandBindingFor_<Capability, Kind::OTHER> {
|
||||
static constexpr RawBrandedSchema::Binding get(uint16_t listDepth) {
|
||||
return { 18, listDepth, 0, 3 };
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr RawBrandedSchema::Binding brandBindingFor() {
|
||||
return BrandBindingFor_<T>::get(0);
|
||||
}
|
||||
|
||||
kj::StringTree structString(StructReader reader, const RawBrandedSchema& schema);
|
||||
kj::String enumString(uint16_t value, const RawBrandedSchema& schema);
|
||||
// Declared here so that we can declare inline stringify methods on generated types.
|
||||
// Defined in stringify.c++, which depends on dynamic.c++, which is allowed not to be linked in.
|
||||
|
||||
template <typename T>
|
||||
inline kj::StringTree structString(StructReader reader) {
|
||||
return structString(reader, rawBrandedSchema<T>());
|
||||
}
|
||||
template <typename T>
|
||||
inline kj::String enumString(T value) {
|
||||
return enumString(static_cast<uint16_t>(value), rawBrandedSchema<T>());
|
||||
}
|
||||
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// TODO(cleanup): Unify ConstStruct and ConstList.
|
||||
template <typename T>
|
||||
class ConstStruct {
|
||||
public:
|
||||
ConstStruct() = delete;
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ConstStruct);
|
||||
inline explicit constexpr ConstStruct(const word* ptr): ptr(ptr) {}
|
||||
|
||||
inline typename T::Reader get() const {
|
||||
return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<T>();
|
||||
}
|
||||
|
||||
inline operator typename T::Reader() const { return get(); }
|
||||
inline typename T::Reader operator*() const { return get(); }
|
||||
inline TemporaryPointer<typename T::Reader> operator->() const { return get(); }
|
||||
|
||||
private:
|
||||
const word* ptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ConstList {
|
||||
public:
|
||||
ConstList() = delete;
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ConstList);
|
||||
inline explicit constexpr ConstList(const word* ptr): ptr(ptr) {}
|
||||
|
||||
inline typename List<T>::Reader get() const {
|
||||
return AnyPointer::Reader(PointerReader::getRootUnchecked(ptr)).getAs<List<T>>();
|
||||
}
|
||||
|
||||
inline operator typename List<T>::Reader() const { return get(); }
|
||||
inline typename List<T>::Reader operator*() const { return get(); }
|
||||
inline TemporaryPointer<typename List<T>::Reader> operator->() const { return get(); }
|
||||
|
||||
private:
|
||||
const word* ptr;
|
||||
};
|
||||
|
||||
template <size_t size>
|
||||
class ConstText {
|
||||
public:
|
||||
ConstText() = delete;
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ConstText);
|
||||
inline explicit constexpr ConstText(const word* ptr): ptr(ptr) {}
|
||||
|
||||
inline Text::Reader get() const {
|
||||
return Text::Reader(reinterpret_cast<const char*>(ptr), size);
|
||||
}
|
||||
|
||||
inline operator Text::Reader() const { return get(); }
|
||||
inline Text::Reader operator*() const { return get(); }
|
||||
inline TemporaryPointer<Text::Reader> operator->() const { return get(); }
|
||||
|
||||
inline kj::StringPtr toString() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
const word* ptr;
|
||||
};
|
||||
|
||||
template <size_t size>
|
||||
inline kj::StringPtr KJ_STRINGIFY(const ConstText<size>& s) {
|
||||
return s.get();
|
||||
}
|
||||
|
||||
template <size_t size>
|
||||
class ConstData {
|
||||
public:
|
||||
ConstData() = delete;
|
||||
KJ_DISALLOW_COPY_AND_MOVE(ConstData);
|
||||
inline explicit constexpr ConstData(const word* ptr): ptr(ptr) {}
|
||||
|
||||
inline Data::Reader get() const {
|
||||
return Data::Reader(reinterpret_cast<const byte*>(ptr), size);
|
||||
}
|
||||
|
||||
inline operator Data::Reader() const { return get(); }
|
||||
inline Data::Reader operator*() const { return get(); }
|
||||
inline TemporaryPointer<Data::Reader> operator->() const { return get(); }
|
||||
|
||||
private:
|
||||
const word* ptr;
|
||||
};
|
||||
|
||||
template <size_t size>
|
||||
inline auto KJ_STRINGIFY(const ConstData<size>& s) -> decltype(kj::toCharSequence(s.get())) {
|
||||
return kj::toCharSequence(s.get());
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
|
||||
inline constexpr uint64_t typeId() { return CapnpPrivate::typeId; }
|
||||
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
|
||||
inline constexpr uint64_t typeId() { return id; }
|
||||
// typeId<MyType>() returns the type ID as defined in the schema. Works with structs, enums, and
|
||||
// interfaces.
|
||||
|
||||
template <typename T>
|
||||
inline constexpr uint sizeInWords() {
|
||||
// Return the size, in words, of a Struct type, if allocated free-standing (not in a list).
|
||||
// May be useful for pre-computing space needed in order to precisely allocate messages.
|
||||
|
||||
return unbound((upgradeBound<uint>(_::structSize<T>().data) +
|
||||
_::structSize<T>().pointers * WORDS_PER_POINTER) / WORDS);
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
// MSVC doesn't understand floating-point constexpr yet.
|
||||
//
|
||||
// TODO(msvc): Remove this hack when MSVC is fixed.
|
||||
#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value)
|
||||
#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value) = value
|
||||
#else
|
||||
#define CAPNP_NON_INT_CONSTEXPR_DECL_INIT(value) = value
|
||||
#define CAPNP_NON_INT_CONSTEXPR_DEF_INIT(value)
|
||||
#endif
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
// TODO(msvc): A little hack to allow MSVC to use C++14 return type deduction in cases where the
|
||||
// explicit type exposes bugs in the compiler.
|
||||
#define CAPNP_AUTO_IF_MSVC(...) auto
|
||||
#else
|
||||
#define CAPNP_AUTO_IF_MSVC(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
// TODO(msvc): MSVC does not even expect constexprs to have definitions below C++17.
|
||||
#if (__cplusplus < 201703L) && !(defined(_MSC_VER) && !defined(__clang__))
|
||||
#define CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL 1
|
||||
#else
|
||||
#define CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL 0
|
||||
#endif
|
||||
|
||||
#if CAPNP_LITE
|
||||
|
||||
#define CAPNP_DECLARE_SCHEMA(id) \
|
||||
extern ::capnp::word const* const bp_##id
|
||||
|
||||
#define CAPNP_DECLARE_ENUM(type, id) \
|
||||
inline ::kj::String KJ_STRINGIFY(type##_##id value) { \
|
||||
return ::kj::str(static_cast<uint16_t>(value)); \
|
||||
} \
|
||||
template <> struct EnumInfo<type##_##id> { \
|
||||
struct IsEnum; \
|
||||
static constexpr uint64_t typeId = 0x##id; \
|
||||
static inline ::capnp::word const* encodedSchema() { return bp_##id; } \
|
||||
}
|
||||
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#define CAPNP_DEFINE_ENUM(type, id) \
|
||||
constexpr uint64_t EnumInfo<type>::typeId
|
||||
#else
|
||||
#define CAPNP_DEFINE_ENUM(type, id)
|
||||
#endif
|
||||
|
||||
#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \
|
||||
struct IsStruct; \
|
||||
static constexpr uint64_t typeId = 0x##id; \
|
||||
static constexpr uint16_t dataWordSize = dataWordSize_; \
|
||||
static constexpr uint16_t pointerCount = pointerCount_; \
|
||||
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; }
|
||||
|
||||
#else // CAPNP_LITE
|
||||
|
||||
#define CAPNP_DECLARE_SCHEMA(id) \
|
||||
extern ::capnp::word const* const bp_##id; \
|
||||
extern const ::capnp::_::RawSchema s_##id
|
||||
|
||||
#define CAPNP_DECLARE_ENUM(type, id) \
|
||||
inline ::kj::String KJ_STRINGIFY(type##_##id value) { \
|
||||
return ::capnp::_::enumString(value); \
|
||||
} \
|
||||
template <> struct EnumInfo<type##_##id> { \
|
||||
struct IsEnum; \
|
||||
static constexpr uint64_t typeId = 0x##id; \
|
||||
static inline ::capnp::word const* encodedSchema() { return bp_##id; } \
|
||||
static constexpr ::capnp::_::RawSchema const* schema = &s_##id; \
|
||||
}
|
||||
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#define CAPNP_DEFINE_ENUM(type, id) \
|
||||
constexpr uint64_t EnumInfo<type>::typeId; \
|
||||
constexpr ::capnp::_::RawSchema const* EnumInfo<type>::schema
|
||||
#else
|
||||
#define CAPNP_DEFINE_ENUM(type, id)
|
||||
#endif
|
||||
|
||||
#define CAPNP_DECLARE_STRUCT_HEADER(id, dataWordSize_, pointerCount_) \
|
||||
struct IsStruct; \
|
||||
static constexpr uint64_t typeId = 0x##id; \
|
||||
static constexpr ::capnp::Kind kind = ::capnp::Kind::STRUCT; \
|
||||
static constexpr uint16_t dataWordSize = dataWordSize_; \
|
||||
static constexpr uint16_t pointerCount = pointerCount_; \
|
||||
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \
|
||||
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id;
|
||||
|
||||
#define CAPNP_DECLARE_INTERFACE_HEADER(id) \
|
||||
struct IsInterface; \
|
||||
static constexpr uint64_t typeId = 0x##id; \
|
||||
static constexpr ::capnp::Kind kind = ::capnp::Kind::INTERFACE; \
|
||||
static inline ::capnp::word const* encodedSchema() { return ::capnp::schemas::bp_##id; } \
|
||||
static constexpr ::capnp::_::RawSchema const* schema = &::capnp::schemas::s_##id;
|
||||
|
||||
#endif // CAPNP_LITE, else
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
CAPNP_DECLARE_SCHEMA(995f9a3377c0b16e);
|
||||
// HACK: Forward-declare the RawSchema for StreamResult, from stream.capnp. This allows capnp
|
||||
// files which declare streaming methods to avoid including stream.capnp.h.
|
||||
}
|
||||
}
|
||||
|
||||
CAPNP_END_HEADER
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,26 @@
|
|||
// 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.
|
||||
|
||||
#include "list.h"
|
||||
|
||||
namespace capnp {
|
||||
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,552 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "layout.h"
|
||||
#include "orphan.h"
|
||||
#include <initializer_list>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
class TemporaryPointer {
|
||||
// This class is a little hack which lets us define operator->() in cases where it needs to
|
||||
// return a pointer to a temporary value. We instead construct a TemporaryPointer and return that
|
||||
// (by value). The compiler then invokes operator->() on the TemporaryPointer, which itself is
|
||||
// able to return a real pointer to its member.
|
||||
|
||||
public:
|
||||
TemporaryPointer(T&& value): value(kj::mv(value)) {}
|
||||
TemporaryPointer(const T& value): value(value) {}
|
||||
|
||||
inline T* operator->() { return &value; }
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
|
||||
// By default this isn't compatible with STL algorithms. To add STL support either define
|
||||
// KJ_STD_COMPAT at the top of your compilation unit or include capnp/compat/std-iterator.h.
|
||||
template <typename Container, typename Element>
|
||||
class IndexingIterator {
|
||||
public:
|
||||
IndexingIterator() = default;
|
||||
|
||||
inline Element operator*() const { return (*container)[index]; }
|
||||
inline TemporaryPointer<Element> operator->() const {
|
||||
return TemporaryPointer<Element>((*container)[index]);
|
||||
}
|
||||
inline Element operator[]( int off) const { return (*container)[index]; }
|
||||
inline Element operator[](uint off) const { return (*container)[index]; }
|
||||
|
||||
inline IndexingIterator& operator++() { ++index; return *this; }
|
||||
inline IndexingIterator operator++(int) { IndexingIterator other = *this; ++index; return other; }
|
||||
inline IndexingIterator& operator--() { --index; return *this; }
|
||||
inline IndexingIterator operator--(int) { IndexingIterator other = *this; --index; return other; }
|
||||
|
||||
inline IndexingIterator operator+(uint amount) const { return IndexingIterator(container, index + amount); }
|
||||
inline IndexingIterator operator-(uint amount) const { return IndexingIterator(container, index - amount); }
|
||||
inline IndexingIterator operator+( int amount) const { return IndexingIterator(container, index + amount); }
|
||||
inline IndexingIterator operator-( int amount) const { return IndexingIterator(container, index - amount); }
|
||||
|
||||
inline int operator-(const IndexingIterator& other) const { return index - other.index; }
|
||||
|
||||
inline IndexingIterator& operator+=(uint amount) { index += amount; return *this; }
|
||||
inline IndexingIterator& operator-=(uint amount) { index -= amount; return *this; }
|
||||
inline IndexingIterator& operator+=( int amount) { index += amount; return *this; }
|
||||
inline IndexingIterator& operator-=( int amount) { index -= amount; return *this; }
|
||||
|
||||
// STL says comparing iterators of different containers is not allowed, so we only compare
|
||||
// indices here.
|
||||
inline bool operator==(const IndexingIterator& other) const { return index == other.index; }
|
||||
inline bool operator!=(const IndexingIterator& other) const { return index != other.index; }
|
||||
inline bool operator<=(const IndexingIterator& other) const { return index <= other.index; }
|
||||
inline bool operator>=(const IndexingIterator& other) const { return index >= other.index; }
|
||||
inline bool operator< (const IndexingIterator& other) const { return index < other.index; }
|
||||
inline bool operator> (const IndexingIterator& other) const { return index > other.index; }
|
||||
|
||||
private:
|
||||
Container* container;
|
||||
uint index;
|
||||
|
||||
friend Container;
|
||||
inline IndexingIterator(Container* container, uint index)
|
||||
: container(container), index(index) {}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T>
|
||||
struct List<T, Kind::PRIMITIVE> {
|
||||
// List of primitives.
|
||||
|
||||
List() = delete;
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
typedef List<T> Reads;
|
||||
|
||||
inline Reader(): reader(_::elementSizeForType<T>()) {}
|
||||
inline explicit Reader(_::ListReader reader): reader(reader) {}
|
||||
|
||||
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
|
||||
inline T operator[](uint index) const {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return reader.template getDataElement<T>(bounded(index) * ELEMENTS);
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<const Reader, T> Iterator;
|
||||
inline Iterator begin() const { return Iterator(this, 0); }
|
||||
inline Iterator end() const { return Iterator(this, size()); }
|
||||
|
||||
inline MessageSize totalSize() const {
|
||||
return reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
private:
|
||||
_::ListReader reader;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
template <typename U, Kind K>
|
||||
friend struct List;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
typedef List<T> Builds;
|
||||
|
||||
inline Builder(): builder(_::elementSizeForType<T>()) {}
|
||||
inline Builder(decltype(nullptr)): Builder() {}
|
||||
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
|
||||
|
||||
inline operator Reader() const { return Reader(builder.asReader()); }
|
||||
inline Reader asReader() const { return Reader(builder.asReader()); }
|
||||
|
||||
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
|
||||
inline T operator[](uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return builder.template getDataElement<T>(bounded(index) * ELEMENTS);
|
||||
}
|
||||
inline void set(uint index, T value) {
|
||||
// Alas, it is not possible to make operator[] return a reference to which you can assign,
|
||||
// since the encoded representation does not necessarily match the compiler's representation
|
||||
// of the type. We can't even return a clever class that implements operator T() and
|
||||
// operator=() because it will lead to surprising behavior when using type inference (e.g.
|
||||
// calling a template function with inferred argument types, or using "auto" or "decltype").
|
||||
|
||||
builder.template setDataElement<T>(bounded(index) * ELEMENTS, value);
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<Builder, T> Iterator;
|
||||
inline Iterator begin() { return Iterator(this, 0); }
|
||||
inline Iterator end() { return Iterator(this, size()); }
|
||||
|
||||
private:
|
||||
_::ListBuilder builder;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Pipeline {};
|
||||
|
||||
private:
|
||||
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
|
||||
return builder.initList(_::elementSizeForType<T>(), bounded(size) * ELEMENTS);
|
||||
}
|
||||
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
|
||||
return builder.getList(_::elementSizeForType<T>(), defaultValue);
|
||||
}
|
||||
inline static _::ListReader getFromPointer(
|
||||
const _::PointerReader& reader, const word* defaultValue) {
|
||||
return reader.getList(_::elementSizeForType<T>(), defaultValue);
|
||||
}
|
||||
|
||||
template <typename U, Kind k>
|
||||
friend struct List;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct List<T, Kind::ENUM>: public List<T, Kind::PRIMITIVE> {};
|
||||
|
||||
template <typename T>
|
||||
struct List<T, Kind::STRUCT> {
|
||||
// List of structs.
|
||||
|
||||
List() = delete;
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
typedef List<T> Reads;
|
||||
|
||||
inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {}
|
||||
inline explicit Reader(_::ListReader reader): reader(reader) {}
|
||||
|
||||
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
|
||||
inline typename T::Reader operator[](uint index) const {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return typename T::Reader(reader.getStructElement(bounded(index) * ELEMENTS));
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
|
||||
inline Iterator begin() const { return Iterator(this, 0); }
|
||||
inline Iterator end() const { return Iterator(this, size()); }
|
||||
|
||||
inline MessageSize totalSize() const {
|
||||
return reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
private:
|
||||
_::ListReader reader;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
template <typename U, Kind K>
|
||||
friend struct List;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
typedef List<T> Builds;
|
||||
|
||||
inline Builder(): builder(ElementSize::INLINE_COMPOSITE) {}
|
||||
inline Builder(decltype(nullptr)): Builder() {}
|
||||
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
|
||||
|
||||
inline operator Reader() const { return Reader(builder.asReader()); }
|
||||
inline Reader asReader() const { return Reader(builder.asReader()); }
|
||||
|
||||
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
|
||||
inline typename T::Builder operator[](uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return typename T::Builder(builder.getStructElement(bounded(index) * ELEMENTS));
|
||||
}
|
||||
|
||||
inline void adoptWithCaveats(uint index, Orphan<T>&& orphan) {
|
||||
// Mostly behaves like you'd expect `adopt` to behave, but with two caveats originating from
|
||||
// the fact that structs in a struct list are allocated inline rather than by pointer:
|
||||
// * This actually performs a shallow copy, effectively adopting each of the orphan's
|
||||
// children rather than adopting the orphan itself. The orphan ends up being discarded,
|
||||
// possibly wasting space in the message object.
|
||||
// * If the orphan is larger than the target struct -- say, because the orphan was built
|
||||
// using a newer version of the schema that has additional fields -- it will be truncated,
|
||||
// losing data.
|
||||
|
||||
KJ_IREQUIRE(index < size());
|
||||
|
||||
// We pass a zero-valued StructSize to asStruct() because we do not want the struct to be
|
||||
// expanded under any circumstances. We're just going to throw it away anyway, and
|
||||
// transferContentFrom() already carefully compares the struct sizes before transferring.
|
||||
builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom(
|
||||
orphan.builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS)));
|
||||
}
|
||||
inline void setWithCaveats(uint index, const typename T::Reader& reader) {
|
||||
// Mostly behaves like you'd expect `set` to behave, but with a caveat originating from
|
||||
// the fact that structs in a struct list are allocated inline rather than by pointer:
|
||||
// If the source struct is larger than the target struct -- say, because the source was built
|
||||
// using a newer version of the schema that has additional fields -- it will be truncated,
|
||||
// losing data.
|
||||
//
|
||||
// Note: If you are trying to concatenate some lists, use Orphanage::newOrphanConcat() to
|
||||
// do it without losing any data in case the source lists come from a newer version of the
|
||||
// protocol. (Plus, it's easier to use anyhow.)
|
||||
|
||||
KJ_IREQUIRE(index < size());
|
||||
builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(reader._reader);
|
||||
}
|
||||
|
||||
// There are no init(), set(), adopt(), or disown() methods for lists of structs because the
|
||||
// elements of the list are inlined and are initialized when the list is initialized. This
|
||||
// means that init() would be redundant, and set() would risk data loss if the input struct
|
||||
// were from a newer version of the protocol.
|
||||
|
||||
typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
|
||||
inline Iterator begin() { return Iterator(this, 0); }
|
||||
inline Iterator end() { return Iterator(this, size()); }
|
||||
|
||||
private:
|
||||
_::ListBuilder builder;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Pipeline {};
|
||||
|
||||
private:
|
||||
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
|
||||
return builder.initStructList(bounded(size) * ELEMENTS, _::structSize<T>());
|
||||
}
|
||||
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
|
||||
return builder.getStructList(_::structSize<T>(), defaultValue);
|
||||
}
|
||||
inline static _::ListReader getFromPointer(
|
||||
const _::PointerReader& reader, const word* defaultValue) {
|
||||
return reader.getList(ElementSize::INLINE_COMPOSITE, defaultValue);
|
||||
}
|
||||
|
||||
template <typename U, Kind k>
|
||||
friend struct List;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct List<List<T>, Kind::LIST> {
|
||||
// List of lists.
|
||||
|
||||
List() = delete;
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
typedef List<List<T>> Reads;
|
||||
|
||||
inline Reader(): reader(ElementSize::POINTER) {}
|
||||
inline explicit Reader(_::ListReader reader): reader(reader) {}
|
||||
|
||||
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
|
||||
inline typename List<T>::Reader operator[](uint index) const {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return typename List<T>::Reader(_::PointerHelpers<List<T>>::get(
|
||||
reader.getPointerElement(bounded(index) * ELEMENTS)));
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<const Reader, typename List<T>::Reader> Iterator;
|
||||
inline Iterator begin() const { return Iterator(this, 0); }
|
||||
inline Iterator end() const { return Iterator(this, size()); }
|
||||
|
||||
inline MessageSize totalSize() const {
|
||||
return reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
private:
|
||||
_::ListReader reader;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
template <typename U, Kind K>
|
||||
friend struct List;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
typedef List<List<T>> Builds;
|
||||
|
||||
inline Builder(): builder(ElementSize::POINTER) {}
|
||||
inline Builder(decltype(nullptr)): Builder() {}
|
||||
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
|
||||
|
||||
inline operator Reader() const { return Reader(builder.asReader()); }
|
||||
inline Reader asReader() const { return Reader(builder.asReader()); }
|
||||
|
||||
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
|
||||
inline typename List<T>::Builder operator[](uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return typename List<T>::Builder(_::PointerHelpers<List<T>>::get(
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS)));
|
||||
}
|
||||
inline typename List<T>::Builder init(uint index, uint size) {
|
||||
KJ_IREQUIRE(index < this->size());
|
||||
return typename List<T>::Builder(_::PointerHelpers<List<T>>::init(
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS), size));
|
||||
}
|
||||
inline void set(uint index, typename List<T>::Reader value) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS).setList(value.reader);
|
||||
}
|
||||
void set(uint index, std::initializer_list<ReaderFor<T>> value) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
auto l = init(index, value.size());
|
||||
uint i = 0;
|
||||
for (auto& element: value) {
|
||||
l.set(i++, element);
|
||||
}
|
||||
}
|
||||
inline void adopt(uint index, Orphan<List<T>>&& value) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder));
|
||||
}
|
||||
inline Orphan<List<T>> disown(uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return Orphan<List<T>>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<Builder, typename List<T>::Builder> Iterator;
|
||||
inline Iterator begin() { return Iterator(this, 0); }
|
||||
inline Iterator end() { return Iterator(this, size()); }
|
||||
|
||||
private:
|
||||
_::ListBuilder builder;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Pipeline {};
|
||||
|
||||
private:
|
||||
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
|
||||
return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
|
||||
}
|
||||
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
|
||||
return builder.getList(ElementSize::POINTER, defaultValue);
|
||||
}
|
||||
inline static _::ListReader getFromPointer(
|
||||
const _::PointerReader& reader, const word* defaultValue) {
|
||||
return reader.getList(ElementSize::POINTER, defaultValue);
|
||||
}
|
||||
|
||||
template <typename U, Kind k>
|
||||
friend struct List;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct List<T, Kind::BLOB> {
|
||||
List() = delete;
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
typedef List<T> Reads;
|
||||
|
||||
inline Reader(): reader(ElementSize::POINTER) {}
|
||||
inline explicit Reader(_::ListReader reader): reader(reader) {}
|
||||
|
||||
inline uint size() const { return unbound(reader.size() / ELEMENTS); }
|
||||
inline typename T::Reader operator[](uint index) const {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return reader.getPointerElement(bounded(index) * ELEMENTS)
|
||||
.template getBlob<T>(nullptr, ZERO * BYTES);
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<const Reader, typename T::Reader> Iterator;
|
||||
inline Iterator begin() const { return Iterator(this, 0); }
|
||||
inline Iterator end() const { return Iterator(this, size()); }
|
||||
|
||||
inline MessageSize totalSize() const {
|
||||
return reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
private:
|
||||
_::ListReader reader;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
template <typename U, Kind K>
|
||||
friend struct List;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
typedef List<T> Builds;
|
||||
|
||||
inline Builder(): builder(ElementSize::POINTER) {}
|
||||
inline Builder(decltype(nullptr)): Builder() {}
|
||||
inline explicit Builder(_::ListBuilder builder): builder(builder) {}
|
||||
|
||||
inline operator Reader() const { return Reader(builder.asReader()); }
|
||||
inline Reader asReader() const { return Reader(builder.asReader()); }
|
||||
|
||||
inline uint size() const { return unbound(builder.size() / ELEMENTS); }
|
||||
inline typename T::Builder operator[](uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return builder.getPointerElement(bounded(index) * ELEMENTS)
|
||||
.template getBlob<T>(nullptr, ZERO * BYTES);
|
||||
}
|
||||
inline void set(uint index, typename T::Reader value) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS).template setBlob<T>(value);
|
||||
}
|
||||
inline typename T::Builder init(uint index, uint size) {
|
||||
KJ_IREQUIRE(index < this->size());
|
||||
return builder.getPointerElement(bounded(index) * ELEMENTS)
|
||||
.template initBlob<T>(bounded(size) * BYTES);
|
||||
}
|
||||
inline void adopt(uint index, Orphan<T>&& value) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value.builder));
|
||||
}
|
||||
inline Orphan<T> disown(uint index) {
|
||||
KJ_IREQUIRE(index < size());
|
||||
return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
|
||||
}
|
||||
|
||||
typedef _::IndexingIterator<Builder, typename T::Builder> Iterator;
|
||||
inline Iterator begin() { return Iterator(this, 0); }
|
||||
inline Iterator end() { return Iterator(this, size()); }
|
||||
|
||||
private:
|
||||
_::ListBuilder builder;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
friend class Orphanage;
|
||||
template <typename U, Kind K>
|
||||
friend struct ToDynamic_;
|
||||
};
|
||||
|
||||
class Pipeline {};
|
||||
|
||||
private:
|
||||
inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
|
||||
return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
|
||||
}
|
||||
inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
|
||||
return builder.getList(ElementSize::POINTER, defaultValue);
|
||||
}
|
||||
inline static _::ListReader getFromPointer(
|
||||
const _::PointerReader& reader, const word* defaultValue) {
|
||||
return reader.getList(ElementSize::POINTER, defaultValue);
|
||||
}
|
||||
|
||||
template <typename U, Kind k>
|
||||
friend struct List;
|
||||
template <typename U, Kind K>
|
||||
friend struct _::PointerHelpers;
|
||||
};
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
#ifdef KJ_STD_COMPAT
|
||||
#include "compat/std-iterator.h"
|
||||
#endif // KJ_STD_COMPAT
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
// Copyright (c) 2015 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.
|
||||
|
||||
#pragma once
|
||||
// In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards
|
||||
// calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a
|
||||
// membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely
|
||||
// introducing new objects.
|
||||
//
|
||||
// The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability
|
||||
// to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this
|
||||
// by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice
|
||||
// indicates it should be revoked, after which all calls through the wrapper will throw exceptions.
|
||||
// However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new
|
||||
// capability in that call, or if Carol returns a capability to Bob in the response to a call, then
|
||||
// the two are now able to communicate using this new capability, which Alice cannot revoke. In
|
||||
// order to avoid this problem, Alice must use not just a wrapper but a "membrane", which
|
||||
// recursively wraps all objects that pass through it in either direction. Thus, all connections
|
||||
// formed between Bob and Carol (originating from Alice's original introduction) can be revoked
|
||||
// together by revoking the membrane.
|
||||
//
|
||||
// Note that when a capability is passed into a membrane and then passed back out, the result is
|
||||
// the original capability, not a double-membraned capability. This means that in our revocation
|
||||
// example, if Bob uses his capability to Carol to obtain another capability from her, then send
|
||||
// it back to her, the capability Carol receives back will NOT be revoked when Bob's access to
|
||||
// Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use
|
||||
// cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then
|
||||
// passed back can be recognized as the original capability.
|
||||
//
|
||||
// Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html
|
||||
|
||||
#include "capability.h"
|
||||
#include <kj/map.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class MembranePolicy {
|
||||
// Applications may implement this interface to define a membrane policy, which allows some
|
||||
// calls crossing the membrane to be blocked or redirected.
|
||||
|
||||
public:
|
||||
virtual kj::Maybe<Capability::Client> inboundCall(
|
||||
uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
|
||||
// Given an inbound call (a call originating "outside" the membrane destined for an object
|
||||
// "inside" the membrane), decides what to do with it. The policy may:
|
||||
//
|
||||
// - Return null to indicate that the call should proceed to the destination. All capabilities
|
||||
// in the parameters or result will be properly wrapped in the same membrane.
|
||||
// - Return a capability to have the call redirected to that capability. Note that the redirect
|
||||
// capability will be treated as outside the membrane, so the params and results will not be
|
||||
// auto-wrapped; however, the callee can easily wrap the returned capability in the membrane
|
||||
// itself before returning to achieve this effect.
|
||||
// - Throw an exception to cause the call to fail with that exception.
|
||||
//
|
||||
// `target` is the underlying capability (*inside* the membrane) for which the call is destined.
|
||||
// Generally, the only way you should use `target` is to wrap it in some capability which you
|
||||
// return as a redirect. The redirect capability may modify the call in some way and send it to
|
||||
// `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when
|
||||
// copying parameters or results across the membrane.
|
||||
//
|
||||
// Note that since `target` is inside the capability, if you were to directly return it (rather
|
||||
// than return null), the effect would be that the membrane would be broken: the call would
|
||||
// proceed directly and any new capabilities introduced through it would not be membraned. You
|
||||
// generally should not do that.
|
||||
|
||||
virtual kj::Maybe<Capability::Client> outboundCall(
|
||||
uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0;
|
||||
// Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating
|
||||
// outside.
|
||||
//
|
||||
// Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases
|
||||
// that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would
|
||||
// redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run
|
||||
// into inconsistent behavion when a promise is returned across a membrane, and that promise
|
||||
// later resolves to a capability on the other side of the membrane: calls on the promise
|
||||
// will enter and then exit the membrane, but calls on the eventual resolution will not cross
|
||||
// the membrane at all, so it is important that these two cases behave the same.
|
||||
|
||||
virtual kj::Own<MembranePolicy> addRef() = 0;
|
||||
// Return a new owned pointer to the same policy.
|
||||
//
|
||||
// Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement
|
||||
// `addRef()` as `return kj::addRef(*this);`.
|
||||
//
|
||||
// Note that the membraning system considers two membranes created with the same MembranePolicy
|
||||
// object actually to be the *same* membrane. This is relevant when an object passes into the
|
||||
// membrane and then back out (or out and then back in): instead of double-wrapping the object,
|
||||
// the wrapping will be removed.
|
||||
|
||||
virtual kj::Maybe<kj::Promise<void>> onRevoked() { return nullptr; }
|
||||
// If this returns non-null, then it is a promise that will reject (throw an exception) when the
|
||||
// membrane should be revoked. On revocation, all capabilities pointing across the membrane will
|
||||
// be dropped and all outstanding calls canceled. The exception thrown by the promise will be
|
||||
// propagated to all these calls. It is an error for the promise to resolve without throwing.
|
||||
//
|
||||
// After the revocation promise has rejected, inboundCall() and outboundCall() will still be
|
||||
// invoked for new calls, but the `target` passed to them will be a capability that always
|
||||
// rethrows the revocation exception.
|
||||
|
||||
virtual bool shouldResolveBeforeRedirecting() { return false; }
|
||||
// If this returns true, then when inboundCall() or outboundCall() returns a redirect, but the
|
||||
// original target is a promise, then the membrane will discard the redirect and instead wait
|
||||
// for the promise to become more resolved and try again.
|
||||
//
|
||||
// This behavior is important in particular when implementing a membrane that wants to intercept
|
||||
// calls that would otherwise terminate inside the membrane, but needs to be careful not to
|
||||
// intercept calls that might be reflected back out of the membrane. If the promise eventually
|
||||
// resolves to a capability outside the membrane, then the call will be forwarded to that
|
||||
// capability without applying the policy at all.
|
||||
//
|
||||
// However, some membranes don't need this behavior, and may be negatively impacted by the
|
||||
// unnecessary waiting. Such membranes can keep this disabled.
|
||||
//
|
||||
// TODO(cleanup): Consider a backwards-incompatible revamp of the MembranePolicy API with a
|
||||
// better design here. Maybe we should more carefully distinguish between MembranePolicies
|
||||
// which are reversible vs. those which are one-way?
|
||||
|
||||
virtual bool allowFdPassthrough() { return false; }
|
||||
// Should file descriptors be allowed to pass through this membrane?
|
||||
//
|
||||
// A MembranePolicy obviously cannot mediate nor revoke access to a file descriptor once it has
|
||||
// passed through, so this must be used with caution. If you only want to allow file descriptors
|
||||
// on certain methods, you could do so by implementing inboundCall()/outboundCall() to
|
||||
// special-case those methods.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Control over importing and exporting.
|
||||
//
|
||||
// Most membranes should not override these methods. The default behavior is that a capability
|
||||
// that crosses the membrane is wrapped in it, and if the wrapped version crosses back the other
|
||||
// way, it is unwrapped.
|
||||
|
||||
virtual Capability::Client importExternal(Capability::Client external);
|
||||
// An external capability is crossing into the membrane. Returns the capability that should
|
||||
// substitute for it when called from the inside.
|
||||
//
|
||||
// The default implementation creates a capability that invokes this MembranePolicy. E.g. all
|
||||
// calls will invoke outboundCall().
|
||||
//
|
||||
// Note that reverseMembrane(cap, policy) normally calls policy->importExternal(cap), unless
|
||||
// `cap` itself was originally returned by the default implementation of exportInternal(), in
|
||||
// which case importInternal() is called instead.
|
||||
|
||||
virtual Capability::Client exportInternal(Capability::Client internal);
|
||||
// An internal capability is crossing out of the membrane. Returns the capability that should
|
||||
// substitute for it when called from the outside.
|
||||
//
|
||||
// The default implementation creates a capability that invokes this MembranePolicy. E.g. all
|
||||
// calls will invoke inboundCall().
|
||||
//
|
||||
// Note that membrane(cap, policy) normally calls policy->exportInternal(cap), unless `cap`
|
||||
// itself was originally returned by the default implementation of exportInternal(), in which
|
||||
// case importInternal() is called instead.
|
||||
|
||||
virtual MembranePolicy& rootPolicy() { return *this; }
|
||||
// If two policies return the same value for rootPolicy(), then a capability imported through
|
||||
// one can be exported through the other, and vice versa. `importInternal()` and
|
||||
// `exportExternal()` will always be called on the root policy, passing the two child policies
|
||||
// as parameters. If you don't override rootPolicy(), then the policy references passed to
|
||||
// importInternal() and exportExternal() will always be references to *this.
|
||||
|
||||
virtual Capability::Client importInternal(
|
||||
Capability::Client internal, MembranePolicy& exportPolicy, MembranePolicy& importPolicy);
|
||||
// An internal capability which was previously exported is now being re-imported, i.e. a
|
||||
// capability passed out of the membrane and then back in.
|
||||
//
|
||||
// The default implementation simply returns `internal`.
|
||||
|
||||
virtual Capability::Client exportExternal(
|
||||
Capability::Client external, MembranePolicy& importPolicy, MembranePolicy& exportPolicy);
|
||||
// An external capability which was previously imported is now being re-exported, i.e. a
|
||||
// capability passed into the membrane and then back out.
|
||||
//
|
||||
// The default implementation simply returns `external`.
|
||||
|
||||
private:
|
||||
kj::HashMap<ClientHook*, ClientHook*> wrappers;
|
||||
kj::HashMap<ClientHook*, ClientHook*> reverseWrappers;
|
||||
// Tracks capabilities that already have wrappers instantiated. The maps map from pointer to
|
||||
// inner capability to pointer to wrapper. When a wrapper is destroyed it removes itself from
|
||||
// the map.
|
||||
|
||||
friend class MembraneHook;
|
||||
};
|
||||
|
||||
Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy);
|
||||
// Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane,
|
||||
// while the returned capability should only be called from outside the membrane.
|
||||
|
||||
Capability::Client reverseMembrane(Capability::Client outer, kj::Own<MembranePolicy> policy);
|
||||
// Like `membrane` but treat the input capability as "outside" the membrane, and return a
|
||||
// capability appropriate for use inside.
|
||||
//
|
||||
// Applications typically won't use this directly; the membraning code automatically sets up
|
||||
// reverse membranes where needed.
|
||||
|
||||
template <typename ClientType>
|
||||
ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy);
|
||||
template <typename ClientType>
|
||||
ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy);
|
||||
// Convenience templates which return the same interface type as the input.
|
||||
|
||||
template <typename ServerType>
|
||||
typename ServerType::Serves::Client membrane(
|
||||
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
|
||||
template <typename ServerType>
|
||||
typename ServerType::Serves::Client reverseMembrane(
|
||||
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy);
|
||||
// Convenience templates which input a capability server type and return the appropriate client
|
||||
// type.
|
||||
|
||||
template <typename Reader>
|
||||
Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
|
||||
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
|
||||
// Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities
|
||||
// found within it. `from` is interpreted as "outside" the membrane while `to` is "inside".
|
||||
|
||||
template <typename Reader>
|
||||
Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
|
||||
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy);
|
||||
// Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside".
|
||||
|
||||
// =======================================================================================
|
||||
// inline implementation details
|
||||
|
||||
template <typename ClientType>
|
||||
ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy) {
|
||||
return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
|
||||
.castAs<typename ClientType::Calls>();
|
||||
}
|
||||
template <typename ClientType>
|
||||
ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy) {
|
||||
return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
|
||||
.castAs<typename ClientType::Calls>();
|
||||
}
|
||||
|
||||
template <typename ServerType>
|
||||
typename ServerType::Serves::Client membrane(
|
||||
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
|
||||
return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
|
||||
.castAs<typename ServerType::Serves>();
|
||||
}
|
||||
template <typename ServerType>
|
||||
typename ServerType::Serves::Client reverseMembrane(
|
||||
kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) {
|
||||
return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy))
|
||||
.castAs<typename ServerType::Serves>();
|
||||
}
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to,
|
||||
kj::Own<MembranePolicy> policy, bool reverse);
|
||||
OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to,
|
||||
kj::Own<MembranePolicy> policy, bool reverse);
|
||||
OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to,
|
||||
kj::Own<MembranePolicy> policy, bool reverse);
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename Reader>
|
||||
Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane(
|
||||
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
|
||||
return _::copyOutOfMembrane(
|
||||
_::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
|
||||
to, kj::mv(policy), true);
|
||||
}
|
||||
|
||||
template <typename Reader>
|
||||
Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane(
|
||||
Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) {
|
||||
return _::copyOutOfMembrane(
|
||||
_::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from),
|
||||
to, kj::mv(policy), false);
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
// Copyright (c) 2013-2016 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.
|
||||
|
||||
#define CAPNP_PRIVATE
|
||||
#include "message.h"
|
||||
#include <kj/debug.h>
|
||||
#include "arena.h"
|
||||
#include "orphan.h"
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace capnp {
|
||||
|
||||
namespace {
|
||||
|
||||
class DummyCapTableReader: public _::CapTableReader {
|
||||
public:
|
||||
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override {
|
||||
#if CAPNP_LITE
|
||||
KJ_UNIMPLEMENTED("no cap tables in lite mode");
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
static KJ_CONSTEXPR(const) DummyCapTableReader dummyCapTableReader = DummyCapTableReader();
|
||||
|
||||
} // namespace
|
||||
|
||||
MessageReader::MessageReader(ReaderOptions options): options(options), allocatedArena(false) {}
|
||||
MessageReader::~MessageReader() noexcept(false) {
|
||||
if (allocatedArena) {
|
||||
arena()->~ReaderArena();
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageReader::isCanonical() {
|
||||
if (!allocatedArena) {
|
||||
static_assert(sizeof(_::ReaderArena) <= sizeof(arenaSpace),
|
||||
"arenaSpace is too small to hold a ReaderArena. Please increase it. This will break "
|
||||
"ABI compatibility.");
|
||||
kj::ctor(*arena(), this);
|
||||
allocatedArena = true;
|
||||
}
|
||||
|
||||
_::SegmentReader *segment = arena()->tryGetSegment(_::SegmentId(0));
|
||||
|
||||
if (segment == NULL) {
|
||||
// The message has no segments
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena()->tryGetSegment(_::SegmentId(1))) {
|
||||
// The message has more than one segment
|
||||
return false;
|
||||
}
|
||||
|
||||
const word* readHead = segment->getStartPtr() + 1;
|
||||
bool rootIsCanonical = _::PointerReader::getRoot(segment, nullptr,
|
||||
segment->getStartPtr(),
|
||||
this->getOptions().nestingLimit)
|
||||
.isCanonical(&readHead);
|
||||
bool allWordsConsumed = segment->getOffsetTo(readHead) == segment->getSize();
|
||||
return rootIsCanonical && allWordsConsumed;
|
||||
}
|
||||
|
||||
size_t MessageReader::sizeInWords() {
|
||||
return arena()->sizeInWords();
|
||||
}
|
||||
|
||||
AnyPointer::Reader MessageReader::getRootInternal() {
|
||||
if (!allocatedArena) {
|
||||
static_assert(sizeof(_::ReaderArena) <= sizeof(arenaSpace),
|
||||
"arenaSpace is too small to hold a ReaderArena. Please increase it. This will break "
|
||||
"ABI compatibility.");
|
||||
kj::ctor(*arena(), this);
|
||||
allocatedArena = true;
|
||||
}
|
||||
|
||||
_::SegmentReader* segment = arena()->tryGetSegment(_::SegmentId(0));
|
||||
KJ_REQUIRE(segment != nullptr &&
|
||||
segment->checkObject(segment->getStartPtr(), ONE * WORDS),
|
||||
"Message did not contain a root pointer.") {
|
||||
return AnyPointer::Reader();
|
||||
}
|
||||
|
||||
// const_cast here is safe because dummyCapTableReader has no state.
|
||||
return AnyPointer::Reader(_::PointerReader::getRoot(
|
||||
segment, const_cast<DummyCapTableReader*>(&dummyCapTableReader),
|
||||
segment->getStartPtr(), options.nestingLimit));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
MessageBuilder::MessageBuilder(): allocatedArena(false) {}
|
||||
|
||||
MessageBuilder::~MessageBuilder() noexcept(false) {
|
||||
if (allocatedArena) {
|
||||
kj::dtor(*arena());
|
||||
}
|
||||
}
|
||||
|
||||
MessageBuilder::MessageBuilder(kj::ArrayPtr<SegmentInit> segments)
|
||||
: allocatedArena(false) {
|
||||
kj::ctor(*arena(), this, segments);
|
||||
allocatedArena = true;
|
||||
}
|
||||
|
||||
_::SegmentBuilder* MessageBuilder::getRootSegment() {
|
||||
if (allocatedArena) {
|
||||
return arena()->getSegment(_::SegmentId(0));
|
||||
} else {
|
||||
static_assert(sizeof(_::BuilderArena) <= sizeof(arenaSpace),
|
||||
"arenaSpace is too small to hold a BuilderArena. Please increase it.");
|
||||
kj::ctor(*arena(), this);
|
||||
allocatedArena = true;
|
||||
|
||||
auto allocation = arena()->allocate(POINTER_SIZE_IN_WORDS);
|
||||
|
||||
KJ_ASSERT(allocation.segment->getSegmentId() == _::SegmentId(0),
|
||||
"First allocated word of new arena was not in segment ID 0.");
|
||||
KJ_ASSERT(allocation.words == allocation.segment->getPtrUnchecked(ZERO * WORDS),
|
||||
"First allocated word of new arena was not the first word in its segment.");
|
||||
return allocation.segment;
|
||||
}
|
||||
}
|
||||
|
||||
AnyPointer::Builder MessageBuilder::getRootInternal() {
|
||||
_::SegmentBuilder* rootSegment = getRootSegment();
|
||||
return AnyPointer::Builder(_::PointerBuilder::getRoot(
|
||||
rootSegment, arena()->getLocalCapTable(), rootSegment->getPtrUnchecked(ZERO * WORDS)));
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> MessageBuilder::getSegmentsForOutput() {
|
||||
if (allocatedArena) {
|
||||
return arena()->getSegmentsForOutput();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Orphanage MessageBuilder::getOrphanage() {
|
||||
// We must ensure that the arena and root pointer have been allocated before the Orphanage
|
||||
// can be used.
|
||||
if (!allocatedArena) getRootSegment();
|
||||
|
||||
return Orphanage(arena(), arena()->getLocalCapTable());
|
||||
}
|
||||
|
||||
bool MessageBuilder::isCanonical() {
|
||||
_::SegmentReader *segment = getRootSegment();
|
||||
|
||||
if (segment == NULL) {
|
||||
// The message has no segments
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena()->tryGetSegment(_::SegmentId(1))) {
|
||||
// The message has more than one segment
|
||||
return false;
|
||||
}
|
||||
|
||||
const word* readHead = segment->getStartPtr() + 1;
|
||||
return _::PointerReader::getRoot(segment, nullptr, segment->getStartPtr(), kj::maxValue)
|
||||
.isCanonical(&readHead);
|
||||
}
|
||||
|
||||
size_t MessageBuilder::sizeInWords() {
|
||||
return arena()->sizeInWords();
|
||||
}
|
||||
|
||||
kj::Own<_::CapTableBuilder> MessageBuilder::releaseBuiltinCapTable() {
|
||||
return arena()->releaseLocalCapTable();
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
SegmentArrayMessageReader::SegmentArrayMessageReader(
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments, ReaderOptions options)
|
||||
: MessageReader(options), segments(segments) {}
|
||||
|
||||
SegmentArrayMessageReader::~SegmentArrayMessageReader() noexcept(false) {}
|
||||
|
||||
kj::ArrayPtr<const word> SegmentArrayMessageReader::getSegment(uint id) {
|
||||
if (id < segments.size()) {
|
||||
return segments[id];
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
MallocMessageBuilder::MallocMessageBuilder(
|
||||
uint firstSegmentWords, AllocationStrategy allocationStrategy)
|
||||
: nextSize(firstSegmentWords), allocationStrategy(allocationStrategy),
|
||||
ownFirstSegment(true), returnedFirstSegment(false), firstSegment(nullptr) {}
|
||||
|
||||
MallocMessageBuilder::MallocMessageBuilder(
|
||||
kj::ArrayPtr<word> firstSegment, AllocationStrategy allocationStrategy)
|
||||
: nextSize(firstSegment.size()), allocationStrategy(allocationStrategy),
|
||||
ownFirstSegment(false), returnedFirstSegment(false), firstSegment(firstSegment.begin()) {
|
||||
KJ_REQUIRE(firstSegment.size() > 0, "First segment size must be non-zero.");
|
||||
|
||||
// Checking just the first word should catch most cases of failing to zero the segment.
|
||||
KJ_REQUIRE(*reinterpret_cast<uint64_t*>(firstSegment.begin()) == 0,
|
||||
"First segment must be zeroed.");
|
||||
}
|
||||
|
||||
MallocMessageBuilder::~MallocMessageBuilder() noexcept(false) {
|
||||
if (returnedFirstSegment) {
|
||||
if (ownFirstSegment) {
|
||||
free(firstSegment);
|
||||
} else {
|
||||
// Must zero first segment.
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments = getSegmentsForOutput();
|
||||
if (segments.size() > 0) {
|
||||
KJ_ASSERT(segments[0].begin() == firstSegment,
|
||||
"First segment in getSegmentsForOutput() is not the first segment allocated?");
|
||||
memset(firstSegment, 0, segments[0].size() * sizeof(word));
|
||||
}
|
||||
}
|
||||
|
||||
for (void* ptr: moreSegments) {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kj::ArrayPtr<word> MallocMessageBuilder::allocateSegment(uint minimumSize) {
|
||||
KJ_REQUIRE(bounded(minimumSize) * WORDS <= MAX_SEGMENT_WORDS,
|
||||
"MallocMessageBuilder asked to allocate segment above maximum serializable size.");
|
||||
KJ_ASSERT(bounded(nextSize) * WORDS <= MAX_SEGMENT_WORDS,
|
||||
"MallocMessageBuilder nextSize out of bounds.");
|
||||
|
||||
if (!returnedFirstSegment && !ownFirstSegment) {
|
||||
kj::ArrayPtr<word> result = kj::arrayPtr(reinterpret_cast<word*>(firstSegment), nextSize);
|
||||
if (result.size() >= minimumSize) {
|
||||
returnedFirstSegment = true;
|
||||
return result;
|
||||
}
|
||||
// If the provided first segment wasn't big enough, we discard it and proceed to allocate
|
||||
// our own. This never happens in practice since minimumSize is always 1 for the first
|
||||
// segment.
|
||||
ownFirstSegment = true;
|
||||
}
|
||||
|
||||
uint size = kj::max(minimumSize, nextSize);
|
||||
|
||||
void* result = calloc(size, sizeof(word));
|
||||
if (result == nullptr) {
|
||||
KJ_FAIL_SYSCALL("calloc(size, sizeof(word))", ENOMEM, size);
|
||||
}
|
||||
|
||||
if (!returnedFirstSegment) {
|
||||
firstSegment = result;
|
||||
returnedFirstSegment = true;
|
||||
|
||||
// After the first segment, we want nextSize to equal the total size allocated so far.
|
||||
if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) nextSize = size;
|
||||
} else {
|
||||
moreSegments.add(result);
|
||||
if (allocationStrategy == AllocationStrategy::GROW_HEURISTICALLY) {
|
||||
// set nextSize = min(nextSize+size, MAX_SEGMENT_WORDS)
|
||||
// while protecting against possible overflow of (nextSize+size)
|
||||
nextSize = (size <= unbound(MAX_SEGMENT_WORDS / WORDS) - nextSize)
|
||||
? nextSize + size : unbound(MAX_SEGMENT_WORDS / WORDS);
|
||||
}
|
||||
}
|
||||
|
||||
return kj::arrayPtr(reinterpret_cast<word*>(result), size);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
FlatMessageBuilder::FlatMessageBuilder(kj::ArrayPtr<word> array): array(array), allocated(false) {}
|
||||
FlatMessageBuilder::~FlatMessageBuilder() noexcept(false) {}
|
||||
|
||||
void FlatMessageBuilder::requireFilled() {
|
||||
KJ_REQUIRE(getSegmentsForOutput()[0].end() == array.end(),
|
||||
"FlatMessageBuilder's buffer was too large.");
|
||||
}
|
||||
|
||||
kj::ArrayPtr<word> FlatMessageBuilder::allocateSegment(uint minimumSize) {
|
||||
KJ_REQUIRE(!allocated, "FlatMessageBuilder's buffer was not large enough.");
|
||||
allocated = true;
|
||||
return array;
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,558 @@
|
|||
// Copyright (c) 2013-2016 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kj/common.h>
|
||||
#include <kj/memory.h>
|
||||
#include <kj/mutex.h>
|
||||
#include <kj/debug.h>
|
||||
#include <kj/vector.h>
|
||||
#include "common.h"
|
||||
#include "layout.h"
|
||||
#include "any.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
namespace _ { // private
|
||||
class ReaderArena;
|
||||
class BuilderArena;
|
||||
struct CloneImpl;
|
||||
}
|
||||
|
||||
class StructSchema;
|
||||
class Orphanage;
|
||||
template <typename T>
|
||||
class Orphan;
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
struct ReaderOptions {
|
||||
// Options controlling how data is read.
|
||||
|
||||
uint64_t traversalLimitInWords = 8 * 1024 * 1024;
|
||||
// Limits how many total words of data are allowed to be traversed. Traversal is counted when
|
||||
// a new struct or list builder is obtained, e.g. from a get() accessor. This means that calling
|
||||
// the getter for the same sub-struct multiple times will cause it to be double-counted. Once
|
||||
// the traversal limit is reached, an error will be reported.
|
||||
//
|
||||
// This limit exists for security reasons. It is possible for an attacker to construct a message
|
||||
// in which multiple pointers point at the same location. This is technically invalid, but hard
|
||||
// to detect. Using such a message, an attacker could cause a message which is small on the wire
|
||||
// to appear much larger when actually traversed, possibly exhausting server resources leading to
|
||||
// denial-of-service.
|
||||
//
|
||||
// It makes sense to set a traversal limit that is much larger than the underlying message.
|
||||
// Together with sensible coding practices (e.g. trying to avoid calling sub-object getters
|
||||
// multiple times, which is expensive anyway), this should provide adequate protection without
|
||||
// inconvenience.
|
||||
//
|
||||
// The default limit is 64 MiB. This may or may not be a sensible number for any given use case,
|
||||
// but probably at least prevents easy exploitation while also avoiding causing problems in most
|
||||
// typical cases.
|
||||
|
||||
int nestingLimit = 64;
|
||||
// Limits how deeply-nested a message structure can be, e.g. structs containing other structs or
|
||||
// lists of structs.
|
||||
//
|
||||
// Like the traversal limit, this limit exists for security reasons. Since it is common to use
|
||||
// recursive code to traverse recursive data structures, an attacker could easily cause a stack
|
||||
// overflow by sending a very-deeply-nested (or even cyclic) message, without the message even
|
||||
// being very large. The default limit of 64 is probably low enough to prevent any chance of
|
||||
// stack overflow, yet high enough that it is never a problem in practice.
|
||||
};
|
||||
|
||||
class MessageReader {
|
||||
// Abstract interface for an object used to read a Cap'n Proto message. Subclasses of
|
||||
// MessageReader are responsible for reading the raw, flat message content. Callers should
|
||||
// usually call `messageReader.getRoot<MyStructType>()` to get a `MyStructType::Reader`
|
||||
// representing the root of the message, then use that to traverse the message content.
|
||||
//
|
||||
// Some common subclasses of `MessageReader` include `SegmentArrayMessageReader`, whose
|
||||
// constructor accepts pointers to the raw data, and `StreamFdMessageReader` (from
|
||||
// `serialize.h`), which reads the message from a file descriptor. One might implement other
|
||||
// subclasses to handle things like reading from shared memory segments, mmap()ed files, etc.
|
||||
|
||||
public:
|
||||
MessageReader(ReaderOptions options);
|
||||
// It is suggested that subclasses take ReaderOptions as a constructor parameter, but give it a
|
||||
// default value of "ReaderOptions()". The base class constructor doesn't have a default value
|
||||
// in order to remind subclasses that they really need to give the user a way to provide this.
|
||||
|
||||
virtual ~MessageReader() noexcept(false);
|
||||
|
||||
virtual kj::ArrayPtr<const word> getSegment(uint id) = 0;
|
||||
// Gets the segment with the given ID, or returns null if no such segment exists. This method
|
||||
// will be called at most once for each segment ID.
|
||||
|
||||
inline const ReaderOptions& getOptions();
|
||||
// Get the options passed to the constructor.
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Reader getRoot();
|
||||
// Get the root struct of the message, interpreting it as the given struct type.
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Reader getRoot(SchemaType schema);
|
||||
// Dynamically interpret the root struct of the message using the given schema (a StructSchema).
|
||||
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
|
||||
// use this.
|
||||
|
||||
bool isCanonical();
|
||||
// Returns whether the message encoded in the reader is in canonical form.
|
||||
|
||||
size_t sizeInWords();
|
||||
// Add up the size of all segments.
|
||||
|
||||
private:
|
||||
ReaderOptions options;
|
||||
|
||||
#if defined(__EMSCRIPTEN__) || (defined(__APPLE__) && defined(__ppc__))
|
||||
static constexpr size_t arenaSpacePadding = 19;
|
||||
#else
|
||||
static constexpr size_t arenaSpacePadding = 18;
|
||||
#endif
|
||||
|
||||
// Space in which we can construct a ReaderArena. We don't use ReaderArena directly here
|
||||
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
|
||||
// other headers. We don't use a pointer to a ReaderArena because that would require an
|
||||
// extra malloc on every message which could be expensive when processing small messages.
|
||||
alignas(8) void* arenaSpace[arenaSpacePadding + sizeof(kj::MutexGuarded<void*>) / sizeof(void*)];
|
||||
bool allocatedArena;
|
||||
|
||||
_::ReaderArena* arena() { return reinterpret_cast<_::ReaderArena*>(arenaSpace); }
|
||||
AnyPointer::Reader getRootInternal();
|
||||
};
|
||||
|
||||
class MessageBuilder {
|
||||
// Abstract interface for an object used to allocate and build a message. Subclasses of
|
||||
// MessageBuilder are responsible for allocating the space in which the message will be written.
|
||||
// The most common subclass is `MallocMessageBuilder`, but other subclasses may be used to do
|
||||
// tricky things like allocate messages in shared memory or mmap()ed files.
|
||||
//
|
||||
// Creating a new message ususually means allocating a new MessageBuilder (ideally on the stack)
|
||||
// and then calling `messageBuilder.initRoot<MyStructType>()` to get a `MyStructType::Builder`.
|
||||
// That, in turn, can be used to fill in the message content. When done, you can call
|
||||
// `messageBuilder.getSegmentsForOutput()` to get a list of flat data arrays containing the
|
||||
// message.
|
||||
|
||||
public:
|
||||
MessageBuilder();
|
||||
virtual ~MessageBuilder() noexcept(false);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(MessageBuilder);
|
||||
|
||||
struct SegmentInit {
|
||||
kj::ArrayPtr<word> space;
|
||||
|
||||
size_t wordsUsed;
|
||||
// Number of words in `space` which are used; the rest are free space in which additional
|
||||
// objects may be allocated.
|
||||
};
|
||||
|
||||
explicit MessageBuilder(kj::ArrayPtr<SegmentInit> segments);
|
||||
// Create a MessageBuilder backed by existing memory. This is an advanced interface that most
|
||||
// people should not use. THIS METHOD IS INSECURE; see below.
|
||||
//
|
||||
// This allows a MessageBuilder to be constructed to modify an in-memory message without first
|
||||
// making a copy of the content. This is especially useful in conjunction with mmap().
|
||||
//
|
||||
// The contents of each segment must outlive the MessageBuilder, but the SegmentInit array itself
|
||||
// only need outlive the constructor.
|
||||
//
|
||||
// SECURITY: Do not use this in conjunction with untrusted data. This constructor assumes that
|
||||
// the input message is valid. This constructor is designed to be used with data you control,
|
||||
// e.g. an mmap'd file which is owned and accessed by only one program. When reading data you
|
||||
// do not trust, you *must* load it into a Reader and then copy into a Builder as a means of
|
||||
// validating the content.
|
||||
//
|
||||
// WARNING: It is NOT safe to initialize a MessageBuilder in this way from memory that is
|
||||
// currently in use by another MessageBuilder or MessageReader. Other readers/builders will
|
||||
// not observe changes to the segment sizes nor newly-allocated segments caused by allocating
|
||||
// new objects in this message.
|
||||
|
||||
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) = 0;
|
||||
// Allocates an array of at least the given number of zero'd words, throwing an exception or
|
||||
// crashing if this is not possible. It is expected that this method will usually return more
|
||||
// space than requested, and the caller should use that extra space as much as possible before
|
||||
// allocating more. The returned space remains valid at least until the MessageBuilder is
|
||||
// destroyed.
|
||||
//
|
||||
// allocateSegment() is responsible for zeroing the memory before returning. This is required
|
||||
// because otherwise the Cap'n Proto implementation would have to zero the memory anyway, and
|
||||
// many allocators are able to provide already-zero'd memory more efficiently.
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Builder initRoot();
|
||||
// Initialize the root struct of the message as the given struct type.
|
||||
|
||||
template <typename Reader>
|
||||
void setRoot(Reader&& value);
|
||||
// Set the root struct to a deep copy of the given struct.
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Builder getRoot();
|
||||
// Get the root struct of the message, interpreting it as the given struct type.
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Builder getRoot(SchemaType schema);
|
||||
// Dynamically interpret the root struct of the message using the given schema (a StructSchema).
|
||||
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
|
||||
// use this.
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Builder initRoot(SchemaType schema);
|
||||
// Dynamically init the root struct of the message using the given schema (a StructSchema).
|
||||
// RootType in this case must be DynamicStruct, and you must #include <capnp/dynamic.h> to
|
||||
// use this.
|
||||
|
||||
template <typename T>
|
||||
void adoptRoot(Orphan<T>&& orphan);
|
||||
// Like setRoot() but adopts the orphan without copying.
|
||||
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> getSegmentsForOutput();
|
||||
// Get the raw data that makes up the message.
|
||||
|
||||
Orphanage getOrphanage();
|
||||
|
||||
bool isCanonical();
|
||||
// Check whether the message builder is in canonical form
|
||||
|
||||
size_t sizeInWords();
|
||||
// Add up the allocated space from all segments.
|
||||
|
||||
private:
|
||||
alignas(8) void* arenaSpace[22];
|
||||
// Space in which we can construct a BuilderArena. We don't use BuilderArena directly here
|
||||
// because we don't want clients to have to #include arena.h, which itself includes a bunch of
|
||||
// big STL headers. We don't use a pointer to a BuilderArena because that would require an
|
||||
// extra malloc on every message which could be expensive when processing small messages.
|
||||
|
||||
bool allocatedArena = false;
|
||||
// We have to initialize the arena lazily because when we do so we want to allocate the root
|
||||
// pointer immediately, and this will allocate a segment, which requires a virtual function
|
||||
// call on the MessageBuilder. We can't do such a call in the constructor since the subclass
|
||||
// isn't constructed yet. This is kind of annoying because it means that getOrphanage() is
|
||||
// not thread-safe, but that shouldn't be a huge deal...
|
||||
|
||||
_::BuilderArena* arena() { return reinterpret_cast<_::BuilderArena*>(arenaSpace); }
|
||||
_::SegmentBuilder* getRootSegment();
|
||||
AnyPointer::Builder getRootInternal();
|
||||
|
||||
kj::Own<_::CapTableBuilder> releaseBuiltinCapTable();
|
||||
// Hack for clone() to extract the cap table.
|
||||
|
||||
friend struct _::CloneImpl;
|
||||
// We can't declare clone() as a friend directly because old versions of GCC incorrectly demand
|
||||
// that the first declaration (even if it is a friend declaration) specify the default type args,
|
||||
// whereas correct compilers do not permit default type args to be specified on a friend decl.
|
||||
};
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Reader readMessageUnchecked(const word* data);
|
||||
// IF THE INPUT IS INVALID, THIS MAY CRASH, CORRUPT MEMORY, CREATE A SECURITY HOLE IN YOUR APP,
|
||||
// MURDER YOUR FIRST-BORN CHILD, AND/OR BRING ABOUT ETERNAL DAMNATION ON ALL OF HUMANITY. DO NOT
|
||||
// USE UNLESS YOU UNDERSTAND THE CONSEQUENCES.
|
||||
//
|
||||
// Given a pointer to a known-valid message located in a single contiguous memory segment,
|
||||
// returns a reader for that message. No bounds-checking will be done while traversing this
|
||||
// message. Use this only if you have already verified that all pointers are valid and in-bounds,
|
||||
// and there are no far pointers in the message.
|
||||
//
|
||||
// To create a message that can be passed to this function, build a message using a MallocAllocator
|
||||
// whose preferred segment size is larger than the message size. This guarantees that the message
|
||||
// will be allocated as a single segment, meaning getSegmentsForOutput() returns a single word
|
||||
// array. That word array is your message; you may pass a pointer to its first word into
|
||||
// readMessageUnchecked() to read the message.
|
||||
//
|
||||
// This can be particularly handy for embedding messages in generated code: you can
|
||||
// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way
|
||||
// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have
|
||||
// a message MyMessage, you can read its default value like so:
|
||||
// MyMessage::Reader reader = Message<MyMessage>::readMessageUnchecked(MyMessage::DEFAULT.words);
|
||||
//
|
||||
// To sanitize a message from an untrusted source such that it can be safely passed to
|
||||
// readMessageUnchecked(), use copyToUnchecked().
|
||||
|
||||
template <typename Reader>
|
||||
void copyToUnchecked(Reader&& reader, kj::ArrayPtr<word> uncheckedBuffer);
|
||||
// Copy the content of the given reader into the given buffer, such that it can safely be passed to
|
||||
// readMessageUnchecked(). The buffer's size must be exactly reader.totalSizeInWords() + 1,
|
||||
// otherwise an exception will be thrown. The buffer must be zero'd before calling.
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Reader readDataStruct(kj::ArrayPtr<const word> data);
|
||||
// Interprets the given data as a single, data-only struct. Only primitive fields (booleans,
|
||||
// numbers, and enums) will be readable; all pointers will be null. This is useful if you want
|
||||
// to use Cap'n Proto as a language/platform-neutral way to pack some bits.
|
||||
//
|
||||
// The input is a word array rather than a byte array to enforce alignment. If you have a byte
|
||||
// array which you know is word-aligned (or if your platform supports unaligned reads and you don't
|
||||
// mind the performance penalty), then you can use `reinterpret_cast` to convert a byte array into
|
||||
// a word array:
|
||||
//
|
||||
// kj::arrayPtr(reinterpret_cast<const word*>(bytes.begin()),
|
||||
// reinterpret_cast<const word*>(bytes.end()))
|
||||
|
||||
template <typename BuilderType>
|
||||
typename kj::ArrayPtr<const word> writeDataStruct(BuilderType builder);
|
||||
// Given a struct builder, get the underlying data section as a word array, suitable for passing
|
||||
// to `readDataStruct()`.
|
||||
//
|
||||
// Note that you may call `.toBytes()` on the returned value to convert to `ArrayPtr<const byte>`.
|
||||
|
||||
template <typename Type>
|
||||
static typename Type::Reader defaultValue();
|
||||
// Get a default instance of the given struct or list type.
|
||||
//
|
||||
// TODO(cleanup): Find a better home for this function?
|
||||
|
||||
template <typename Reader, typename = FromReader<Reader>>
|
||||
kj::Own<kj::Decay<Reader>> clone(Reader&& reader);
|
||||
// Make a deep copy of the given Reader on the heap, producing an owned pointer.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class SegmentArrayMessageReader: public MessageReader {
|
||||
// A simple MessageReader that reads from an array of word arrays representing all segments.
|
||||
// In particular you can read directly from the output of MessageBuilder::getSegmentsForOutput()
|
||||
// (although it would probably make more sense to call builder.getRoot().asReader() in that case).
|
||||
|
||||
public:
|
||||
SegmentArrayMessageReader(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments,
|
||||
ReaderOptions options = ReaderOptions());
|
||||
// Creates a message pointing at the given segment array, without taking ownership of the
|
||||
// segments. All arrays passed in must remain valid until the MessageReader is destroyed.
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(SegmentArrayMessageReader);
|
||||
~SegmentArrayMessageReader() noexcept(false);
|
||||
|
||||
virtual kj::ArrayPtr<const word> getSegment(uint id) override;
|
||||
|
||||
private:
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments;
|
||||
};
|
||||
|
||||
enum class AllocationStrategy: uint8_t {
|
||||
FIXED_SIZE,
|
||||
// The builder will prefer to allocate the same amount of space for each segment with no
|
||||
// heuristic growth. It will still allocate larger segments when the preferred size is too small
|
||||
// for some single object. This mode is generally not recommended, but can be particularly useful
|
||||
// for testing in order to force a message to allocate a predictable number of segments. Note
|
||||
// that you can force every single object in the message to be located in a separate segment by
|
||||
// using this mode with firstSegmentWords = 0.
|
||||
|
||||
GROW_HEURISTICALLY
|
||||
// The builder will heuristically decide how much space to allocate for each segment. Each
|
||||
// allocated segment will be progressively larger than the previous segments on the assumption
|
||||
// that message sizes are exponentially distributed. The total number of segments that will be
|
||||
// allocated for a message of size n is O(log n).
|
||||
};
|
||||
|
||||
constexpr uint SUGGESTED_FIRST_SEGMENT_WORDS = 1024;
|
||||
constexpr AllocationStrategy SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy::GROW_HEURISTICALLY;
|
||||
|
||||
class MallocMessageBuilder: public MessageBuilder {
|
||||
// A simple MessageBuilder that uses malloc() (actually, calloc()) to allocate segments. This
|
||||
// implementation should be reasonable for any case that doesn't require writing the message to
|
||||
// a specific location in memory.
|
||||
|
||||
public:
|
||||
explicit MallocMessageBuilder(uint firstSegmentWords = SUGGESTED_FIRST_SEGMENT_WORDS,
|
||||
AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY);
|
||||
// Creates a BuilderContext which allocates at least the given number of words for the first
|
||||
// segment, and then uses the given strategy to decide how much to allocate for subsequent
|
||||
// segments. When choosing a value for firstSegmentWords, consider that:
|
||||
// 1) Reading and writing messages gets slower when multiple segments are involved, so it's good
|
||||
// if most messages fit in a single segment.
|
||||
// 2) Unused bytes will not be written to the wire, so generally it is not a big deal to allocate
|
||||
// more space than you need. It only becomes problematic if you are allocating many messages
|
||||
// in parallel and thus use lots of memory, or if you allocate so much extra space that just
|
||||
// zeroing it out becomes a bottleneck.
|
||||
// The defaults have been chosen to be reasonable for most people, so don't change them unless you
|
||||
// have reason to believe you need to.
|
||||
|
||||
explicit MallocMessageBuilder(kj::ArrayPtr<word> firstSegment,
|
||||
AllocationStrategy allocationStrategy = SUGGESTED_ALLOCATION_STRATEGY);
|
||||
// This version always returns the given array for the first segment, and then proceeds with the
|
||||
// allocation strategy. This is useful for optimization when building lots of small messages in
|
||||
// a tight loop: you can reuse the space for the first segment.
|
||||
//
|
||||
// firstSegment MUST be zero-initialized. MallocMessageBuilder's destructor will write new zeros
|
||||
// over any space that was used so that it can be reused.
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(MallocMessageBuilder);
|
||||
virtual ~MallocMessageBuilder() noexcept(false);
|
||||
|
||||
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) override;
|
||||
|
||||
private:
|
||||
uint nextSize;
|
||||
AllocationStrategy allocationStrategy;
|
||||
|
||||
bool ownFirstSegment;
|
||||
bool returnedFirstSegment;
|
||||
|
||||
void* firstSegment;
|
||||
kj::Vector<void*> moreSegments;
|
||||
};
|
||||
|
||||
class FlatMessageBuilder: public MessageBuilder {
|
||||
// THIS IS NOT THE CLASS YOU'RE LOOKING FOR.
|
||||
//
|
||||
// If you want to write a message into already-existing scratch space, use `MallocMessageBuilder`
|
||||
// and pass the scratch space to its constructor. It will then only fall back to malloc() if
|
||||
// the scratch space is not large enough.
|
||||
//
|
||||
// Do NOT use this class unless you really know what you're doing. This class is problematic
|
||||
// because it requires advance knowledge of the size of your message, which is usually impossible
|
||||
// to determine without actually building the message. The class was created primarily to
|
||||
// implement `copyToUnchecked()`, which itself exists only to support other internal parts of
|
||||
// the Cap'n Proto implementation.
|
||||
|
||||
public:
|
||||
explicit FlatMessageBuilder(kj::ArrayPtr<word> array);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(FlatMessageBuilder);
|
||||
virtual ~FlatMessageBuilder() noexcept(false);
|
||||
|
||||
void requireFilled();
|
||||
// Throws an exception if the flat array is not exactly full.
|
||||
|
||||
virtual kj::ArrayPtr<word> allocateSegment(uint minimumSize) override;
|
||||
|
||||
private:
|
||||
kj::ArrayPtr<word> array;
|
||||
bool allocated;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// implementation details
|
||||
|
||||
inline const ReaderOptions& MessageReader::getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
inline typename RootType::Reader MessageReader::getRoot() {
|
||||
return getRootInternal().getAs<RootType>();
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
inline typename RootType::Builder MessageBuilder::initRoot() {
|
||||
return getRootInternal().initAs<RootType>();
|
||||
}
|
||||
|
||||
template <typename Reader>
|
||||
inline void MessageBuilder::setRoot(Reader&& value) {
|
||||
getRootInternal().setAs<FromReader<Reader>>(value);
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
inline typename RootType::Builder MessageBuilder::getRoot() {
|
||||
return getRootInternal().getAs<RootType>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MessageBuilder::adoptRoot(Orphan<T>&& orphan) {
|
||||
return getRootInternal().adopt(kj::mv(orphan));
|
||||
}
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Reader MessageReader::getRoot(SchemaType schema) {
|
||||
return getRootInternal().getAs<RootType>(schema);
|
||||
}
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Builder MessageBuilder::getRoot(SchemaType schema) {
|
||||
return getRootInternal().getAs<RootType>(schema);
|
||||
}
|
||||
|
||||
template <typename RootType, typename SchemaType>
|
||||
typename RootType::Builder MessageBuilder::initRoot(SchemaType schema) {
|
||||
return getRootInternal().initAs<RootType>(schema);
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Reader readMessageUnchecked(const word* data) {
|
||||
return AnyPointer::Reader(_::PointerReader::getRootUnchecked(data)).getAs<RootType>();
|
||||
}
|
||||
|
||||
template <typename Reader>
|
||||
void copyToUnchecked(Reader&& reader, kj::ArrayPtr<word> uncheckedBuffer) {
|
||||
FlatMessageBuilder builder(uncheckedBuffer);
|
||||
builder.setRoot(kj::fwd<Reader>(reader));
|
||||
builder.requireFilled();
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
typename RootType::Reader readDataStruct(kj::ArrayPtr<const word> data) {
|
||||
return typename RootType::Reader(_::StructReader(data));
|
||||
}
|
||||
|
||||
template <typename BuilderType>
|
||||
typename kj::ArrayPtr<const word> writeDataStruct(BuilderType builder) {
|
||||
auto bytes = _::PointerHelpers<FromBuilder<BuilderType>>::getInternalBuilder(kj::mv(builder))
|
||||
.getDataSectionAsBlob();
|
||||
return kj::arrayPtr(reinterpret_cast<word*>(bytes.begin()),
|
||||
reinterpret_cast<word*>(bytes.end()));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
static typename Type::Reader defaultValue() {
|
||||
return typename Type::Reader(_::StructReader());
|
||||
}
|
||||
|
||||
namespace _ {
|
||||
struct CloneImpl {
|
||||
static inline kj::Own<_::CapTableBuilder> releaseBuiltinCapTable(MessageBuilder& message) {
|
||||
return message.releaseBuiltinCapTable();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Reader, typename>
|
||||
kj::Own<kj::Decay<Reader>> clone(Reader&& reader) {
|
||||
auto size = reader.totalSize();
|
||||
auto buffer = kj::heapArray<capnp::word>(size.wordCount + 1);
|
||||
memset(buffer.asBytes().begin(), 0, buffer.asBytes().size());
|
||||
if (size.capCount == 0) {
|
||||
copyToUnchecked(reader, buffer);
|
||||
auto result = readMessageUnchecked<FromReader<Reader>>(buffer.begin());
|
||||
return kj::attachVal(result, kj::mv(buffer));
|
||||
} else {
|
||||
FlatMessageBuilder builder(buffer);
|
||||
builder.setRoot(kj::fwd<Reader>(reader));
|
||||
builder.requireFilled();
|
||||
auto capTable = _::CloneImpl::releaseBuiltinCapTable(builder);
|
||||
AnyPointer::Reader raw(_::PointerReader::getRootUnchecked(buffer.begin()).imbue(capTable));
|
||||
return kj::attachVal(raw.getAs<FromReader<Reader>>(), kj::mv(buffer), kj::mv(capTable));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
kj::Array<word> canonicalize(T&& reader) {
|
||||
return _::PointerHelpers<FromReader<T>>::getInternalReader(reader).canonicalize();
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class StructSchema;
|
||||
class ListSchema;
|
||||
struct DynamicStruct;
|
||||
struct DynamicList;
|
||||
namespace _ { struct OrphanageInternal; }
|
||||
|
||||
template <typename T>
|
||||
class Orphan {
|
||||
// Represents an object which is allocated within some message builder but has no pointers
|
||||
// pointing at it. An Orphan can later be "adopted" by some other object as one of that object's
|
||||
// fields, without having to copy the orphan. For a field `foo` of pointer type, the generated
|
||||
// code will define builder methods `void adoptFoo(Orphan<T>)` and `Orphan<T> disownFoo()`.
|
||||
// Orphans can also be created independently of any parent using an Orphanage.
|
||||
//
|
||||
// `Orphan<T>` can be moved but not copied, like `Own<T>`, so that it is impossible for one
|
||||
// orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its
|
||||
// contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space
|
||||
// in a message arena).
|
||||
|
||||
public:
|
||||
Orphan() = default;
|
||||
KJ_DISALLOW_COPY(Orphan);
|
||||
Orphan(Orphan&&) = default;
|
||||
Orphan& operator=(Orphan&&) = default;
|
||||
inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {}
|
||||
|
||||
inline BuilderFor<T> get();
|
||||
// Get the underlying builder. If the orphan is null, this will allocate and return a default
|
||||
// object rather than crash. This is done for security -- otherwise, you might enable a DoS
|
||||
// attack any time you disown a field and fail to check if it is null. In the case of structs,
|
||||
// this means that the orphan is no longer null after get() returns. In the case of lists,
|
||||
// no actual object is allocated since a simple empty ListBuilder can be returned.
|
||||
|
||||
inline ReaderFor<T> getReader() const;
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
|
||||
|
||||
inline void truncate(uint size);
|
||||
// Resize an object (which must be a list or a blob) to the given size.
|
||||
//
|
||||
// If the new size is less than the original, the remaining elements will be discarded. The
|
||||
// list is never moved in this case. If the list happens to be located at the end of its segment
|
||||
// (which is always true if the list was the last thing allocated), the removed memory will be
|
||||
// reclaimed (reducing the message size), otherwise it is simply zeroed. The reclaiming behavior
|
||||
// is particularly useful for allocating buffer space when you aren't sure how much space you
|
||||
// actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and
|
||||
// then truncate it back to the amount of space actually used.
|
||||
//
|
||||
// If the new size is greater than the original, the list is extended with default values. If
|
||||
// the list is the last object in its segment *and* there is enough space left in the segment to
|
||||
// extend it to cover the new values, then the list is extended in-place. Otherwise, it must be
|
||||
// moved to a new location, leaving a zero'd hole in the previous space that won't be filled.
|
||||
// This copy is shallow; sub-objects will simply be reparented, not copied.
|
||||
//
|
||||
// Any existing readers or builders pointing at the object are invalidated by this call (even if
|
||||
// it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer.
|
||||
|
||||
private:
|
||||
_::OrphanBuilder builder;
|
||||
|
||||
template <typename, Kind>
|
||||
friend struct _::PointerHelpers;
|
||||
template <typename, Kind>
|
||||
friend struct List;
|
||||
template <typename U>
|
||||
friend class Orphan;
|
||||
friend class Orphanage;
|
||||
friend class MessageBuilder;
|
||||
};
|
||||
|
||||
class Orphanage: private kj::DisallowConstCopy {
|
||||
// Use to directly allocate Orphan objects, without having a parent object allocate and then
|
||||
// disown the object.
|
||||
|
||||
public:
|
||||
inline Orphanage(): arena(nullptr) {}
|
||||
|
||||
template <typename BuilderType>
|
||||
static Orphanage getForMessageContaining(BuilderType builder);
|
||||
// Construct an Orphanage that allocates within the message containing the given Builder. This
|
||||
// allows the constructed Orphans to be adopted by objects within said message.
|
||||
//
|
||||
// This constructor takes the builder rather than having the builder have a getOrphanage() method
|
||||
// because this is an advanced feature and we don't want to pollute the builder APIs with it.
|
||||
//
|
||||
// Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its
|
||||
// `getOrphanage()` method.
|
||||
|
||||
template <typename RootType>
|
||||
Orphan<RootType> newOrphan() const;
|
||||
// Allocate a new orphaned struct.
|
||||
|
||||
template <typename RootType>
|
||||
Orphan<RootType> newOrphan(uint size) const;
|
||||
// Allocate a new orphaned list or blob.
|
||||
|
||||
Orphan<DynamicStruct> newOrphan(StructSchema schema) const;
|
||||
// Dynamically create an orphan struct with the given schema. You must
|
||||
// #include <capnp/dynamic.h> to use this.
|
||||
|
||||
Orphan<DynamicList> newOrphan(ListSchema schema, uint size) const;
|
||||
// Dynamically create an orphan list with the given schema. You must #include <capnp/dynamic.h>
|
||||
// to use this.
|
||||
|
||||
template <typename Reader>
|
||||
Orphan<FromReader<Reader>> newOrphanCopy(Reader copyFrom) const;
|
||||
// Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the
|
||||
// given object.
|
||||
|
||||
template <typename T>
|
||||
Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<T> lists) const;
|
||||
template <typename T>
|
||||
Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<const T> lists) const;
|
||||
// Given an array of List readers, copy and concatenate the lists, creating a new Orphan.
|
||||
//
|
||||
// Note that compared to allocating the list yourself and using `setWithCaveats()` to set each
|
||||
// item, this method avoids the "caveats": the new list will be allocated with the element size
|
||||
// being the maximum of that from all the input lists. This is particularly important when
|
||||
// concatenating struct lists: if the lists were created using a newer version of the protocol
|
||||
// in which some new fields had been added to the struct, using `setWithCaveats()` would
|
||||
// truncate off those new fields.
|
||||
|
||||
Orphan<Data> referenceExternalData(Data::Reader data) const;
|
||||
// Creates an Orphan<Data> that points at an existing region of memory (e.g. from another message)
|
||||
// without copying it. There are some SEVERE restrictions on how this can be used:
|
||||
// - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is
|
||||
// abandoned).
|
||||
// - Because the data is const, you will not be allowed to obtain a `Data::Builder`
|
||||
// for this blob. Any call which would return such a builder will throw an exception. You
|
||||
// can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once
|
||||
// the orphan is adopted). It is your responsibility to make sure your code can deal with
|
||||
// these problems when using this optimization; if you can't, allocate a copy instead.
|
||||
// - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on
|
||||
// the CPU). Any pointer returned by malloc() as well as any data blob obtained from another
|
||||
// Cap'n Proto message satisfies this.
|
||||
// - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte
|
||||
// boundary will be visible in the raw message when it is written out. Thus, there must be no
|
||||
// secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe
|
||||
// as these bytes should be zero (unless the sender had the same problem).
|
||||
//
|
||||
// The array will actually become one of the message's segments. The data can thus be adopted
|
||||
// into the message tree without copying it. This is particularly useful when referencing very
|
||||
// large blobs, such as whole mmap'd files.
|
||||
|
||||
private:
|
||||
_::BuilderArena* arena;
|
||||
_::CapTableBuilder* capTable;
|
||||
|
||||
inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable)
|
||||
: arena(arena), capTable(capTable) {}
|
||||
|
||||
template <typename T, Kind = CAPNP_KIND(T)>
|
||||
struct GetInnerBuilder;
|
||||
template <typename T, Kind = CAPNP_KIND(T)>
|
||||
struct GetInnerReader;
|
||||
template <typename T>
|
||||
struct NewOrphanListImpl;
|
||||
|
||||
friend class MessageBuilder;
|
||||
friend struct _::OrphanageInternal;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details.
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T, Kind = CAPNP_KIND(T)>
|
||||
struct OrphanGetImpl;
|
||||
|
||||
template <typename T>
|
||||
struct OrphanGetImpl<T, Kind::PRIMITIVE> {
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, _::elementSizeForType<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct OrphanGetImpl<T, Kind::STRUCT> {
|
||||
static inline typename T::Builder apply(_::OrphanBuilder& builder) {
|
||||
return typename T::Builder(builder.asStruct(_::structSize<T>()));
|
||||
}
|
||||
static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) {
|
||||
return typename T::Reader(builder.asStructReader(_::structSize<T>()));
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, _::structSize<T>());
|
||||
}
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
template <typename T>
|
||||
struct OrphanGetImpl<T, Kind::INTERFACE> {
|
||||
static inline typename T::Client apply(_::OrphanBuilder& builder) {
|
||||
return typename T::Client(builder.asCapability());
|
||||
}
|
||||
static inline typename T::Client applyReader(const _::OrphanBuilder& builder) {
|
||||
return typename T::Client(builder.asCapability());
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, ElementSize::POINTER);
|
||||
}
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
template <typename T, Kind k>
|
||||
struct OrphanGetImpl<List<T, k>, Kind::LIST> {
|
||||
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
|
||||
return typename List<T>::Builder(builder.asList(_::ElementSizeForType<T>::value));
|
||||
}
|
||||
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
|
||||
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, ElementSize::POINTER);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct OrphanGetImpl<List<T, Kind::STRUCT>, Kind::LIST> {
|
||||
static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) {
|
||||
return typename List<T>::Builder(builder.asStructList(_::structSize<T>()));
|
||||
}
|
||||
static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) {
|
||||
return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value));
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, ElementSize::POINTER);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OrphanGetImpl<Text, Kind::BLOB> {
|
||||
static inline Text::Builder apply(_::OrphanBuilder& builder) {
|
||||
return Text::Builder(builder.asText());
|
||||
}
|
||||
static inline Text::Reader applyReader(const _::OrphanBuilder& builder) {
|
||||
return Text::Reader(builder.asTextReader());
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, ElementSize::POINTER);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OrphanGetImpl<Data, Kind::BLOB> {
|
||||
static inline Data::Builder apply(_::OrphanBuilder& builder) {
|
||||
return Data::Builder(builder.asData());
|
||||
}
|
||||
static inline Data::Reader applyReader(const _::OrphanBuilder& builder) {
|
||||
return Data::Reader(builder.asDataReader());
|
||||
}
|
||||
static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
|
||||
builder.truncate(size, ElementSize::POINTER);
|
||||
}
|
||||
};
|
||||
|
||||
struct OrphanageInternal {
|
||||
static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; }
|
||||
static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; }
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T>
|
||||
inline BuilderFor<T> Orphan<T>::get() {
|
||||
return _::OrphanGetImpl<T>::apply(builder);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ReaderFor<T> Orphan<T>::getReader() const {
|
||||
return _::OrphanGetImpl<T>::applyReader(builder);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Orphan<T>::truncate(uint size) {
|
||||
_::OrphanGetImpl<ListElementType<T>>::truncateListOf(builder, bounded(size) * ELEMENTS);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Orphan<Text>::truncate(uint size) {
|
||||
builder.truncateText(bounded(size) * ELEMENTS);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Orphan<Data>::truncate(uint size) {
|
||||
builder.truncate(bounded(size) * ELEMENTS, ElementSize::BYTE);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::GetInnerBuilder<T, Kind::STRUCT> {
|
||||
static inline _::StructBuilder apply(typename T::Builder& t) {
|
||||
return t._builder;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::GetInnerBuilder<T, Kind::LIST> {
|
||||
static inline _::ListBuilder apply(typename T::Builder& t) {
|
||||
return t.builder;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BuilderType>
|
||||
Orphanage Orphanage::getForMessageContaining(BuilderType builder) {
|
||||
auto inner = GetInnerBuilder<FromBuilder<BuilderType>>::apply(builder);
|
||||
return Orphanage(inner.getArena(), inner.getCapTable());
|
||||
}
|
||||
|
||||
template <typename RootType>
|
||||
Orphan<RootType> Orphanage::newOrphan() const {
|
||||
return Orphan<RootType>(_::OrphanBuilder::initStruct(arena, capTable, _::structSize<RootType>()));
|
||||
}
|
||||
|
||||
template <typename T, Kind k>
|
||||
struct Orphanage::NewOrphanListImpl<List<T, k>> {
|
||||
static inline _::OrphanBuilder apply(
|
||||
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
|
||||
return _::OrphanBuilder::initList(
|
||||
arena, capTable, bounded(size) * ELEMENTS, _::ElementSizeForType<T>::value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::NewOrphanListImpl<List<T, Kind::STRUCT>> {
|
||||
static inline _::OrphanBuilder apply(
|
||||
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
|
||||
return _::OrphanBuilder::initStructList(
|
||||
arena, capTable, bounded(size) * ELEMENTS, _::structSize<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Orphanage::NewOrphanListImpl<Text> {
|
||||
static inline _::OrphanBuilder apply(
|
||||
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
|
||||
return _::OrphanBuilder::initText(arena, capTable, bounded(size) * BYTES);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Orphanage::NewOrphanListImpl<Data> {
|
||||
static inline _::OrphanBuilder apply(
|
||||
_::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) {
|
||||
return _::OrphanBuilder::initData(arena, capTable, bounded(size) * BYTES);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RootType>
|
||||
Orphan<RootType> Orphanage::newOrphan(uint size) const {
|
||||
return Orphan<RootType>(NewOrphanListImpl<RootType>::apply(arena, capTable, size));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::GetInnerReader<T, Kind::STRUCT> {
|
||||
static inline _::StructReader apply(const typename T::Reader& t) {
|
||||
return t._reader;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::GetInnerReader<T, Kind::LIST> {
|
||||
static inline _::ListReader apply(const typename T::Reader& t) {
|
||||
return t.reader;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Orphanage::GetInnerReader<T, Kind::BLOB> {
|
||||
static inline const typename T::Reader& apply(const typename T::Reader& t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Reader>
|
||||
inline Orphan<FromReader<Reader>> Orphanage::newOrphanCopy(Reader copyFrom) const {
|
||||
return Orphan<FromReader<Reader>>(_::OrphanBuilder::copy(
|
||||
arena, capTable, GetInnerReader<FromReader<Reader>>::apply(copyFrom)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Orphan<List<ListElementType<FromReader<T>>>>
|
||||
Orphanage::newOrphanConcat(kj::ArrayPtr<T> lists) const {
|
||||
return newOrphanConcat(kj::implicitCast<kj::ArrayPtr<const T>>(lists));
|
||||
}
|
||||
template <typename T>
|
||||
inline Orphan<List<ListElementType<FromReader<T>>>>
|
||||
Orphanage::newOrphanConcat(kj::ArrayPtr<const T> lists) const {
|
||||
// Optimization / simplification: Rely on List<T>::Reader containing nothing except a
|
||||
// _::ListReader.
|
||||
static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?");
|
||||
kj::ArrayPtr<const _::ListReader> raw(
|
||||
reinterpret_cast<const _::ListReader*>(lists.begin()), lists.size());
|
||||
typedef ListElementType<FromReader<T>> Element;
|
||||
return Orphan<List<Element>>(
|
||||
_::OrphanBuilder::concat(arena, capTable,
|
||||
_::elementSizeForType<Element>(),
|
||||
_::minStructSizeForElement<Element>(), raw));
|
||||
}
|
||||
|
||||
inline Orphan<Data> Orphanage::referenceExternalData(Data::Reader data) const {
|
||||
return Orphan<Data>(_::OrphanBuilder::referenceExternalData(arena, data));
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "layout.h"
|
||||
#include "list.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace _ { // private
|
||||
|
||||
// PointerHelpers is a template class that assists in wrapping/unwrapping the low-level types in
|
||||
// layout.h with the high-level public API and generated types. This way, the code generator
|
||||
// and other templates do not have to specialize on each kind of pointer.
|
||||
|
||||
template <typename T>
|
||||
struct PointerHelpers<T, Kind::STRUCT> {
|
||||
static inline typename T::Reader get(PointerReader reader, const word* defaultValue = nullptr) {
|
||||
return typename T::Reader(reader.getStruct(defaultValue));
|
||||
}
|
||||
static inline typename T::Builder get(PointerBuilder builder,
|
||||
const word* defaultValue = nullptr) {
|
||||
return typename T::Builder(builder.getStruct(structSize<T>(), defaultValue));
|
||||
}
|
||||
static inline void set(PointerBuilder builder, typename T::Reader value) {
|
||||
builder.setStruct(value._reader);
|
||||
}
|
||||
static inline void setCanonical(PointerBuilder builder, typename T::Reader value) {
|
||||
builder.setStruct(value._reader, true);
|
||||
}
|
||||
static inline typename T::Builder init(PointerBuilder builder) {
|
||||
return typename T::Builder(builder.initStruct(structSize<T>()));
|
||||
}
|
||||
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
|
||||
builder.adopt(kj::mv(value.builder));
|
||||
}
|
||||
static inline Orphan<T> disown(PointerBuilder builder) {
|
||||
return Orphan<T>(builder.disown());
|
||||
}
|
||||
static inline _::StructReader getInternalReader(const typename T::Reader& reader) {
|
||||
return reader._reader;
|
||||
}
|
||||
static inline _::StructBuilder getInternalBuilder(typename T::Builder&& builder) {
|
||||
return builder._builder;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PointerHelpers<List<T>, Kind::LIST> {
|
||||
static inline typename List<T>::Reader get(PointerReader reader,
|
||||
const word* defaultValue = nullptr) {
|
||||
return typename List<T>::Reader(List<T>::getFromPointer(reader, defaultValue));
|
||||
}
|
||||
static inline typename List<T>::Builder get(PointerBuilder builder,
|
||||
const word* defaultValue = nullptr) {
|
||||
return typename List<T>::Builder(List<T>::getFromPointer(builder, defaultValue));
|
||||
}
|
||||
static inline void set(PointerBuilder builder, typename List<T>::Reader value) {
|
||||
builder.setList(value.reader);
|
||||
}
|
||||
static inline void setCanonical(PointerBuilder builder, typename List<T>::Reader value) {
|
||||
builder.setList(value.reader, true);
|
||||
}
|
||||
static void set(PointerBuilder builder, kj::ArrayPtr<const ReaderFor<T>> value) {
|
||||
auto l = init(builder, value.size());
|
||||
uint i = 0;
|
||||
for (auto& element: value) {
|
||||
l.set(i++, element);
|
||||
}
|
||||
}
|
||||
static inline typename List<T>::Builder init(PointerBuilder builder, uint size) {
|
||||
return typename List<T>::Builder(List<T>::initPointer(builder, size));
|
||||
}
|
||||
static inline void adopt(PointerBuilder builder, Orphan<List<T>>&& value) {
|
||||
builder.adopt(kj::mv(value.builder));
|
||||
}
|
||||
static inline Orphan<List<T>> disown(PointerBuilder builder) {
|
||||
return Orphan<List<T>>(builder.disown());
|
||||
}
|
||||
static inline _::ListReader getInternalReader(const typename List<T>::Reader& reader) {
|
||||
return reader.reader;
|
||||
}
|
||||
static inline _::ListBuilder getInternalBuilder(typename List<T>::Builder&& builder) {
|
||||
return builder.builder;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PointerHelpers<T, Kind::BLOB> {
|
||||
static inline typename T::Reader get(PointerReader reader,
|
||||
const void* defaultValue = nullptr,
|
||||
uint defaultBytes = 0) {
|
||||
return reader.getBlob<T>(defaultValue, bounded(defaultBytes) * BYTES);
|
||||
}
|
||||
static inline typename T::Builder get(PointerBuilder builder,
|
||||
const void* defaultValue = nullptr,
|
||||
uint defaultBytes = 0) {
|
||||
return builder.getBlob<T>(defaultValue, bounded(defaultBytes) * BYTES);
|
||||
}
|
||||
static inline void set(PointerBuilder builder, typename T::Reader value) {
|
||||
builder.setBlob<T>(value);
|
||||
}
|
||||
static inline void setCanonical(PointerBuilder builder, typename T::Reader value) {
|
||||
builder.setBlob<T>(value);
|
||||
}
|
||||
static inline typename T::Builder init(PointerBuilder builder, uint size) {
|
||||
return builder.initBlob<T>(bounded(size) * BYTES);
|
||||
}
|
||||
static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
|
||||
builder.adopt(kj::mv(value.builder));
|
||||
}
|
||||
static inline Orphan<T> disown(PointerBuilder builder) {
|
||||
return Orphan<T>(builder.disown());
|
||||
}
|
||||
};
|
||||
|
||||
struct UncheckedMessage {
|
||||
typedef const word* Reader;
|
||||
};
|
||||
|
||||
template <> struct Kind_<UncheckedMessage> { static constexpr Kind kind = Kind::OTHER; };
|
||||
|
||||
template <>
|
||||
struct PointerHelpers<UncheckedMessage> {
|
||||
// Reads an AnyPointer field as an unchecked message pointer. Requires that the containing
|
||||
// message is itself unchecked. This hack is currently private. It is used to locate default
|
||||
// values within encoded schemas.
|
||||
|
||||
static inline const word* get(PointerReader reader) {
|
||||
return reader.getUnchecked();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dynamic.h"
|
||||
#include <kj/string-tree.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
kj::StringTree prettyPrint(DynamicStruct::Reader value);
|
||||
kj::StringTree prettyPrint(DynamicStruct::Builder value);
|
||||
kj::StringTree prettyPrint(DynamicList::Reader value);
|
||||
kj::StringTree prettyPrint(DynamicList::Builder value);
|
||||
// Print the given Cap'n Proto struct or list with nice indentation. Note that you can pass any
|
||||
// struct or list reader or builder type to this method, since they can be implicitly converted
|
||||
// to one of the dynamic types.
|
||||
//
|
||||
// If you don't want indentation, just use the value's KJ stringifier (e.g. pass it to kj::str(),
|
||||
// any of the KJ debug macros, etc.).
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h" // for uint and friends
|
||||
|
||||
#if _MSC_VER && !defined(__clang__)
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
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__ || defined(__clang__)
|
||||
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__ || defined(__clang__)
|
||||
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`.
|
||||
|
||||
bool mayContainCapabilities = true;
|
||||
// See StructSchema::mayContainCapabilities.
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/schema.capnp.h>
|
||||
#include "message.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
template <typename T, typename CapnpPrivate = typename T::_capnpPrivate>
|
||||
inline schema::Node::Reader schemaProto() {
|
||||
// Get the schema::Node for this type's schema. This function works even in lite mode.
|
||||
return readMessageUnchecked<schema::Node>(CapnpPrivate::encodedSchema());
|
||||
}
|
||||
|
||||
template <typename T, uint64_t id = schemas::EnumInfo<T>::typeId>
|
||||
inline schema::Node::Reader schemaProto() {
|
||||
// Get the schema::Node for this type's schema. This function works even in lite mode.
|
||||
return readMessageUnchecked<schema::Node>(schemas::EnumInfo<T>::encodedSchema());
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "schema.h"
|
||||
#include <kj/memory.h>
|
||||
#include <kj/mutex.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class SchemaLoader {
|
||||
// Class which can be used to construct Schema objects from schema::Nodes as defined in
|
||||
// schema.capnp.
|
||||
//
|
||||
// It is a bad idea to use this class on untrusted input with exceptions disabled -- you may
|
||||
// be exposing yourself to denial-of-service attacks, as attackers can easily construct schemas
|
||||
// that are subtly inconsistent in a way that causes exceptions to be thrown either by
|
||||
// SchemaLoader or by the dynamic API when the schemas are subsequently used. If you enable and
|
||||
// properly catch exceptions, you should be OK -- assuming no bugs in the Cap'n Proto
|
||||
// implementation, of course.
|
||||
|
||||
public:
|
||||
class LazyLoadCallback {
|
||||
public:
|
||||
virtual void load(const SchemaLoader& loader, uint64_t id) const = 0;
|
||||
// Request that the schema node with the given ID be loaded into the given SchemaLoader. If
|
||||
// the callback is able to find a schema for this ID, it should invoke `loadOnce()` on
|
||||
// `loader` to load it. If no such node exists, it should simply do nothing and return.
|
||||
//
|
||||
// The callback is allowed to load schema nodes other than the one requested, e.g. because it
|
||||
// expects they will be needed soon.
|
||||
//
|
||||
// If the `SchemaLoader` is used from multiple threads, the callback must be thread-safe.
|
||||
// In particular, it's possible for multiple threads to invoke `load()` with the same ID.
|
||||
// If the callback performs a large amount of work to look up IDs, it should be sure to
|
||||
// de-dup these requests.
|
||||
};
|
||||
|
||||
SchemaLoader();
|
||||
|
||||
SchemaLoader(const LazyLoadCallback& callback);
|
||||
// Construct a SchemaLoader which will invoke the given callback when a schema node is requested
|
||||
// that isn't already loaded.
|
||||
|
||||
~SchemaLoader() noexcept(false);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(SchemaLoader);
|
||||
|
||||
Schema get(uint64_t id, schema::Brand::Reader brand = schema::Brand::Reader(),
|
||||
Schema scope = Schema()) const;
|
||||
// Gets the schema for the given ID, throwing an exception if it isn't present.
|
||||
//
|
||||
// The returned schema may be invalidated if load() is called with a new schema for the same ID.
|
||||
// In general, you should not call load() while a schema from this loader is in-use.
|
||||
//
|
||||
// `brand` and `scope` are used to determine brand bindings where relevant. `brand` gives
|
||||
// parameter bindings for the target type's brand parameters that were specified at the reference
|
||||
// site. `scope` specifies the scope in which the type ID appeared -- if `brand` itself contains
|
||||
// parameter references or indicates that some parameters will be inherited, these will be
|
||||
// interpreted within / inherited from `scope`.
|
||||
|
||||
kj::Maybe<Schema> tryGet(uint64_t id, schema::Brand::Reader bindings = schema::Brand::Reader(),
|
||||
Schema scope = Schema()) const;
|
||||
// Like get() but doesn't throw.
|
||||
|
||||
Schema getUnbound(uint64_t id) const;
|
||||
// Gets a special version of the schema in which all brand parameters are "unbound". This means
|
||||
// that if you look up a type via the Schema API, and it resolves to a brand parameter, the
|
||||
// returned Type's getBrandParameter() method will return info about that parameter. Otherwise,
|
||||
// normally, all brand parameters that aren't otherwise bound are assumed to simply be
|
||||
// "AnyPointer".
|
||||
|
||||
Type getType(schema::Type::Reader type, Schema scope = Schema()) const;
|
||||
// Convenience method which interprets a schema::Type to produce a Type object. Implemented in
|
||||
// terms of get().
|
||||
|
||||
Schema load(const schema::Node::Reader& reader);
|
||||
// Loads the given schema node. Validates the node and throws an exception if invalid. This
|
||||
// makes a copy of the schema, so the object passed in can be destroyed after this returns.
|
||||
//
|
||||
// If the node has any dependencies which are not already loaded, they will be initialized as
|
||||
// stubs -- empty schemas of whichever kind is expected.
|
||||
//
|
||||
// If another schema for the given reader has already been seen, the loader will inspect both
|
||||
// schemas to determine which one is newer, and use that that one. If the two versions are
|
||||
// found to be incompatible, an exception is thrown. If the two versions differ but are
|
||||
// compatible and the loader cannot determine which is newer (e.g., the only changes are renames),
|
||||
// the existing schema will be preferred. Note that in any case, the loader will end up keeping
|
||||
// around copies of both schemas, so you shouldn't repeatedly reload schemas into the same loader.
|
||||
//
|
||||
// The following properties of the schema node are validated:
|
||||
// - Struct size and preferred list encoding are valid and consistent.
|
||||
// - Struct members are fields or unions.
|
||||
// - Union members are fields.
|
||||
// - Field offsets are in-bounds.
|
||||
// - Ordinals and codeOrders are sequential starting from zero.
|
||||
// - Values are of the right union case to match their types.
|
||||
//
|
||||
// You should assume anything not listed above is NOT validated. In particular, things that are
|
||||
// not validated now, but could be in the future, include but are not limited to:
|
||||
// - Names.
|
||||
// - Annotation values. (This is hard because the annotation declaration is not always
|
||||
// available.)
|
||||
// - Content of default/constant values of pointer type. (Validating these would require knowing
|
||||
// their schema, but even if the schemas are available at validation time, they could be
|
||||
// updated by a subsequent load(), invalidating existing values. Instead, these values are
|
||||
// validated at the time they are used, as usual for Cap'n Proto objects.)
|
||||
//
|
||||
// Also note that unknown types are not considered invalid. Instead, the dynamic API returns
|
||||
// a DynamicValue with type UNKNOWN for these.
|
||||
|
||||
Schema loadOnce(const schema::Node::Reader& reader) const;
|
||||
// Like `load()` but does nothing if a schema with the same ID is already loaded. In contrast,
|
||||
// `load()` would attempt to compare the schemas and take the newer one. `loadOnce()` is safe
|
||||
// to call even while concurrently using schemas from this loader. It should be considered an
|
||||
// error to call `loadOnce()` with two non-identical schemas that share the same ID, although
|
||||
// this error may or may not actually be detected by the implementation.
|
||||
|
||||
template <typename T>
|
||||
void loadCompiledTypeAndDependencies();
|
||||
// Load the schema for the given compiled-in type and all of its dependencies.
|
||||
//
|
||||
// If you want to be able to cast a DynamicValue built from this SchemaLoader to the compiled-in
|
||||
// type using as<T>(), you must call this method before constructing the DynamicValue. Otherwise,
|
||||
// as<T>() will throw an exception complaining about type mismatch.
|
||||
|
||||
kj::Array<Schema> getAllLoaded() const;
|
||||
// Get a complete list of all loaded schema nodes. It is particularly useful to call this after
|
||||
// loadCompiledTypeAndDependencies<T>() in order to get a flat list of all of T's transitive
|
||||
// dependencies.
|
||||
|
||||
void computeOptimizationHints();
|
||||
// Call after all interesting schemas have been loaded to compute optimization hints. In
|
||||
// particular, this initializes `hasNoCapabilities` for every struct type. Before this is called,
|
||||
// that value is initialized to false for all types (which ensures correct behavior but does not
|
||||
// allow the optimization).
|
||||
//
|
||||
// If any loaded struct types contain fields of types for which no schema has been loaded, they
|
||||
// will be presumed to possibly contain capabilities. `LazyLoadCallback` will NOT be invoked to
|
||||
// load any types that haven't been loaded yet.
|
||||
//
|
||||
// TODO(someday): Perhaps we could dynamically initialize the hints on-demand, but it would be
|
||||
// much more work to implement.
|
||||
|
||||
private:
|
||||
class Validator;
|
||||
class CompatibilityChecker;
|
||||
class Impl;
|
||||
class InitializerImpl;
|
||||
class BrandedInitializerImpl;
|
||||
kj::MutexGuarded<kj::Own<Impl>> impl;
|
||||
|
||||
void loadNative(const _::RawSchema* nativeSchema);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void SchemaLoader::loadCompiledTypeAndDependencies() {
|
||||
loadNative(&_::rawSchema<T>());
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "schema-loader.h"
|
||||
#include <kj/string.h>
|
||||
#include <kj/filesystem.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class ParsedSchema;
|
||||
class SchemaFile;
|
||||
|
||||
class SchemaParser {
|
||||
// Parses `.capnp` files to produce `Schema` objects.
|
||||
//
|
||||
// This class is thread-safe, hence all its methods are const.
|
||||
|
||||
public:
|
||||
SchemaParser();
|
||||
~SchemaParser() noexcept(false);
|
||||
|
||||
ParsedSchema parseFromDirectory(
|
||||
const kj::ReadableDirectory& baseDir, kj::Path path,
|
||||
kj::ArrayPtr<const kj::ReadableDirectory* const> importPath) const;
|
||||
// Parse a file from the KJ filesystem API. Throws an exception if the file doesn't exist.
|
||||
//
|
||||
// `baseDir` and `path` are used together to resolve relative imports. `path` is the source
|
||||
// file's path within `baseDir`. Relative imports will be interpreted relative to `path` and
|
||||
// will be opened using `baseDir`. Note that the KJ filesystem API prohibits "breaking out" of
|
||||
// a directory using "..", so relative imports will be restricted to children of `baseDir`.
|
||||
//
|
||||
// `importPath` is used for absolute imports (imports that start with a '/'). Each directory in
|
||||
// the array will be searched in order until a file is found.
|
||||
//
|
||||
// All `ReadableDirectory` objects must remain valid until the `SchemaParser` is destroyed. Also,
|
||||
// the `importPath` array must remain valid. `path` will be copied; it need not remain valid.
|
||||
//
|
||||
// This method is a shortcut, equivalent to:
|
||||
// parser.parseFile(SchemaFile::newDiskFile(baseDir, path, importPath))`;
|
||||
//
|
||||
// This method throws an exception if any errors are encountered in the file or in anything the
|
||||
// file depends on. Note that merely importing another file does not count as a dependency on
|
||||
// anything in the imported file -- only the imported types which are actually used are
|
||||
// "dependencies".
|
||||
//
|
||||
// Hint: Use kj::newDiskFilesystem() to initialize the KJ filesystem API. Usually you should do
|
||||
// this at a high level in your program, e.g. the main() function, and then pass down the
|
||||
// appropriate File/Directory objects to the components that need them. Example:
|
||||
//
|
||||
// auto fs = kj::newDiskFilesystem();
|
||||
// SchemaParser parser;
|
||||
// auto schema = parser.parseFromDirectory(fs->getCurrent(),
|
||||
// kj::Path::parse("foo/bar.capnp"), nullptr);
|
||||
//
|
||||
// Hint: To use in-memory data rather than real disk, you can use kj::newInMemoryDirectory(),
|
||||
// write the files you want, then pass it to SchemaParser. Example:
|
||||
//
|
||||
// auto dir = kj::newInMemoryDirectory(kj::nullClock());
|
||||
// auto path = kj::Path::parse("foo/bar.capnp");
|
||||
// dir->openFile(path, kj::WriteMode::CREATE | kj::WriteMode::CREATE_PARENT)
|
||||
// ->writeAll("struct Foo {}");
|
||||
// auto schema = parser.parseFromDirectory(*dir, path, nullptr);
|
||||
//
|
||||
// Hint: You can create an in-memory directory but then populate it with real files from disk,
|
||||
// in order to control what is visible while also avoiding reading files yourself or making
|
||||
// extra copies. Example:
|
||||
//
|
||||
// auto fs = kj::newDiskFilesystem();
|
||||
// auto dir = kj::newInMemoryDirectory(kj::nullClock());
|
||||
// auto fakePath = kj::Path::parse("foo/bar.capnp");
|
||||
// auto realPath = kj::Path::parse("path/to/some/file.capnp");
|
||||
// dir->transfer(fakePath, kj::WriteMode::CREATE | kj::WriteMode::CREATE_PARENT,
|
||||
// fs->getCurrent(), realPath, kj::TransferMode::LINK);
|
||||
// auto schema = parser.parseFromDirectory(*dir, fakePath, nullptr);
|
||||
//
|
||||
// In this example, note that any imports in the file will fail, since the in-memory directory
|
||||
// you created contains no files except the specific one you linked in.
|
||||
|
||||
ParsedSchema parseDiskFile(kj::StringPtr displayName, kj::StringPtr diskPath,
|
||||
kj::ArrayPtr<const kj::StringPtr> importPath) const
|
||||
CAPNP_DEPRECATED("Use parseFromDirectory() instead.");
|
||||
// Creates a private kj::Filesystem and uses it to parse files from the real disk.
|
||||
//
|
||||
// DO NOT USE in new code. Use parseFromDirectory() instead.
|
||||
//
|
||||
// This API has a serious problem: the file can import and embed files located anywhere on disk
|
||||
// using relative paths. Even if you specify no `importPath`, relative imports still work. By
|
||||
// using `parseFromDirectory()`, you can arrange so that imports are only allowed within a
|
||||
// particular directory, or even set up a dummy filesystem where other files are not visible.
|
||||
|
||||
void setDiskFilesystem(kj::Filesystem& fs)
|
||||
CAPNP_DEPRECATED("Use parseFromDirectory() instead.");
|
||||
// Call before calling parseDiskFile() to choose an alternative disk filesystem implementation.
|
||||
// This exists mostly for testing purposes; new code should use parseFromDirectory() instead.
|
||||
//
|
||||
// If parseDiskFile() is called without having called setDiskFilesystem(), then
|
||||
// kj::newDiskFilesystem() will be used instead.
|
||||
|
||||
ParsedSchema parseFile(kj::Own<SchemaFile>&& file) const;
|
||||
// Advanced interface for parsing a file that may or may not be located in any global namespace.
|
||||
// Most users will prefer `parseFromDirectory()`.
|
||||
//
|
||||
// If the file has already been parsed (that is, a SchemaFile that compares equal to this one
|
||||
// was parsed previously), the existing schema will be returned again.
|
||||
//
|
||||
// This method reports errors by calling SchemaFile::reportError() on the file where the error
|
||||
// is located. If that call does not throw an exception, `parseFile()` may in fact return
|
||||
// normally. In this case, the result is a best-effort attempt to compile the schema, but it
|
||||
// may be invalid or corrupt, and using it for anything may cause exceptions to be thrown.
|
||||
|
||||
kj::Maybe<schema::Node::SourceInfo::Reader> getSourceInfo(Schema schema) const;
|
||||
// Look up source info (e.g. doc comments) for the given schema, which must have come from this
|
||||
// SchemaParser. Note that this will also work for implicit group and param types that don't have
|
||||
// a type name hence don't have a `ParsedSchema`.
|
||||
|
||||
template <typename T>
|
||||
inline void loadCompiledTypeAndDependencies() {
|
||||
// See SchemaLoader::loadCompiledTypeAndDependencies().
|
||||
getLoader().loadCompiledTypeAndDependencies<T>();
|
||||
}
|
||||
|
||||
kj::Array<Schema> getAllLoaded() const {
|
||||
// Gets an array of all schema nodes that have been parsed so far.
|
||||
return getLoader().getAllLoaded();
|
||||
}
|
||||
|
||||
void setFileIdsRequired(bool value) { fileIdsRequired = value; }
|
||||
// By befault, capnp files must declare a file-level type ID (like `@0xbe702824338d3f7f;`).
|
||||
// Use `setFileIdsReqired(false)` to lift this requirement.
|
||||
//
|
||||
// If no ID is specified, a random one will be assigned. This will cause all types declared in
|
||||
// the file to have randomized IDs as well (unless they declare an ID explicitly), which means
|
||||
// that parsing the same file twice will appear to to produce a totally new, incompatible set of
|
||||
// types. In particular, this means that you will not be able to use any interface types in the
|
||||
// file for RPC, since the RPC protocol uses type IDs to identify methods.
|
||||
//
|
||||
// Setting this false is particularly useful when using Cap'n Proto as a config format. Typically
|
||||
// type IDs are irrelevant for config files, and the requirement to specify one is cumbersome.
|
||||
// For this reason, `capnp eval` does not require type ID to be present.
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
struct DiskFileCompat;
|
||||
class ModuleImpl;
|
||||
kj::Own<Impl> impl;
|
||||
mutable bool hadErrors = false;
|
||||
bool fileIdsRequired = true;
|
||||
|
||||
ModuleImpl& getModuleImpl(kj::Own<SchemaFile>&& file) const;
|
||||
const SchemaLoader& getLoader() const;
|
||||
SchemaLoader& getLoader();
|
||||
|
||||
friend class ParsedSchema;
|
||||
};
|
||||
|
||||
class ParsedSchema: public Schema {
|
||||
// ParsedSchema is an extension of Schema which also has the ability to look up nested nodes
|
||||
// by name. See `SchemaParser`.
|
||||
|
||||
class ParsedSchemaList;
|
||||
friend class ParsedSchemaList;
|
||||
|
||||
public:
|
||||
inline ParsedSchema(): parser(nullptr) {}
|
||||
|
||||
kj::Maybe<ParsedSchema> findNested(kj::StringPtr name) const;
|
||||
// Gets the nested node with the given name, or returns null if there is no such nested
|
||||
// declaration.
|
||||
|
||||
ParsedSchema getNested(kj::StringPtr name) const;
|
||||
// Gets the nested node with the given name, or throws an exception if there is no such nested
|
||||
// declaration.
|
||||
|
||||
ParsedSchemaList getAllNested() const;
|
||||
// Get all the nested nodes
|
||||
|
||||
schema::Node::SourceInfo::Reader getSourceInfo() const;
|
||||
// Get the source info for this schema.
|
||||
|
||||
private:
|
||||
inline ParsedSchema(Schema inner, const SchemaParser& parser): Schema(inner), parser(&parser) {}
|
||||
|
||||
const SchemaParser* parser;
|
||||
friend class SchemaParser;
|
||||
};
|
||||
|
||||
class ParsedSchema::ParsedSchemaList {
|
||||
public:
|
||||
ParsedSchemaList() = default; // empty list
|
||||
|
||||
inline uint size() const { return list.size(); }
|
||||
ParsedSchema operator[](uint index) const;
|
||||
|
||||
typedef _::IndexingIterator<const ParsedSchemaList, ParsedSchema> Iterator;
|
||||
inline Iterator begin() const { return Iterator(this, 0); }
|
||||
inline Iterator end() const { return Iterator(this, size()); }
|
||||
|
||||
private:
|
||||
ParsedSchema parent;
|
||||
List<schema::Node::NestedNode>::Reader list;
|
||||
|
||||
inline ParsedSchemaList(ParsedSchema parent, List<schema::Node::NestedNode>::Reader list)
|
||||
: parent(parent), list(list) {}
|
||||
|
||||
friend class ParsedSchema;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Advanced API
|
||||
|
||||
class SchemaFile {
|
||||
// Abstract interface representing a schema file. You can implement this yourself in order to
|
||||
// gain more control over how the compiler resolves imports and reads files. For the
|
||||
// common case of files on disk or other global filesystem-like namespaces, use
|
||||
// `SchemaFile::newDiskFile()`.
|
||||
|
||||
public:
|
||||
// Note: Cap'n Proto 0.6.x and below had classes FileReader and DiskFileReader and a method
|
||||
// newDiskFile() defined here. These were removed when SchemaParser was transitioned to use the
|
||||
// KJ filesystem API. You should be able to get the same effect by subclassing
|
||||
// kj::ReadableDirectory, or using kj::newInMemoryDirectory().
|
||||
|
||||
static kj::Own<SchemaFile> newFromDirectory(
|
||||
const kj::ReadableDirectory& baseDir, kj::Path path,
|
||||
kj::ArrayPtr<const kj::ReadableDirectory* const> importPath,
|
||||
kj::Maybe<kj::String> displayNameOverride = nullptr);
|
||||
// Construct a SchemaFile representing a file in a kj::ReadableDirectory. This is used to
|
||||
// implement SchemaParser::parseFromDirectory(); see there for details.
|
||||
//
|
||||
// The SchemaFile compares equal to any other SchemaFile that has exactly the same `baseDir`
|
||||
// object (by identity) and `path` (by value).
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// For more control, you can implement this interface.
|
||||
|
||||
virtual kj::StringPtr getDisplayName() const = 0;
|
||||
// Get the file's name, as it should appear in the schema.
|
||||
|
||||
virtual kj::Array<const char> readContent() const = 0;
|
||||
// Read the file's entire content and return it as a byte array.
|
||||
|
||||
virtual kj::Maybe<kj::Own<SchemaFile>> import(kj::StringPtr path) const = 0;
|
||||
// Resolve an import, relative to this file.
|
||||
//
|
||||
// `path` is exactly what appears between quotes after the `import` keyword in the source code.
|
||||
// It is entirely up to the `SchemaFile` to decide how to map this to another file. Typically,
|
||||
// a leading '/' means that the file is an "absolute" path and is searched for in some list of
|
||||
// schema file repositories. On the other hand, a path that doesn't start with '/' is relative
|
||||
// to the importing file.
|
||||
|
||||
virtual bool operator==(const SchemaFile& other) const = 0;
|
||||
virtual bool operator!=(const SchemaFile& other) const = 0;
|
||||
virtual size_t hashCode() const = 0;
|
||||
// Compare two SchemaFiles to see if they refer to the same underlying file. This is an
|
||||
// optimization used to avoid the need to re-parse a file to check its ID.
|
||||
|
||||
struct SourcePos {
|
||||
uint byte;
|
||||
uint line;
|
||||
uint column;
|
||||
};
|
||||
virtual void reportError(SourcePos start, SourcePos end, kj::StringPtr message) const = 0;
|
||||
// Report that the file contains an error at the given interval.
|
||||
|
||||
private:
|
||||
class DiskSchemaFile;
|
||||
};
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,320 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kj/async-io.h>
|
||||
#include <kj/io.h>
|
||||
#include "message.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
struct MessageReaderAndFds {
|
||||
kj::Own<MessageReader> reader;
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fds;
|
||||
};
|
||||
|
||||
struct MessageAndFds {
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments;
|
||||
kj::ArrayPtr<const int> fds;
|
||||
};
|
||||
|
||||
class MessageStream {
|
||||
// Interface over which messages can be sent and received; virtualizes
|
||||
// the functionality above.
|
||||
public:
|
||||
virtual kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessage(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr) = 0;
|
||||
// Read a message that may also have file descriptors attached, e.g. from a Unix socket with
|
||||
// SCM_RIGHTS. Returns null on EOF.
|
||||
//
|
||||
// `scratchSpace`, if provided, must remain valid until the returned MessageReader is destroyed.
|
||||
|
||||
kj::Promise<kj::Maybe<kj::Own<MessageReader>>> tryReadMessage(
|
||||
ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Equivalent to the above with fdSpace = nullptr.
|
||||
|
||||
kj::Promise<MessageReaderAndFds> readMessage(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
kj::Promise<kj::Own<MessageReader>> readMessage(
|
||||
ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Like tryReadMessage, but throws an exception on EOF.
|
||||
|
||||
virtual kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const int> fds,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments)
|
||||
KJ_WARN_UNUSED_RESULT = 0;
|
||||
kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const int> fds,
|
||||
MessageBuilder& builder)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
// Write a message with FDs attached, e.g. to a Unix socket with SCM_RIGHTS.
|
||||
// The parameters must remain valid until the returned promise resolves.
|
||||
|
||||
kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
kj::Promise<void> writeMessage(MessageBuilder& builder)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
// Equivalent to the above with fds = nullptr.
|
||||
|
||||
kj::Promise<void> writeMessages(
|
||||
kj::ArrayPtr<MessageAndFds> messages)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
virtual kj::Promise<void> writeMessages(
|
||||
kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages)
|
||||
KJ_WARN_UNUSED_RESULT = 0;
|
||||
kj::Promise<void> writeMessages(kj::ArrayPtr<MessageBuilder*> builders)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
// Similar to the above, but for writing multiple messages at a time in a batch.
|
||||
|
||||
virtual kj::Maybe<int> getSendBufferSize() = 0;
|
||||
// Get the size of the underlying send buffer, if applicable. The RPC
|
||||
// system uses this as a hint for flow control purposes; see:
|
||||
//
|
||||
// https://capnproto.org/news/2020-04-23-capnproto-0.8.html#multi-stream-flow-control
|
||||
//
|
||||
// ...for a more thorough explanation of how this is used. Implementations
|
||||
// may return nullptr if they do not have access to this information, or if
|
||||
// the underlying transport does not use a congestion window.
|
||||
|
||||
virtual kj::Promise<void> end() = 0;
|
||||
// Cleanly shut down just the write end of the transport, while keeping the read end open.
|
||||
|
||||
};
|
||||
|
||||
class AsyncIoMessageStream final: public MessageStream {
|
||||
// A MessageStream that wraps an AsyncIoStream.
|
||||
public:
|
||||
explicit AsyncIoMessageStream(kj::AsyncIoStream& stream);
|
||||
|
||||
// Implements MessageStream
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessage(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr) override;
|
||||
kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const int> fds,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) override;
|
||||
kj::Promise<void> writeMessages(
|
||||
kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages) override;
|
||||
kj::Maybe<int> getSendBufferSize() override;
|
||||
|
||||
kj::Promise<void> end() override;
|
||||
|
||||
// Make sure the overridden virtual methods don't hide the non-virtual methods.
|
||||
using MessageStream::tryReadMessage;
|
||||
using MessageStream::writeMessage;
|
||||
private:
|
||||
kj::AsyncIoStream& stream;
|
||||
};
|
||||
|
||||
class AsyncCapabilityMessageStream final: public MessageStream {
|
||||
// A MessageStream that wraps an AsyncCapabilityStream.
|
||||
public:
|
||||
explicit AsyncCapabilityMessageStream(kj::AsyncCapabilityStream& stream);
|
||||
|
||||
// Implements MessageStream
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessage(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr) override;
|
||||
kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const int> fds,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) override;
|
||||
kj::Promise<void> writeMessages(
|
||||
kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages) override;
|
||||
kj::Maybe<int> getSendBufferSize() override;
|
||||
kj::Promise<void> end() override;
|
||||
|
||||
// Make sure the overridden virtual methods don't hide the non-virtual methods.
|
||||
using MessageStream::tryReadMessage;
|
||||
using MessageStream::writeMessage;
|
||||
private:
|
||||
kj::AsyncCapabilityStream& stream;
|
||||
};
|
||||
|
||||
class BufferedMessageStream final: public MessageStream {
|
||||
// A MessageStream that reads into a buffer in the hopes of receiving multiple messages in a
|
||||
// single system call. Compared to the other implementations, this implementation is expected
|
||||
// to be faster when reading from an OS stream (but probably not when reading from an in-memory
|
||||
// async pipe). It has the down sides of using more memory (for the buffer) and requiring extra
|
||||
// copies.
|
||||
|
||||
public:
|
||||
using IsShortLivedCallback = kj::Function<bool(MessageReader&)>;
|
||||
// Callback function which decides whether a message will be "short-lived", meaning that it is
|
||||
// guaranteed to be dropped before the next message is read. The stream uses this as an
|
||||
// optimization to decide whether it can return a MessageReader pointing into the buffer, which
|
||||
// will be reused for future reads. For long-lived messages, the stream must copy the content
|
||||
// into a separate buffer.
|
||||
|
||||
explicit BufferedMessageStream(
|
||||
kj::AsyncIoStream& stream, IsShortLivedCallback isShortLivedCallback,
|
||||
size_t bufferSizeInWords = 8192);
|
||||
explicit BufferedMessageStream(
|
||||
kj::AsyncCapabilityStream& stream, IsShortLivedCallback isShortLivedCallback,
|
||||
size_t bufferSizeInWords = 8192);
|
||||
|
||||
// Implements MessageStream
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessage(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr) override;
|
||||
kj::Promise<void> writeMessage(
|
||||
kj::ArrayPtr<const int> fds,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) override;
|
||||
kj::Promise<void> writeMessages(
|
||||
kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages) override;
|
||||
kj::Maybe<int> getSendBufferSize() override;
|
||||
kj::Promise<void> end() override;
|
||||
|
||||
// Make sure the overridden virtual methods don't hide the non-virtual methods.
|
||||
using MessageStream::tryReadMessage;
|
||||
using MessageStream::writeMessage;
|
||||
|
||||
private:
|
||||
kj::AsyncIoStream& stream;
|
||||
kj::Maybe<kj::AsyncCapabilityStream&> capStream;
|
||||
IsShortLivedCallback isShortLivedCallback;
|
||||
|
||||
kj::Array<word> buffer;
|
||||
|
||||
word* beginData;
|
||||
// Pointer to location in `buffer` where the next message starts. This is always on a word
|
||||
// boundray since messages are always a whole number of words.
|
||||
|
||||
kj::byte* beginAvailable;
|
||||
// Pointer to the location in `buffer` where unused buffer space begins, i.e. immediately after
|
||||
// the last byte read.
|
||||
|
||||
kj::Vector<kj::AutoCloseFd> leftoverFds;
|
||||
// FDs which were accidentally read too early. These are always connected to the last message
|
||||
// in the buffer, since the OS would not have allowed us to read past that point.
|
||||
|
||||
bool hasOutstandingShortLivedMessage = false;
|
||||
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessageImpl(
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace, size_t fdsSoFar,
|
||||
ReaderOptions options, kj::ArrayPtr<word> scratchSpace);
|
||||
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> readEntireMessage(
|
||||
kj::ArrayPtr<const byte> prefix, size_t expectedSizeInWords,
|
||||
kj::ArrayPtr<kj::AutoCloseFd> fdSpace, size_t fdsSoFar,
|
||||
ReaderOptions options);
|
||||
// Given a message prefix and expected size of the whole message, read the entire message into
|
||||
// a single array and return it.
|
||||
|
||||
kj::Promise<kj::AsyncCapabilityStream::ReadResult> tryReadWithFds(
|
||||
void* buffer, size_t minBytes, size_t maxBytes, kj::AutoCloseFd* fdBuffer, size_t maxFds);
|
||||
// Executes AsyncCapabilityStream::tryReadWithFds() on the underlying stream, or falls back to
|
||||
// AsyncIoStream::tryRead() if it's not a capability stream.
|
||||
|
||||
class MessageReaderImpl;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Stand-alone functions for reading & writing messages on AsyncInput/AsyncOutputStreams.
|
||||
//
|
||||
// In general, foo(stream, ...) is equivalent to
|
||||
// AsyncIoMessageStream(stream).foo(...), whenever the latter would type check.
|
||||
//
|
||||
// The first argument must remain valid until the returned promise resolves
|
||||
// (or is canceled).
|
||||
|
||||
kj::Promise<kj::Own<MessageReader>> readMessage(
|
||||
kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
|
||||
kj::Promise<kj::Maybe<kj::Own<MessageReader>>> tryReadMessage(
|
||||
kj::AsyncInputStream& input, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
|
||||
kj::Promise<void> writeMessage(kj::AsyncOutputStream& output,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
|
||||
kj::Promise<void> writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Stand-alone versions that support FD passing.
|
||||
//
|
||||
// For each of these, `foo(stream, ...)` is equivalent to
|
||||
// `AsyncCapabilityMessageStream(stream).foo(...)`.
|
||||
|
||||
kj::Promise<MessageReaderAndFds> readMessage(
|
||||
kj::AsyncCapabilityStream& input, kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
|
||||
kj::Promise<kj::Maybe<MessageReaderAndFds>> tryReadMessage(
|
||||
kj::AsyncCapabilityStream& input, kj::ArrayPtr<kj::AutoCloseFd> fdSpace,
|
||||
ReaderOptions options = ReaderOptions(), kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
|
||||
kj::Promise<void> writeMessage(kj::AsyncCapabilityStream& output, kj::ArrayPtr<const int> fds,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
kj::Promise<void> writeMessage(kj::AsyncCapabilityStream& output, kj::ArrayPtr<const int> fds,
|
||||
MessageBuilder& builder)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Stand-alone functions for writing multiple messages at once on AsyncOutputStreams.
|
||||
|
||||
kj::Promise<void> writeMessages(kj::AsyncOutputStream& output,
|
||||
kj::ArrayPtr<kj::ArrayPtr<const kj::ArrayPtr<const word>>> messages)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
|
||||
kj::Promise<void> writeMessages(
|
||||
kj::AsyncOutputStream& output, kj::ArrayPtr<MessageBuilder*> builders)
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
|
||||
// =======================================================================================
|
||||
// inline implementation details
|
||||
|
||||
inline kj::Promise<void> writeMessage(kj::AsyncOutputStream& output, MessageBuilder& builder) {
|
||||
return writeMessage(output, builder.getSegmentsForOutput());
|
||||
}
|
||||
inline kj::Promise<void> writeMessage(
|
||||
kj::AsyncCapabilityStream& output, kj::ArrayPtr<const int> fds, MessageBuilder& builder) {
|
||||
return writeMessage(output, fds, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline kj::Promise<void> MessageStream::writeMessage(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
return writeMessage(nullptr, segments);
|
||||
}
|
||||
|
||||
inline kj::Promise<void> MessageStream::writeMessage(MessageBuilder& builder) {
|
||||
return writeMessage(builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline kj::Promise<void> MessageStream::writeMessage(
|
||||
kj::ArrayPtr<const int> fds, MessageBuilder& builder) {
|
||||
return writeMessage(fds, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
// 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.
|
||||
|
||||
#include "serialize-packed.h"
|
||||
#include <kj/debug.h>
|
||||
#include "layout.h"
|
||||
#include <vector>
|
||||
|
||||
namespace capnp {
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
PackedInputStream::PackedInputStream(kj::BufferedInputStream& inner): inner(inner) {}
|
||||
PackedInputStream::~PackedInputStream() noexcept(false) {}
|
||||
|
||||
size_t PackedInputStream::tryRead(void* dst, size_t minBytes, size_t maxBytes) {
|
||||
if (maxBytes == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
KJ_DREQUIRE(minBytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned.");
|
||||
KJ_DREQUIRE(maxBytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned.");
|
||||
|
||||
uint8_t* __restrict__ out = reinterpret_cast<uint8_t*>(dst);
|
||||
uint8_t* const outEnd = reinterpret_cast<uint8_t*>(dst) + maxBytes;
|
||||
uint8_t* const outMin = reinterpret_cast<uint8_t*>(dst) + minBytes;
|
||||
|
||||
kj::ArrayPtr<const byte> buffer = inner.tryGetReadBuffer();
|
||||
if (buffer.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
const uint8_t* __restrict__ in = reinterpret_cast<const uint8_t*>(buffer.begin());
|
||||
|
||||
#define REFRESH_BUFFER() \
|
||||
inner.skip(buffer.size()); \
|
||||
buffer = inner.getReadBuffer(); \
|
||||
KJ_REQUIRE(buffer.size() > 0, "Premature end of packed input.") { \
|
||||
return out - reinterpret_cast<uint8_t*>(dst); \
|
||||
} \
|
||||
in = reinterpret_cast<const uint8_t*>(buffer.begin())
|
||||
|
||||
#define BUFFER_END (reinterpret_cast<const uint8_t*>(buffer.end()))
|
||||
#define BUFFER_REMAINING ((size_t)(BUFFER_END - in))
|
||||
|
||||
for (;;) {
|
||||
uint8_t tag;
|
||||
|
||||
KJ_DASSERT((out - reinterpret_cast<uint8_t*>(dst)) % sizeof(word) == 0,
|
||||
"Output pointer should always be aligned here.");
|
||||
|
||||
if (BUFFER_REMAINING < 10) {
|
||||
if (out >= outMin) {
|
||||
// We read at least the minimum amount, so go ahead and return.
|
||||
inner.skip(in - reinterpret_cast<const uint8_t*>(buffer.begin()));
|
||||
return out - reinterpret_cast<uint8_t*>(dst);
|
||||
}
|
||||
|
||||
if (BUFFER_REMAINING == 0) {
|
||||
REFRESH_BUFFER();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have at least 1, but not 10, bytes available. We need to read slowly, doing a bounds
|
||||
// check on each byte.
|
||||
|
||||
tag = *in++;
|
||||
|
||||
for (uint i = 0; i < 8; i++) {
|
||||
if (tag & (1u << i)) {
|
||||
if (BUFFER_REMAINING == 0) {
|
||||
REFRESH_BUFFER();
|
||||
}
|
||||
*out++ = *in++;
|
||||
} else {
|
||||
*out++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (BUFFER_REMAINING == 0 && (tag == 0 || tag == 0xffu)) {
|
||||
REFRESH_BUFFER();
|
||||
}
|
||||
} else {
|
||||
tag = *in++;
|
||||
|
||||
#define HANDLE_BYTE(n) \
|
||||
{ \
|
||||
bool isNonzero = (tag & (1u << n)) != 0; \
|
||||
*out++ = *in & (-(int8_t)isNonzero); \
|
||||
in += isNonzero; \
|
||||
}
|
||||
|
||||
HANDLE_BYTE(0);
|
||||
HANDLE_BYTE(1);
|
||||
HANDLE_BYTE(2);
|
||||
HANDLE_BYTE(3);
|
||||
HANDLE_BYTE(4);
|
||||
HANDLE_BYTE(5);
|
||||
HANDLE_BYTE(6);
|
||||
HANDLE_BYTE(7);
|
||||
#undef HANDLE_BYTE
|
||||
}
|
||||
|
||||
if (tag == 0) {
|
||||
KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here.");
|
||||
|
||||
uint runLength = *in++ * sizeof(word);
|
||||
|
||||
KJ_REQUIRE(runLength <= outEnd - out,
|
||||
"Packed input did not end cleanly on a segment boundary.") {
|
||||
return out - reinterpret_cast<uint8_t*>(dst);
|
||||
}
|
||||
memset(out, 0, runLength);
|
||||
out += runLength;
|
||||
|
||||
} else if (tag == 0xffu) {
|
||||
KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here.");
|
||||
|
||||
uint runLength = *in++ * sizeof(word);
|
||||
|
||||
KJ_REQUIRE(runLength <= outEnd - out,
|
||||
"Packed input did not end cleanly on a segment boundary.") {
|
||||
return out - reinterpret_cast<uint8_t*>(dst);
|
||||
}
|
||||
|
||||
size_t inRemaining = BUFFER_REMAINING;
|
||||
if (inRemaining >= runLength) {
|
||||
// Fast path.
|
||||
memcpy(out, in, runLength);
|
||||
out += runLength;
|
||||
in += runLength;
|
||||
} else {
|
||||
// Copy over the first buffer, then do one big read for the rest.
|
||||
memcpy(out, in, inRemaining);
|
||||
out += inRemaining;
|
||||
runLength -= inRemaining;
|
||||
|
||||
inner.skip(buffer.size());
|
||||
inner.read(out, runLength);
|
||||
out += runLength;
|
||||
|
||||
if (out == outEnd) {
|
||||
return maxBytes;
|
||||
} else {
|
||||
buffer = inner.getReadBuffer();
|
||||
in = reinterpret_cast<const uint8_t*>(buffer.begin());
|
||||
|
||||
// Skip the bounds check below since we just did the same check above.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out == outEnd) {
|
||||
inner.skip(in - reinterpret_cast<const uint8_t*>(buffer.begin()));
|
||||
return maxBytes;
|
||||
}
|
||||
}
|
||||
|
||||
KJ_FAIL_ASSERT("Can't get here.");
|
||||
return 0; // GCC knows KJ_FAIL_ASSERT doesn't return, but Eclipse CDT still warns...
|
||||
|
||||
#undef REFRESH_BUFFER
|
||||
}
|
||||
|
||||
void PackedInputStream::skip(size_t bytes) {
|
||||
// We can't just read into buffers because buffers must end on block boundaries.
|
||||
|
||||
if (bytes == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
KJ_DREQUIRE(bytes % sizeof(word) == 0, "PackedInputStream reads must be word-aligned.");
|
||||
|
||||
kj::ArrayPtr<const byte> buffer = inner.getReadBuffer();
|
||||
const uint8_t* __restrict__ in = reinterpret_cast<const uint8_t*>(buffer.begin());
|
||||
|
||||
#define REFRESH_BUFFER() \
|
||||
inner.skip(buffer.size()); \
|
||||
buffer = inner.getReadBuffer(); \
|
||||
KJ_REQUIRE(buffer.size() > 0, "Premature end of packed input.") { return; } \
|
||||
in = reinterpret_cast<const uint8_t*>(buffer.begin())
|
||||
|
||||
for (;;) {
|
||||
uint8_t tag;
|
||||
|
||||
if (BUFFER_REMAINING < 10) {
|
||||
if (BUFFER_REMAINING == 0) {
|
||||
REFRESH_BUFFER();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have at least 1, but not 10, bytes available. We need to read slowly, doing a bounds
|
||||
// check on each byte.
|
||||
|
||||
tag = *in++;
|
||||
|
||||
for (uint i = 0; i < 8; i++) {
|
||||
if (tag & (1u << i)) {
|
||||
if (BUFFER_REMAINING == 0) {
|
||||
REFRESH_BUFFER();
|
||||
}
|
||||
in++;
|
||||
}
|
||||
}
|
||||
bytes -= 8;
|
||||
|
||||
if (BUFFER_REMAINING == 0 && (tag == 0 || tag == 0xffu)) {
|
||||
REFRESH_BUFFER();
|
||||
}
|
||||
} else {
|
||||
tag = *in++;
|
||||
|
||||
#define HANDLE_BYTE(n) \
|
||||
in += (tag & (1u << n)) != 0
|
||||
|
||||
HANDLE_BYTE(0);
|
||||
HANDLE_BYTE(1);
|
||||
HANDLE_BYTE(2);
|
||||
HANDLE_BYTE(3);
|
||||
HANDLE_BYTE(4);
|
||||
HANDLE_BYTE(5);
|
||||
HANDLE_BYTE(6);
|
||||
HANDLE_BYTE(7);
|
||||
#undef HANDLE_BYTE
|
||||
|
||||
bytes -= 8;
|
||||
}
|
||||
|
||||
if (tag == 0) {
|
||||
KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here.");
|
||||
|
||||
uint runLength = *in++ * sizeof(word);
|
||||
|
||||
KJ_REQUIRE(runLength <= bytes, "Packed input did not end cleanly on a segment boundary.") {
|
||||
return;
|
||||
}
|
||||
|
||||
bytes -= runLength;
|
||||
|
||||
} else if (tag == 0xffu) {
|
||||
KJ_DASSERT(BUFFER_REMAINING > 0, "Should always have non-empty buffer here.");
|
||||
|
||||
uint runLength = *in++ * sizeof(word);
|
||||
|
||||
KJ_REQUIRE(runLength <= bytes, "Packed input did not end cleanly on a segment boundary.") {
|
||||
return;
|
||||
}
|
||||
|
||||
bytes -= runLength;
|
||||
|
||||
size_t inRemaining = BUFFER_REMAINING;
|
||||
if (inRemaining > runLength) {
|
||||
// Fast path.
|
||||
in += runLength;
|
||||
} else {
|
||||
// Forward skip to the underlying stream.
|
||||
runLength -= inRemaining;
|
||||
inner.skip(buffer.size() + runLength);
|
||||
|
||||
if (bytes == 0) {
|
||||
return;
|
||||
} else {
|
||||
buffer = inner.getReadBuffer();
|
||||
in = reinterpret_cast<const uint8_t*>(buffer.begin());
|
||||
|
||||
// Skip the bounds check below since we just did the same check above.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes == 0) {
|
||||
inner.skip(in - reinterpret_cast<const uint8_t*>(buffer.begin()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
KJ_FAIL_ASSERT("Can't get here.");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
PackedOutputStream::PackedOutputStream(kj::BufferedOutputStream& inner)
|
||||
: inner(inner) {}
|
||||
PackedOutputStream::~PackedOutputStream() noexcept(false) {}
|
||||
|
||||
void PackedOutputStream::write(const void* src, size_t size) {
|
||||
kj::ArrayPtr<byte> buffer = inner.getWriteBuffer();
|
||||
byte slowBuffer[20];
|
||||
|
||||
uint8_t* __restrict__ out = reinterpret_cast<uint8_t*>(buffer.begin());
|
||||
|
||||
const uint8_t* __restrict__ in = reinterpret_cast<const uint8_t*>(src);
|
||||
const uint8_t* const inEnd = reinterpret_cast<const uint8_t*>(src) + size;
|
||||
|
||||
while (in < inEnd) {
|
||||
if (reinterpret_cast<uint8_t*>(buffer.end()) - out < 10) {
|
||||
// Oops, we're out of space. We need at least 10 bytes for the fast path, since we don't
|
||||
// bounds-check on every byte.
|
||||
|
||||
// Write what we have so far.
|
||||
inner.write(buffer.begin(), out - reinterpret_cast<uint8_t*>(buffer.begin()));
|
||||
|
||||
// Use a slow buffer into which we'll encode 10 to 20 bytes. This should get us past the
|
||||
// output stream's buffer boundary.
|
||||
buffer = kj::arrayPtr(slowBuffer, sizeof(slowBuffer));
|
||||
out = reinterpret_cast<uint8_t*>(buffer.begin());
|
||||
}
|
||||
|
||||
uint8_t* tagPos = out++;
|
||||
|
||||
#define HANDLE_BYTE(n) \
|
||||
uint8_t bit##n = *in != 0; \
|
||||
*out = *in; \
|
||||
out += bit##n; /* out only advances if the byte was non-zero */ \
|
||||
++in
|
||||
|
||||
HANDLE_BYTE(0);
|
||||
HANDLE_BYTE(1);
|
||||
HANDLE_BYTE(2);
|
||||
HANDLE_BYTE(3);
|
||||
HANDLE_BYTE(4);
|
||||
HANDLE_BYTE(5);
|
||||
HANDLE_BYTE(6);
|
||||
HANDLE_BYTE(7);
|
||||
#undef HANDLE_BYTE
|
||||
|
||||
uint8_t tag = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
|
||||
| (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);
|
||||
*tagPos = tag;
|
||||
|
||||
if (tag == 0) {
|
||||
// An all-zero word is followed by a count of consecutive zero words (not including the
|
||||
// first one).
|
||||
|
||||
// We can check a whole word at a time. (Here is where we use the assumption that
|
||||
// `src` is word-aligned.)
|
||||
const uint64_t* inWord = reinterpret_cast<const uint64_t*>(in);
|
||||
|
||||
// The count must fit it 1 byte, so limit to 255 words.
|
||||
const uint64_t* limit = reinterpret_cast<const uint64_t*>(inEnd);
|
||||
if (limit - inWord > 255) {
|
||||
limit = inWord + 255;
|
||||
}
|
||||
|
||||
while (inWord < limit && *inWord == 0) {
|
||||
++inWord;
|
||||
}
|
||||
|
||||
// Write the count.
|
||||
*out++ = inWord - reinterpret_cast<const uint64_t*>(in);
|
||||
|
||||
// Advance input.
|
||||
in = reinterpret_cast<const uint8_t*>(inWord);
|
||||
|
||||
} else if (tag == 0xffu) {
|
||||
// An all-nonzero word is followed by a count of consecutive uncompressed words, followed
|
||||
// by the uncompressed words themselves.
|
||||
|
||||
// Count the number of consecutive words in the input which have no more than a single
|
||||
// zero-byte. We look for at least two zeros because that's the point where our compression
|
||||
// scheme becomes a net win.
|
||||
// TODO(perf): Maybe look for three zeros? Compressing a two-zero word is a loss if the
|
||||
// following word has no zeros.
|
||||
const uint8_t* runStart = in;
|
||||
|
||||
const uint8_t* limit = inEnd;
|
||||
if ((size_t)(limit - in) > 255 * sizeof(word)) {
|
||||
limit = in + 255 * sizeof(word);
|
||||
}
|
||||
|
||||
while (in < limit) {
|
||||
// Check eight input bytes for zeros.
|
||||
uint c = *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
c += *in++ == 0;
|
||||
|
||||
if (c >= 2) {
|
||||
// Un-read the word with multiple zeros, since we'll want to compress that one.
|
||||
in -= 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the count.
|
||||
uint count = in - runStart;
|
||||
*out++ = count / sizeof(word);
|
||||
|
||||
if (count <= reinterpret_cast<uint8_t*>(buffer.end()) - out) {
|
||||
// There's enough space to memcpy.
|
||||
memcpy(out, runStart, count);
|
||||
out += count;
|
||||
} else {
|
||||
// Input overruns the output buffer. We'll give it to the output stream in one chunk
|
||||
// and let it decide what to do.
|
||||
inner.write(buffer.begin(), reinterpret_cast<byte*>(out) - buffer.begin());
|
||||
inner.write(runStart, in - runStart);
|
||||
buffer = inner.getWriteBuffer();
|
||||
out = reinterpret_cast<uint8_t*>(buffer.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write whatever is left.
|
||||
inner.write(buffer.begin(), reinterpret_cast<byte*>(out) - buffer.begin());
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
PackedMessageReader::PackedMessageReader(
|
||||
kj::BufferedInputStream& inputStream, ReaderOptions options, kj::ArrayPtr<word> scratchSpace)
|
||||
: PackedInputStream(inputStream),
|
||||
InputStreamMessageReader(static_cast<PackedInputStream&>(*this), options, scratchSpace) {}
|
||||
|
||||
PackedMessageReader::~PackedMessageReader() noexcept(false) {}
|
||||
|
||||
PackedFdMessageReader::PackedFdMessageReader(
|
||||
int fd, ReaderOptions options, kj::ArrayPtr<word> scratchSpace)
|
||||
: FdInputStream(fd),
|
||||
BufferedInputStreamWrapper(static_cast<FdInputStream&>(*this)),
|
||||
PackedMessageReader(static_cast<BufferedInputStreamWrapper&>(*this),
|
||||
options, scratchSpace) {}
|
||||
|
||||
PackedFdMessageReader::PackedFdMessageReader(
|
||||
kj::AutoCloseFd fd, ReaderOptions options, kj::ArrayPtr<word> scratchSpace)
|
||||
: FdInputStream(kj::mv(fd)),
|
||||
BufferedInputStreamWrapper(static_cast<FdInputStream&>(*this)),
|
||||
PackedMessageReader(static_cast<BufferedInputStreamWrapper&>(*this),
|
||||
options, scratchSpace) {}
|
||||
|
||||
PackedFdMessageReader::~PackedFdMessageReader() noexcept(false) {}
|
||||
|
||||
void writePackedMessage(kj::BufferedOutputStream& output,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
_::PackedOutputStream packedOutput(output);
|
||||
writeMessage(packedOutput, segments);
|
||||
}
|
||||
|
||||
void writePackedMessage(kj::OutputStream& output,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
KJ_IF_MAYBE(bufferedOutputPtr, kj::dynamicDowncastIfAvailable<kj::BufferedOutputStream>(output)) {
|
||||
writePackedMessage(*bufferedOutputPtr, segments);
|
||||
} else {
|
||||
byte buffer[8192];
|
||||
kj::BufferedOutputStreamWrapper bufferedOutput(output, kj::arrayPtr(buffer, sizeof(buffer)));
|
||||
writePackedMessage(bufferedOutput, segments);
|
||||
}
|
||||
}
|
||||
|
||||
void writePackedMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
kj::FdOutputStream output(fd);
|
||||
writePackedMessage(output, segments);
|
||||
}
|
||||
|
||||
size_t computeUnpackedSizeInWords(kj::ArrayPtr<const byte> packedBytes) {
|
||||
const byte* ptr = packedBytes.begin();
|
||||
const byte* end = packedBytes.end();
|
||||
|
||||
size_t total = 0;
|
||||
while (ptr < end) {
|
||||
uint tag = *ptr;
|
||||
size_t count = kj::popCount(tag);
|
||||
total += 1;
|
||||
KJ_REQUIRE(end - ptr >= count, "invalid packed data");
|
||||
ptr += count + 1;
|
||||
|
||||
if (tag == 0) {
|
||||
KJ_REQUIRE(ptr < end, "invalid packed data");
|
||||
total += *ptr++;
|
||||
} else if (tag == 0xff) {
|
||||
KJ_REQUIRE(ptr < end, "invalid packed data");
|
||||
size_t words = *ptr++;
|
||||
total += words;
|
||||
size_t bytes = words * sizeof(word);
|
||||
KJ_REQUIRE(end - ptr >= bytes, "invalid packed data");
|
||||
ptr += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serialize.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class PackedInputStream: public kj::InputStream {
|
||||
// An input stream that unpacks packed data with a picky constraint: The caller must read data
|
||||
// in the exact same size and sequence as the data was written to PackedOutputStream.
|
||||
|
||||
public:
|
||||
explicit PackedInputStream(kj::BufferedInputStream& inner);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(PackedInputStream);
|
||||
~PackedInputStream() noexcept(false);
|
||||
|
||||
// implements InputStream ------------------------------------------
|
||||
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
|
||||
void skip(size_t bytes) override;
|
||||
|
||||
private:
|
||||
kj::BufferedInputStream& inner;
|
||||
};
|
||||
|
||||
class PackedOutputStream: public kj::OutputStream {
|
||||
// An output stream that packs data. Buffers passed to `write()` must be word-aligned.
|
||||
public:
|
||||
explicit PackedOutputStream(kj::BufferedOutputStream& inner);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(PackedOutputStream);
|
||||
~PackedOutputStream() noexcept(false);
|
||||
|
||||
// implements OutputStream -----------------------------------------
|
||||
void write(const void* buffer, size_t bytes) override;
|
||||
|
||||
private:
|
||||
kj::BufferedOutputStream& inner;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
class PackedMessageReader: private _::PackedInputStream, public InputStreamMessageReader {
|
||||
public:
|
||||
PackedMessageReader(kj::BufferedInputStream& inputStream, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
KJ_DISALLOW_COPY_AND_MOVE(PackedMessageReader);
|
||||
~PackedMessageReader() noexcept(false);
|
||||
};
|
||||
|
||||
class PackedFdMessageReader: private kj::FdInputStream, private kj::BufferedInputStreamWrapper,
|
||||
public PackedMessageReader {
|
||||
public:
|
||||
PackedFdMessageReader(int fd, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Read message from a file descriptor, without taking ownership of the descriptor.
|
||||
// Note that if you want to reuse the descriptor after the reader is destroyed, you'll need to
|
||||
// seek it, since otherwise the position is unspecified.
|
||||
|
||||
PackedFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Read a message from a file descriptor, taking ownership of the descriptor.
|
||||
|
||||
KJ_DISALLOW_COPY_AND_MOVE(PackedFdMessageReader);
|
||||
|
||||
~PackedFdMessageReader() noexcept(false);
|
||||
};
|
||||
|
||||
void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder);
|
||||
void writePackedMessage(kj::BufferedOutputStream& output,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Write a packed message to a buffered output stream.
|
||||
|
||||
void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder);
|
||||
void writePackedMessage(kj::OutputStream& output,
|
||||
kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Write a packed message to an unbuffered output stream. If you intend to write multiple messages
|
||||
// in succession, consider wrapping your output in a buffered stream in order to reduce system
|
||||
// call overhead.
|
||||
|
||||
void writePackedMessageToFd(int fd, MessageBuilder& builder);
|
||||
void writePackedMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Write a single packed message to the file descriptor.
|
||||
|
||||
size_t computeUnpackedSizeInWords(kj::ArrayPtr<const byte> packedBytes);
|
||||
// Computes the number of words to which the given packed bytes will unpack. Not intended for use
|
||||
// in performance-sensitive situations.
|
||||
|
||||
// =======================================================================================
|
||||
// inline stuff
|
||||
|
||||
inline void writePackedMessage(kj::BufferedOutputStream& output, MessageBuilder& builder) {
|
||||
writePackedMessage(output, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline void writePackedMessage(kj::OutputStream& output, MessageBuilder& builder) {
|
||||
writePackedMessage(output, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline void writePackedMessageToFd(int fd, MessageBuilder& builder) {
|
||||
writePackedMessageToFd(fd, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2015 Philip Quinn.
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kj/string.h>
|
||||
#include "dynamic.h"
|
||||
#include "orphan.h"
|
||||
#include "schema.h"
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class TextCodec {
|
||||
// Reads and writes Cap'n Proto objects in a plain text format (as used in the schema
|
||||
// language for constants, and read/written by the 'decode' and 'encode' commands of
|
||||
// the capnp tool).
|
||||
//
|
||||
// This format is useful for debugging or human input, but it is not a robust alternative
|
||||
// to the binary format. Changes to a schema's types or names that are permitted in a
|
||||
// schema's binary evolution will likely break messages stored in this format.
|
||||
//
|
||||
// Note that definitions or references (to constants, other fields, or files) are not
|
||||
// permitted in this format. To evaluate declarations with the full expressiveness of the
|
||||
// schema language, see `capnp::SchemaParser`.
|
||||
//
|
||||
// Requires linking with the capnpc library.
|
||||
|
||||
public:
|
||||
TextCodec();
|
||||
~TextCodec() noexcept(true);
|
||||
|
||||
void setPrettyPrint(bool enabled);
|
||||
// If enabled, pads the output of `encode()` with spaces and newlines to make it more
|
||||
// human-readable.
|
||||
|
||||
template <typename T>
|
||||
kj::String encode(T&& value) const;
|
||||
kj::String encode(DynamicValue::Reader value) const;
|
||||
// Encode any Cap'n Proto value.
|
||||
|
||||
template <typename T>
|
||||
Orphan<T> decode(kj::StringPtr input, Orphanage orphanage) const;
|
||||
// Decode a text message into a Cap'n Proto object of type T, allocated in the given
|
||||
// orphanage. Any errors parsing the input or assigning the fields of T are thrown as
|
||||
// exceptions.
|
||||
|
||||
void decode(kj::StringPtr input, DynamicStruct::Builder output) const;
|
||||
// Decode a text message for a struct into the given builder. Any errors parsing the
|
||||
// input or assigning the fields of the output are thrown as exceptions.
|
||||
|
||||
// TODO(someday): expose some control over the error handling?
|
||||
private:
|
||||
Orphan<DynamicValue> decode(kj::StringPtr input, Type type, Orphanage orphanage) const;
|
||||
|
||||
bool prettyPrint;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// inline stuff
|
||||
|
||||
template <typename T>
|
||||
inline kj::String TextCodec::encode(T&& value) const {
|
||||
return encode(DynamicValue::Reader(ReaderFor<FromAny<T>>(kj::fwd<T>(value))));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Orphan<T> TextCodec::decode(kj::StringPtr input, Orphanage orphanage) const {
|
||||
return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
// 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.
|
||||
|
||||
#include "serialize.h"
|
||||
#include "layout.h"
|
||||
#include <kj/debug.h>
|
||||
#include <exception>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
namespace capnp {
|
||||
|
||||
FlatArrayMessageReader::FlatArrayMessageReader(
|
||||
kj::ArrayPtr<const word> array, ReaderOptions options)
|
||||
: MessageReader(options), end(array.end()) {
|
||||
if (array.size() < 1) {
|
||||
// Assume empty message.
|
||||
return;
|
||||
}
|
||||
|
||||
const _::WireValue<uint32_t>* table =
|
||||
reinterpret_cast<const _::WireValue<uint32_t>*>(array.begin());
|
||||
|
||||
uint segmentCount = table[0].get() + 1;
|
||||
size_t offset = segmentCount / 2u + 1u;
|
||||
|
||||
KJ_REQUIRE(array.size() >= offset, "Message ends prematurely in segment table.") {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
uint segmentSize = table[1].get();
|
||||
|
||||
KJ_REQUIRE(array.size() >= offset + segmentSize,
|
||||
"Message ends prematurely in first segment.") {
|
||||
return;
|
||||
}
|
||||
|
||||
segment0 = array.slice(offset, offset + segmentSize);
|
||||
offset += segmentSize;
|
||||
}
|
||||
|
||||
if (segmentCount > 1) {
|
||||
moreSegments = kj::heapArray<kj::ArrayPtr<const word>>(segmentCount - 1);
|
||||
|
||||
for (uint i = 1; i < segmentCount; i++) {
|
||||
uint segmentSize = table[i + 1].get();
|
||||
|
||||
KJ_REQUIRE(array.size() >= offset + segmentSize, "Message ends prematurely.") {
|
||||
moreSegments = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
moreSegments[i - 1] = array.slice(offset, offset + segmentSize);
|
||||
offset += segmentSize;
|
||||
}
|
||||
}
|
||||
|
||||
end = array.begin() + offset;
|
||||
}
|
||||
|
||||
size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr<const word> array) {
|
||||
if (array.size() < 1) {
|
||||
// All messages are at least one word.
|
||||
return 1;
|
||||
}
|
||||
|
||||
const _::WireValue<uint32_t>* table =
|
||||
reinterpret_cast<const _::WireValue<uint32_t>*>(array.begin());
|
||||
|
||||
uint segmentCount = table[0].get() + 1;
|
||||
size_t offset = segmentCount / 2u + 1u;
|
||||
|
||||
// If the array is too small to contain the full segment table, truncate segmentCount to just
|
||||
// what is available.
|
||||
segmentCount = kj::min(segmentCount, array.size() * 2 - 1u);
|
||||
|
||||
size_t totalSize = offset;
|
||||
for (uint i = 0; i < segmentCount; i++) {
|
||||
totalSize += table[i + 1].get();
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const word> FlatArrayMessageReader::getSegment(uint id) {
|
||||
if (id == 0) {
|
||||
return segment0;
|
||||
} else if (id <= moreSegments.size()) {
|
||||
return moreSegments[id - 1];
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const word> initMessageBuilderFromFlatArrayCopy(
|
||||
kj::ArrayPtr<const word> array, MessageBuilder& target, ReaderOptions options) {
|
||||
FlatArrayMessageReader reader(array, options);
|
||||
target.setRoot(reader.getRoot<AnyPointer>());
|
||||
return kj::arrayPtr(reader.getEnd(), array.end());
|
||||
}
|
||||
|
||||
kj::Array<word> messageToFlatArray(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
kj::Array<word> result = kj::heapArray<word>(computeSerializedSizeInWords(segments));
|
||||
|
||||
_::WireValue<uint32_t>* table =
|
||||
reinterpret_cast<_::WireValue<uint32_t>*>(result.begin());
|
||||
|
||||
// We write the segment count - 1 because this makes the first word zero for single-segment
|
||||
// messages, improving compression. We don't bother doing this with segment sizes because
|
||||
// one-word segments are rare anyway.
|
||||
table[0].set(segments.size() - 1);
|
||||
|
||||
for (uint i = 0; i < segments.size(); i++) {
|
||||
table[i + 1].set(segments[i].size());
|
||||
}
|
||||
|
||||
if (segments.size() % 2 == 0) {
|
||||
// Set padding byte.
|
||||
table[segments.size() + 1].set(0);
|
||||
}
|
||||
|
||||
word* dst = result.begin() + segments.size() / 2 + 1;
|
||||
|
||||
for (auto& segment: segments) {
|
||||
memcpy(dst, segment.begin(), segment.size() * sizeof(word));
|
||||
dst += segment.size();
|
||||
}
|
||||
|
||||
KJ_DASSERT(dst == result.end(), "Buffer overrun/underrun bug in code above.");
|
||||
|
||||
return kj::mv(result);
|
||||
}
|
||||
|
||||
size_t computeSerializedSizeInWords(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message.");
|
||||
|
||||
size_t totalSize = segments.size() / 2 + 1;
|
||||
|
||||
for (auto& segment: segments) {
|
||||
totalSize += segment.size();
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
InputStreamMessageReader::InputStreamMessageReader(
|
||||
kj::InputStream& inputStream, ReaderOptions options, kj::ArrayPtr<word> scratchSpace)
|
||||
: MessageReader(options), inputStream(inputStream), readPos(nullptr) {
|
||||
_::WireValue<uint32_t> firstWord[2];
|
||||
|
||||
inputStream.read(firstWord, sizeof(firstWord));
|
||||
|
||||
uint segmentCount = firstWord[0].get() + 1;
|
||||
uint segment0Size = segmentCount == 0 ? 0 : firstWord[1].get();
|
||||
|
||||
size_t totalWords = segment0Size;
|
||||
|
||||
// Reject messages with too many segments for security reasons.
|
||||
KJ_REQUIRE(segmentCount < 512, "Message has too many segments.") {
|
||||
segmentCount = 1;
|
||||
segment0Size = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Read sizes for all segments except the first. Include padding if necessary.
|
||||
KJ_STACK_ARRAY(_::WireValue<uint32_t>, moreSizes, segmentCount & ~1, 16, 64);
|
||||
if (segmentCount > 1) {
|
||||
inputStream.read(moreSizes.begin(), moreSizes.size() * sizeof(moreSizes[0]));
|
||||
for (uint i = 0; i < segmentCount - 1; i++) {
|
||||
totalWords += moreSizes[i].get();
|
||||
}
|
||||
}
|
||||
|
||||
// Don't accept a message which the receiver couldn't possibly traverse without hitting the
|
||||
// traversal limit. Without this check, a malicious client could transmit a very large segment
|
||||
// size to make the receiver allocate excessive space and possibly crash.
|
||||
KJ_REQUIRE(totalWords <= options.traversalLimitInWords,
|
||||
"Message is too large. To increase the limit on the receiving end, see "
|
||||
"capnp::ReaderOptions.") {
|
||||
segmentCount = 1;
|
||||
segment0Size = kj::min(segment0Size, options.traversalLimitInWords);
|
||||
totalWords = segment0Size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (scratchSpace.size() < totalWords) {
|
||||
// TODO(perf): Consider allocating each segment as a separate chunk to reduce memory
|
||||
// fragmentation.
|
||||
ownedSpace = kj::heapArray<word>(totalWords);
|
||||
scratchSpace = ownedSpace;
|
||||
}
|
||||
|
||||
segment0 = scratchSpace.slice(0, segment0Size);
|
||||
|
||||
if (segmentCount > 1) {
|
||||
moreSegments = kj::heapArray<kj::ArrayPtr<const word>>(segmentCount - 1);
|
||||
size_t offset = segment0Size;
|
||||
|
||||
for (uint i = 0; i < segmentCount - 1; i++) {
|
||||
uint segmentSize = moreSizes[i].get();
|
||||
moreSegments[i] = scratchSpace.slice(offset, offset + segmentSize);
|
||||
offset += segmentSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (segmentCount == 1) {
|
||||
inputStream.read(scratchSpace.begin(), totalWords * sizeof(word));
|
||||
} else if (segmentCount > 1) {
|
||||
readPos = scratchSpace.asBytes().begin();
|
||||
readPos += inputStream.read(readPos, segment0Size * sizeof(word), totalWords * sizeof(word));
|
||||
}
|
||||
}
|
||||
|
||||
InputStreamMessageReader::~InputStreamMessageReader() noexcept(false) {
|
||||
if (readPos != nullptr) {
|
||||
unwindDetector.catchExceptionsIfUnwinding([&]() {
|
||||
// Note that lazy reads only happen when we have multiple segments, so moreSegments.back() is
|
||||
// valid.
|
||||
const byte* allEnd = reinterpret_cast<const byte*>(moreSegments.back().end());
|
||||
inputStream.skip(allEnd - readPos);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const word> InputStreamMessageReader::getSegment(uint id) {
|
||||
if (id > moreSegments.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
kj::ArrayPtr<const word> segment = id == 0 ? segment0 : moreSegments[id - 1];
|
||||
|
||||
if (readPos != nullptr) {
|
||||
// May need to lazily read more data.
|
||||
const byte* segmentEnd = reinterpret_cast<const byte*>(segment.end());
|
||||
if (readPos < segmentEnd) {
|
||||
// Note that lazy reads only happen when we have multiple segments, so moreSegments.back() is
|
||||
// valid.
|
||||
const byte* allEnd = reinterpret_cast<const byte*>(moreSegments.back().end());
|
||||
readPos += inputStream.read(readPos, segmentEnd - readPos, allEnd - readPos);
|
||||
}
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
void readMessageCopy(kj::InputStream& input, MessageBuilder& target,
|
||||
ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
|
||||
InputStreamMessageReader message(input, options, scratchSpace);
|
||||
target.setRoot(message.getRoot<AnyPointer>());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
KJ_REQUIRE(segments.size() > 0, "Tried to serialize uninitialized message.");
|
||||
|
||||
KJ_STACK_ARRAY(_::WireValue<uint32_t>, table, (segments.size() + 2) & ~size_t(1), 16, 64);
|
||||
|
||||
// We write the segment count - 1 because this makes the first word zero for single-segment
|
||||
// messages, improving compression. We don't bother doing this with segment sizes because
|
||||
// one-word segments are rare anyway.
|
||||
table[0].set(segments.size() - 1);
|
||||
for (uint i = 0; i < segments.size(); i++) {
|
||||
table[i + 1].set(segments[i].size());
|
||||
}
|
||||
if (segments.size() % 2 == 0) {
|
||||
// Set padding byte.
|
||||
table[segments.size() + 1].set(0);
|
||||
}
|
||||
|
||||
KJ_STACK_ARRAY(kj::ArrayPtr<const byte>, pieces, segments.size() + 1, 4, 32);
|
||||
pieces[0] = table.asBytes();
|
||||
|
||||
for (uint i = 0; i < segments.size(); i++) {
|
||||
pieces[i + 1] = segments[i].asBytes();
|
||||
}
|
||||
|
||||
output.write(pieces);
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
StreamFdMessageReader::~StreamFdMessageReader() noexcept(false) {}
|
||||
|
||||
void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments) {
|
||||
#ifdef _WIN32
|
||||
auto oldMode = _setmode(fd, _O_BINARY);
|
||||
if (oldMode != _O_BINARY) {
|
||||
_setmode(fd, oldMode);
|
||||
KJ_FAIL_REQUIRE("Tried to write a message to a file descriptor that is in text mode. Set the "
|
||||
"file descriptor to binary mode by calling the _setmode Windows CRT function, or passing "
|
||||
"_O_BINARY to _open().");
|
||||
}
|
||||
#endif
|
||||
kj::FdOutputStream stream(fd);
|
||||
writeMessage(stream, segments);
|
||||
}
|
||||
|
||||
void readMessageCopyFromFd(int fd, MessageBuilder& target,
|
||||
ReaderOptions options, kj::ArrayPtr<word> scratchSpace) {
|
||||
kj::FdInputStream stream(fd);
|
||||
readMessageCopy(stream, target, options, scratchSpace);
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
// 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.
|
||||
|
||||
// This file implements a simple serialization format for Cap'n Proto messages. The format
|
||||
// is as follows:
|
||||
//
|
||||
// * 32-bit little-endian segment count (4 bytes).
|
||||
// * 32-bit little-endian size of each segment (4*(segment count) bytes).
|
||||
// * Padding so that subsequent data is 64-bit-aligned (0 or 4 bytes). (I.e., if there are an even
|
||||
// number of segments, there are 4 bytes of zeros here, otherwise there is no padding.)
|
||||
// * Data from each segment, in order (8*sum(segment sizes) bytes)
|
||||
//
|
||||
// This format has some important properties:
|
||||
// - It is self-delimiting, so multiple messages may be written to a stream without any external
|
||||
// delimiter.
|
||||
// - The total size and position of each segment can be determined by reading only the first part
|
||||
// of the message, allowing lazy and random-access reading of the segment data.
|
||||
// - A message is always at least 8 bytes.
|
||||
// - A single-segment message can be read entirely in two system calls with no buffering.
|
||||
// - A multi-segment message can be read entirely in three system calls with no buffering.
|
||||
// - The format is appropriate for mmap()ing since all data is aligned.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
#include <kj/io.h>
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
|
||||
class FlatArrayMessageReader: public MessageReader {
|
||||
// Parses a message from a flat array. Note that it makes sense to use this together with mmap()
|
||||
// for extremely fast parsing.
|
||||
|
||||
public:
|
||||
FlatArrayMessageReader(kj::ArrayPtr<const word> array, ReaderOptions options = ReaderOptions());
|
||||
// The array must remain valid until the MessageReader is destroyed.
|
||||
|
||||
kj::ArrayPtr<const word> getSegment(uint id) override;
|
||||
|
||||
const word* getEnd() const { return end; }
|
||||
// Get a pointer just past the end of the message as determined by reading the message header.
|
||||
// This could actually be before the end of the input array. This pointer is useful e.g. if
|
||||
// you know that the input array has extra stuff appended after the message and you want to
|
||||
// get at it.
|
||||
|
||||
private:
|
||||
// Optimize for single-segment case.
|
||||
kj::ArrayPtr<const word> segment0;
|
||||
kj::Array<kj::ArrayPtr<const word>> moreSegments;
|
||||
const word* end;
|
||||
};
|
||||
|
||||
kj::ArrayPtr<const word> initMessageBuilderFromFlatArrayCopy(
|
||||
kj::ArrayPtr<const word> array, MessageBuilder& target,
|
||||
ReaderOptions options = ReaderOptions());
|
||||
// Convenience function which reads a message using `FlatArrayMessageReader` then copies the
|
||||
// content into the target `MessageBuilder`, verifying that the message structure is valid
|
||||
// (although not necessarily that it matches the desired schema).
|
||||
//
|
||||
// Returns an ArrayPtr containing any words left over in the array after consuming the whole
|
||||
// message. This is useful when reading multiple messages that have been concatenated. See also
|
||||
// FlatArrayMessageReader::getEnd().
|
||||
//
|
||||
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
|
||||
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
|
||||
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
|
||||
|
||||
kj::Array<word> messageToFlatArray(MessageBuilder& builder);
|
||||
// Constructs a flat array containing the entire content of the given message.
|
||||
//
|
||||
// To output the message as bytes, use `.asBytes()` on the returned word array. Keep in mind that
|
||||
// `asBytes()` returns an ArrayPtr, so you have to save the Array as well to prevent it from being
|
||||
// deleted. For example:
|
||||
//
|
||||
// kj::Array<capnp::word> words = messageToFlatArray(myMessage);
|
||||
// kj::ArrayPtr<kj::byte> bytes = words.asBytes();
|
||||
// write(fd, bytes.begin(), bytes.size());
|
||||
|
||||
kj::Array<word> messageToFlatArray(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Version of messageToFlatArray that takes a raw segment array.
|
||||
|
||||
size_t computeSerializedSizeInWords(MessageBuilder& builder);
|
||||
// Returns the size, in words, that will be needed to serialize the message, including the header.
|
||||
|
||||
size_t computeSerializedSizeInWords(kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Version of computeSerializedSizeInWords that takes a raw segment array.
|
||||
|
||||
size_t expectedSizeInWordsFromPrefix(kj::ArrayPtr<const word> messagePrefix);
|
||||
// Given a prefix of a serialized message, try to determine the expected total size of the message,
|
||||
// in words. The returned size is based on the information known so far; it may be an underestimate
|
||||
// if the prefix doesn't contain the full segment table.
|
||||
//
|
||||
// If the returned value is greater than `messagePrefix.size()`, then the message is not yet
|
||||
// complete and the app cannot parse it yet. If the returned value is less than or equal to
|
||||
// `messagePrefix.size()`, then the returned value is the exact total size of the message; any
|
||||
// remaining bytes are part of the next message.
|
||||
//
|
||||
// This function is useful when reading messages from a stream in an asynchronous way, but when
|
||||
// using the full KJ async infrastructure would be too difficult. Each time bytes are received,
|
||||
// use this function to determine if an entire message is ready to be parsed.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class InputStreamMessageReader: public MessageReader {
|
||||
// A MessageReader that reads from an abstract kj::InputStream. See also StreamFdMessageReader
|
||||
// for a subclass specific to file descriptors.
|
||||
|
||||
public:
|
||||
InputStreamMessageReader(kj::InputStream& inputStream,
|
||||
ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
~InputStreamMessageReader() noexcept(false);
|
||||
|
||||
// implements MessageReader ----------------------------------------
|
||||
kj::ArrayPtr<const word> getSegment(uint id) override;
|
||||
|
||||
private:
|
||||
kj::InputStream& inputStream;
|
||||
byte* readPos;
|
||||
|
||||
// Optimize for single-segment case.
|
||||
kj::ArrayPtr<const word> segment0;
|
||||
kj::Array<kj::ArrayPtr<const word>> moreSegments;
|
||||
|
||||
kj::Array<word> ownedSpace;
|
||||
// Only if scratchSpace wasn't big enough.
|
||||
|
||||
kj::UnwindDetector unwindDetector;
|
||||
};
|
||||
|
||||
void readMessageCopy(kj::InputStream& input, MessageBuilder& target,
|
||||
ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Convenience function which reads a message using `InputStreamMessageReader` then copies the
|
||||
// content into the target `MessageBuilder`, verifying that the message structure is valid
|
||||
// (although not necessarily that it matches the desired schema).
|
||||
//
|
||||
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
|
||||
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
|
||||
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
|
||||
|
||||
void writeMessage(kj::OutputStream& output, MessageBuilder& builder);
|
||||
// Write the message to the given output stream.
|
||||
|
||||
void writeMessage(kj::OutputStream& output, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Write the segment array to the given output stream.
|
||||
|
||||
// =======================================================================================
|
||||
// Specializations for reading from / writing to file descriptors.
|
||||
|
||||
class StreamFdMessageReader: private kj::FdInputStream, public InputStreamMessageReader {
|
||||
// A MessageReader that reads from a stream-based file descriptor.
|
||||
|
||||
public:
|
||||
StreamFdMessageReader(int fd, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr)
|
||||
: FdInputStream(fd), InputStreamMessageReader(*this, options, scratchSpace) {}
|
||||
// Read message from a file descriptor, without taking ownership of the descriptor.
|
||||
|
||||
StreamFdMessageReader(kj::AutoCloseFd fd, ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr)
|
||||
: FdInputStream(kj::mv(fd)), InputStreamMessageReader(*this, options, scratchSpace) {}
|
||||
// Read a message from a file descriptor, taking ownership of the descriptor.
|
||||
|
||||
~StreamFdMessageReader() noexcept(false);
|
||||
};
|
||||
|
||||
void readMessageCopyFromFd(int fd, MessageBuilder& target,
|
||||
ReaderOptions options = ReaderOptions(),
|
||||
kj::ArrayPtr<word> scratchSpace = nullptr);
|
||||
// Convenience function which reads a message using `StreamFdMessageReader` then copies the
|
||||
// content into the target `MessageBuilder`, verifying that the message structure is valid
|
||||
// (although not necessarily that it matches the desired schema).
|
||||
//
|
||||
// (Note that it's also possible to initialize a `MessageBuilder` directly without a copy using one
|
||||
// of `MessageBuilder`'s constructors. However, this approach skips the validation step and is not
|
||||
// safe to use on untrusted input. Therefore, we do not provide a convenience method for it.)
|
||||
|
||||
void writeMessageToFd(int fd, MessageBuilder& builder);
|
||||
// Write the message to the given file descriptor.
|
||||
//
|
||||
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
|
||||
// you catch this exception at the call site. If throwing an exception is not acceptable, you
|
||||
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
|
||||
|
||||
void writeMessageToFd(int fd, kj::ArrayPtr<const kj::ArrayPtr<const word>> segments);
|
||||
// Write the segment array to the given file descriptor.
|
||||
//
|
||||
// This function throws an exception on any I/O error. If your code is not exception-safe, be sure
|
||||
// you catch this exception at the call site. If throwing an exception is not acceptable, you
|
||||
// can implement your own OutputStream with arbitrary error handling and then use writeMessage().
|
||||
|
||||
// =======================================================================================
|
||||
// inline stuff
|
||||
|
||||
inline kj::Array<word> messageToFlatArray(MessageBuilder& builder) {
|
||||
return messageToFlatArray(builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline size_t computeSerializedSizeInWords(MessageBuilder& builder) {
|
||||
return computeSerializedSizeInWords(builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline void writeMessage(kj::OutputStream& output, MessageBuilder& builder) {
|
||||
writeMessage(output, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
inline void writeMessageToFd(int fd, MessageBuilder& builder) {
|
||||
writeMessageToFd(fd, builder.getSegmentsForOutput());
|
||||
}
|
||||
|
||||
} // namespace capnp
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: stream.capnp
|
||||
|
||||
#include "stream.capnp.h"
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
static const ::capnp::_::AlignedData<17> b_995f9a3377c0b16e = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
110, 177, 192, 119, 51, 154, 95, 153,
|
||||
19, 0, 0, 0, 1, 0, 0, 0,
|
||||
248, 243, 147, 19, 169, 102, 195, 134,
|
||||
0, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 2, 1, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 97, 112, 110, 112, 47, 115, 116,
|
||||
114, 101, 97, 109, 46, 99, 97, 112,
|
||||
110, 112, 58, 83, 116, 114, 101, 97,
|
||||
109, 82, 101, 115, 117, 108, 116, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_995f9a3377c0b16e = b_995f9a3377c0b16e.words;
|
||||
#if !CAPNP_LITE
|
||||
const ::capnp::_::RawSchema s_995f9a3377c0b16e = {
|
||||
0x995f9a3377c0b16e, b_995f9a3377c0b16e.words, 17, nullptr, nullptr,
|
||||
0, 0, nullptr, nullptr, nullptr, { &s_995f9a3377c0b16e, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace capnp {
|
||||
|
||||
// StreamResult
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t StreamResult::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t StreamResult::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind StreamResult::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* StreamResult::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||
// source: stream.capnp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <capnp/generated-header-support.h>
|
||||
#include <kj/windows-sanity.h>
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
|
||||
CAPNP_BEGIN_HEADER
|
||||
|
||||
namespace capnp {
|
||||
namespace schemas {
|
||||
|
||||
CAPNP_DECLARE_SCHEMA(995f9a3377c0b16e);
|
||||
|
||||
} // namespace schemas
|
||||
} // namespace capnp
|
||||
|
||||
namespace capnp {
|
||||
|
||||
struct StreamResult {
|
||||
StreamResult() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(995f9a3377c0b16e, 0, 0)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
class StreamResult::Reader {
|
||||
public:
|
||||
typedef StreamResult Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class StreamResult::Builder {
|
||||
public:
|
||||
typedef StreamResult Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class StreamResult::Pipeline {
|
||||
public:
|
||||
typedef StreamResult Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
} // namespace
|
||||
|
||||
CAPNP_END_HEADER
|
||||
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
tmp=.tmp
|
||||
|
||||
rm -rf $tmp
|
||||
mkdir $tmp
|
||||
cd $tmp
|
||||
git clone https://github.com/capnproto/capnproto.git -b v1.0.1 .
|
||||
cd ..
|
||||
|
||||
rm -rf kj capnp
|
||||
|
||||
# NOTE: putting the original sources in a folder below the .pro file
|
||||
# avoids issues with the include path that Qt imposes and which creates
|
||||
# a name clash with standard headers like "string.h"
|
||||
|
||||
mkdir kj
|
||||
mkdir kj/kj
|
||||
mkdir kj/kj/parse
|
||||
mkdir kj/kj/std
|
||||
mkdir capnp
|
||||
mkdir capnp/capnp
|
||||
mkdir capnp/capnp/compat
|
||||
|
||||
cp $tmp/{LICENSE,CONTRIBUTORS} kj
|
||||
cp $tmp/{LICENSE,CONTRIBUTORS} capnp
|
||||
|
||||
cp kj.pro kj
|
||||
cp capnp.pro capnp
|
||||
|
||||
capnp_sources_lite=(
|
||||
c++.capnp.c++
|
||||
blob.c++
|
||||
arena.c++
|
||||
layout.c++
|
||||
list.c++
|
||||
any.c++
|
||||
message.c++
|
||||
schema.capnp.c++
|
||||
stream.capnp.c++
|
||||
serialize.c++
|
||||
serialize-packed.c++
|
||||
)
|
||||
|
||||
capnp_headers=(
|
||||
arena.h
|
||||
c++.capnp.h
|
||||
common.h
|
||||
blob.h
|
||||
endian.h
|
||||
layout.h
|
||||
orphan.h
|
||||
list.h
|
||||
any.h
|
||||
message.h
|
||||
capability.h
|
||||
membrane.h
|
||||
dynamic.h
|
||||
schema.h
|
||||
schema.capnp.h
|
||||
stream.capnp.h
|
||||
schema-lite.h
|
||||
schema-loader.h
|
||||
schema-parser.h
|
||||
pretty-print.h
|
||||
serialize.h
|
||||
serialize-async.h
|
||||
serialize-packed.h
|
||||
serialize-text.h
|
||||
pointer-helpers.h
|
||||
generated-header-support.h
|
||||
raw-schema.h
|
||||
)
|
||||
|
||||
capnp_compat_headers=(
|
||||
std-iterator.h
|
||||
)
|
||||
|
||||
kj_sources_lite=(
|
||||
array.c++
|
||||
cidr.c++
|
||||
list.c++
|
||||
common.c++
|
||||
debug.c++
|
||||
exception.c++
|
||||
io.c++
|
||||
memory.c++
|
||||
mutex.c++
|
||||
string.c++
|
||||
source-location.c++
|
||||
hash.c++
|
||||
table.c++
|
||||
thread.c++
|
||||
main.c++
|
||||
arena.c++
|
||||
units.c++
|
||||
encoding.c++
|
||||
)
|
||||
|
||||
kj_headers=(
|
||||
cidr.h
|
||||
common.h
|
||||
units.h
|
||||
memory.h
|
||||
refcount.h
|
||||
array.h
|
||||
list.h
|
||||
vector.h
|
||||
string.h
|
||||
string-tree.h
|
||||
source-location.h
|
||||
hash.h
|
||||
table.h
|
||||
map.h
|
||||
encoding.h
|
||||
exception.h
|
||||
debug.h
|
||||
arena.h
|
||||
io.h
|
||||
tuple.h
|
||||
one-of.h
|
||||
function.h
|
||||
mutex.h
|
||||
thread.h
|
||||
threadlocal.h
|
||||
filesystem.h
|
||||
time.h
|
||||
main.h
|
||||
win32-api-version.h
|
||||
windows-sanity.h
|
||||
miniposix.h
|
||||
)
|
||||
|
||||
kj_parse_headers=(
|
||||
common.h
|
||||
char.h
|
||||
)
|
||||
kj_std_headers=(
|
||||
iostream.h
|
||||
)
|
||||
|
||||
for f in ${capnp_sources_lite[@]}; do
|
||||
cp $tmp/c++/src/capnp/$f capnp/capnp
|
||||
done
|
||||
for f in ${capnp_headers[@]}; do
|
||||
cp $tmp/c++/src/capnp/$f capnp/capnp
|
||||
done
|
||||
for f in ${capnp_compat_headers[@]}; do
|
||||
cp $tmp/c++/src/capnp/compat/$f capnp/capnp/compat
|
||||
done
|
||||
|
||||
pri=capnp/capnp.pri
|
||||
echo "" >$pri
|
||||
echo "CAPNP_SOURCES=\\" >>$pri
|
||||
for f in ${capnp_sources_lite[@]}; do
|
||||
echo " capnp/$f \\" >>$pri
|
||||
done
|
||||
echo "" >>$pri
|
||||
echo "CAPNP_HEADERS=\\" >>$pri
|
||||
for f in ${capnp_headers[@]}; do
|
||||
echo " capnp/$f \\" >>$pri
|
||||
done
|
||||
for f in ${capnp_compat_headers[@]}; do
|
||||
echo " capnp/compat/$f \\" >>$pri
|
||||
done
|
||||
|
||||
for f in ${kj_sources_lite[@]}; do
|
||||
cp $tmp/c++/src/kj/$f kj/kj
|
||||
done
|
||||
for f in ${kj_headers[@]}; do
|
||||
cp $tmp/c++/src/kj/$f kj/kj
|
||||
done
|
||||
for f in ${kj_parse_headers[@]}; do
|
||||
cp $tmp/c++/src/kj/parse/$f kj/kj/parse
|
||||
done
|
||||
for f in ${kj_std_headers[@]}; do
|
||||
cp $tmp/c++/src/kj/std/$f kj/kj/std
|
||||
done
|
||||
|
||||
pri=kj/kj.pri
|
||||
echo "" >$pri
|
||||
echo "KJ_SOURCES=\\" >>$pri
|
||||
for f in ${kj_sources_lite[@]}; do
|
||||
echo " kj/$f \\" >>$pri
|
||||
done
|
||||
echo "" >>$pri
|
||||
echo "KJ_HEADERS=\\" >>$pri
|
||||
for f in ${kj_headers[@]}; do
|
||||
echo " kj/$f \\" >>$pri
|
||||
done
|
||||
for f in ${kj_parse_headers[@]}; do
|
||||
echo " kj/parse/$f \\" >>$pri
|
||||
done
|
||||
for f in ${kj_std_headers[@]}; do
|
||||
echo " kj/std/$f \\" >>$pri
|
||||
done
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
TEMPLATE = lib
|
||||
DESTDIR = $$OUT_PWD/../../../../..
|
||||
|
||||
include($$PWD/kj.pri)
|
||||
|
||||
TARGET = xkj
|
||||
SOURCES = $$KJ_SOURCES
|
||||
HEADERS = $$KJ_HEADERS
|
||||
|
||||
DEFINES = CAPNP_LITE
|
||||
INCLUDEPATH =
|
||||
LIBS =
|
||||
QT =
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue