| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #pragma once
- template <typename Base>
- class RuntimeComposer;
- class RuntimeComposerBase;
- typedef void(*RuntimeComponentConstruct)(void *location, RuntimeComposerBase *composer);
- typedef void(*RuntimeComponentDestruct)(void *location);
- typedef void(*RuntimeComponentMove)(void *location, void *waslocation);
- struct RuntimeComponentWrapStruct {
- // Don't init any fields, because it is only created in
- // global scope, so it will be filled by zeros from the start.
- RuntimeComponentWrapStruct() = default;
- RuntimeComponentWrapStruct(std::size_t size, std::size_t align, RuntimeComponentConstruct construct, RuntimeComponentDestruct destruct, RuntimeComponentMove move)
- : Size(size)
- , Align(align)
- , Construct(construct)
- , Destruct(destruct)
- , Move(move) {
- }
- std::size_t Size;
- std::size_t Align;
- RuntimeComponentConstruct Construct;
- RuntimeComponentDestruct Destruct;
- RuntimeComponentMove Move;
- };
- template <int Value, int Denominator>
- struct CeilDivideMinimumOne {
- static constexpr int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0));
- };
- extern RuntimeComponentWrapStruct RuntimeComponentWraps[64];
- extern QAtomicInt RuntimeComponentIndexLast;
- template <typename Type, typename Base>
- struct RuntimeComponent {
- using RuntimeComponentBase = Base;
- RuntimeComponent() {
- // While there is no std::aligned_alloc().
- static_assert(alignof(Type) <= alignof(std::max_align_t), "Components should align to std::max_align_t!");
- }
- RuntimeComponent(const RuntimeComponent &other) = delete;
- RuntimeComponent &operator=(const RuntimeComponent &other) = delete;
- RuntimeComponent(RuntimeComponent &&other) = delete;
- RuntimeComponent &operator=(RuntimeComponent &&other) = default;
- static int Index() {
- static QAtomicInt MyIndex(0);
- if (auto index = MyIndex.loadAcquire()) {
- return index - 1;
- }
- while (true) {
- auto last = RuntimeComponentIndexLast.loadAcquire();
- if (RuntimeComponentIndexLast.testAndSetOrdered(last, last + 1)) {
- Assert(last < 64);
- if (MyIndex.testAndSetOrdered(0, last + 1)) {
- RuntimeComponentWraps[last] = RuntimeComponentWrapStruct(
- sizeof(Type),
- alignof(Type),
- Type::RuntimeComponentConstruct,
- Type::RuntimeComponentDestruct,
- Type::RuntimeComponentMove);
- }
- break;
- }
- }
- return MyIndex.loadAcquire() - 1;
- }
- static uint64 Bit() {
- return (1ULL << Index());
- }
- protected:
- static void RuntimeComponentConstruct(void *location, RuntimeComposerBase *composer) {
- new (location) Type();
- }
- static void RuntimeComponentDestruct(void *location) {
- ((Type*)location)->~Type();
- }
- static void RuntimeComponentMove(void *location, void *waslocation) {
- *(Type*)location = std::move(*(Type*)waslocation);
- }
- };
- class RuntimeComposerMetadata {
- public:
- RuntimeComposerMetadata(uint64 mask) : _mask(mask) {
- for (int i = 0; i != 64; ++i) {
- auto componentBit = (1ULL << i);
- if (_mask & componentBit) {
- auto componentSize = RuntimeComponentWraps[i].Size;
- if (componentSize) {
- auto componentAlign = RuntimeComponentWraps[i].Align;
- if (auto badAlign = (size % componentAlign)) {
- size += (componentAlign - badAlign);
- }
- offsets[i] = size;
- size += componentSize;
- accumulate_max(align, componentAlign);
- }
- } else if (_mask < componentBit) {
- last = i;
- break;
- }
- }
- }
- // Meta pointer in the start.
- std::size_t size = sizeof(const RuntimeComposerMetadata*);
- std::size_t align = alignof(const RuntimeComposerMetadata*);
- std::size_t offsets[64] = { 0 };
- int last = 64;
- bool equals(uint64 mask) const {
- return _mask == mask;
- }
- uint64 maskadd(uint64 mask) const {
- return _mask | mask;
- }
- uint64 maskremove(uint64 mask) const {
- return _mask & (~mask);
- }
- private:
- uint64 _mask;
- };
- const RuntimeComposerMetadata *GetRuntimeComposerMetadata(uint64 mask);
- class RuntimeComposerBase {
- public:
- RuntimeComposerBase(uint64 mask = 0) : _data(zerodata()) {
- if (mask) {
- auto meta = GetRuntimeComposerMetadata(mask);
- auto data = operator new(meta->size);
- Assert(data != nullptr);
- _data = data;
- _meta() = meta;
- for (int i = 0; i < meta->last; ++i) {
- auto offset = meta->offsets[i];
- if (offset >= sizeof(_meta())) {
- try {
- auto constructAt = _dataptrunsafe(offset);
- auto space = RuntimeComponentWraps[i].Size;
- auto alignedAt = constructAt;
- std::align(RuntimeComponentWraps[i].Align, space, alignedAt, space);
- Assert(alignedAt == constructAt);
- RuntimeComponentWraps[i].Construct(constructAt, this);
- } catch (...) {
- while (i > 0) {
- --i;
- offset = meta->offsets[--i];
- if (offset >= sizeof(_meta())) {
- RuntimeComponentWraps[i].Destruct(_dataptrunsafe(offset));
- }
- }
- throw;
- }
- }
- }
- }
- }
- RuntimeComposerBase(const RuntimeComposerBase &other) = delete;
- RuntimeComposerBase &operator=(const RuntimeComposerBase &other) = delete;
- ~RuntimeComposerBase() {
- if (_data != zerodata()) {
- auto meta = _meta();
- for (int i = 0; i < meta->last; ++i) {
- auto offset = meta->offsets[i];
- if (offset >= sizeof(_meta())) {
- RuntimeComponentWraps[i].Destruct(_dataptrunsafe(offset));
- }
- }
- operator delete(_data);
- }
- }
- protected:
- bool UpdateComponents(uint64 mask = 0) {
- if (_meta()->equals(mask)) {
- return false;
- }
- RuntimeComposerBase result(mask);
- result.swap(*this);
- if (_data != zerodata() && result._data != zerodata()) {
- const auto meta = _meta();
- const auto wasmeta = result._meta();
- for (auto i = 0; i != meta->last; ++i) {
- const auto offset = meta->offsets[i];
- const auto wasoffset = wasmeta->offsets[i];
- if (offset >= sizeof(_meta())
- && wasoffset >= sizeof(_meta())) {
- RuntimeComponentWraps[i].Move(
- _dataptrunsafe(offset),
- result._dataptrunsafe(wasoffset));
- }
- }
- }
- return true;
- }
- bool AddComponents(uint64 mask = 0) {
- return UpdateComponents(_meta()->maskadd(mask));
- }
- bool RemoveComponents(uint64 mask = 0) {
- return UpdateComponents(_meta()->maskremove(mask));
- }
- private:
- template <typename Base>
- friend class RuntimeComposer;
- static const RuntimeComposerMetadata *ZeroRuntimeComposerMetadata;
- static void *zerodata() {
- return &ZeroRuntimeComposerMetadata;
- }
- void *_dataptrunsafe(int skip) const {
- return (char*)_data + skip;
- }
- void *_dataptr(int skip) const {
- return (skip >= sizeof(_meta())) ? _dataptrunsafe(skip) : nullptr;
- }
- const RuntimeComposerMetadata *&_meta() const {
- return *static_cast<const RuntimeComposerMetadata**>(_data);
- }
- void *_data = nullptr;
- void swap(RuntimeComposerBase &other) {
- std::swap(_data, other._data);
- }
- };
- template <typename Base>
- class RuntimeComposer : public RuntimeComposerBase {
- public:
- using RuntimeComposerBase::RuntimeComposerBase;
- template <
- typename Type,
- typename = std::enable_if_t<std::is_same_v<
- typename Type::RuntimeComponentBase,
- Base>>>
- bool Has() const {
- return (_meta()->offsets[Type::Index()] >= sizeof(_meta()));
- }
- template <
- typename Type,
- typename = std::enable_if_t<std::is_same_v<
- typename Type::RuntimeComponentBase,
- Base>>>
- Type *Get() {
- return static_cast<Type*>(_dataptr(_meta()->offsets[Type::Index()]));
- }
- template <
- typename Type,
- typename = std::enable_if_t<std::is_same_v<
- typename Type::RuntimeComponentBase,
- Base>>>
- const Type *Get() const {
- return static_cast<const Type*>(_dataptr(_meta()->offsets[Type::Index()]));
- }
- };
|