-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTFactory.hpp
132 lines (109 loc) · 5.57 KB
/
TFactory.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
///
/// Langulus::Flow
/// Copyright (c) 2017 Dimo Markov <[email protected]>
/// Part of the Langulus framework, see https://langulus.com
///
/// SPDX-License-Identifier: GPL-3.0-or-later
///
#pragma once
#include "Common.hpp"
#include <Anyness/Neat.hpp>
#include <Anyness/THive.hpp>
namespace Langulus::Flow
{
/// Usage styles for TFactory
enum class FactoryUsage {
Default, // Default factories aggregate duplicated items
Unique // Unique factories never duplicate items (a set)
};
/// Concept for determining if a type is producible from a factory
/// The type must have a producer defined, not be abstract, be dense, and
/// be referencable
template<class...T>
concept FactoryProducible = ((CT::Producible<T>
and not CT::Abstract<T> and CT::Dense<T> and CT::Referencable<T>)
and ...);
///
/// Factory container
///
/// Basically a templated container used to contain, produce, but most
/// importantly reuse memory. The factory can contain only reference-
/// counted types, because elements are forbidden to move, and are reused
/// in-place. Additionally, the factory also internally utilizes a hashmap
/// to quickly find relevant elements. Items are laid out serially, so
/// that iteration is as fast and cache-friendly as possible.
///
/// By specifying a FactoryUsage::Unique usage, you're essentially
/// making a set of the produced resources, never duplicating elements
/// with the same descriptor twice.
///
template<class T, FactoryUsage USAGE = FactoryUsage::Default>
class TFactory : public Anyness::THive<T> {
public:
LANGULUS(TYPED) T;
using Base = Anyness::THive<T>;
static constexpr bool IsUnique = USAGE == FactoryUsage::Unique;
protected:
using typename Base::Cell;
// A hash map for fast retrieval of elements
TUnorderedMap<Hash, TMany<Cell*>> mHashmap;
NOD() auto Produce(auto*, const Many&) -> T*;
void CreateInner(auto*, Verb&, int, const Many& = {});
void Destroy(Cell*);
NOD() auto FindInner(const Many&) const -> Cell*;
public:
/// Factories can't be default-, move- or copy-constructed
/// We must guarantee that mFactoryOwner is always valid, and move is
/// allowed only via assignment, on a previously initialized factory
/// This is needed, because elements must be remapped to a new valid
/// owner upon move
TFactory() = default;
TFactory(const TFactory&) = delete;
TFactory(TFactory&&) = delete;
~TFactory();
auto operator = (TFactory&&) noexcept -> TFactory&;
void Reset();
void Create(auto*, Verb&);
auto CreateOne(auto*, const Many&) -> T*;
void Select(Verb&);
auto Find(const Many&) const -> const T*;
void Teardown();
IF_SAFE(void Dump() const);
#if LANGULUS(TESTING)
auto& GetHashmap() const { return mHashmap; }
#endif
};
template<class T>
using TFactoryUnique = TFactory<T, FactoryUsage::Unique>;
///
/// An element, that is factory produced (used as CRTP)
///
/// Saves the descriptor by which the item was made with, in order to
/// compare creation requests
/// @attention mDescriptor can contain anything (including Thing
/// references) and is known to cause circular dependencies. That's
/// why ProducedFrom::Teardown has to be called as a first-stage
/// destruction, usually in a custom Reference(int) routine.
///
template<class T>
class ProducedFrom {
LANGULUS(PRODUCER) T;
protected:
template<class, FactoryUsage>
friend class TFactory;
// The descriptor used for hashing and element identification
Many mDescriptor;
// The producer of the element
Ref<T> mProducer;
public:
ProducedFrom(const ProducedFrom&) = delete;
ProducedFrom(ProducedFrom&&);
ProducedFrom(T* = nullptr, const Many& = {});
template<template<class> class S>
ProducedFrom(S<ProducedFrom>&&) requires CT::Intent<S<ProducedFrom>>;
auto GetDescriptor() const noexcept -> const Many&;
Hash GetHash() const noexcept;
auto GetProducer() const noexcept -> const Ref<T>&;
void TeardownInner();
};
} // namespace Langulus::Flow