Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
FlyWeight.hpp
1/*
2Copyright (C) 2018,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#ifndef AEONGAMES_FLYWEIGHT_STORE_H
17#define AEONGAMES_FLYWEIGHT_STORE_H
18
19#include <unordered_map>
20#include <mutex>
21
22namespace AeonGames
23{
28 template<class Key, class Value>
29 class FlyWeight
30 {
31 friend Value;
32 FlyWeight() = default;
33 FlyWeight ( const FlyWeight& aFlyWeight ) : mKey{}
34 {
35 /* A Copy cannot have the same key as the original so do nothing*/
36 }
37 FlyWeight ( FlyWeight&& aFlyWeight ) : mKey ( std::move ( aFlyWeight.mKey ) )
38 {
39 static std::mutex m;
40 std::lock_guard<std::mutex> hold ( m );
41 // A Moved object's key is moved.
42 aFlyWeight.mKey = Key{};
43 mStore[mKey] = this;
44 }
45 const FlyWeight& operator= ( const FlyWeight& aFlyWeight )
46 {
47 /* A Copy cannot have the same key as the original*/
48 if ( &aFlyWeight != this )
49 {
50 mKey = Key{};
51 }
52 return *this;
53 }
54 const FlyWeight& operator= ( FlyWeight&& aFlyWeight )
55 {
56 if ( &aFlyWeight != this )
57 {
58 static std::mutex m;
59 std::lock_guard<std::mutex> hold ( m );
60 // A Moved object's key is moved.
61 aFlyWeight.mKey = Key{};
62 mKey = std::move ( aFlyWeight.mKey );
63 mStore[mKey] = this;
64 }
65 return *this;
66 }
67 FlyWeight ( const Key& aKey ) : mKey ( aKey )
68 {
69 Pack ( aKey );
70 }
71 virtual ~FlyWeight ()
72 {
73 Unpack();
74 }
75 Key mKey{};
76 static std::unordered_map<Key, FlyWeight<Key, Value>*> mStore;
77 public:
79 class Handle
80 {
81 const Key mKey{};
82 public:
87 Handle ( const Key& aKey ) : mKey{aKey}
88 {
89 if ( mKey == Key{} )
90 {
91 throw std::runtime_error ( "The null/empty key is reserved for unpacked objects." );
92 }
93 }
94
97 const Value* const Get() const
98 {
99 auto it = FlyWeight<Key, Value>::mStore.find ( mKey );
100 if ( it != FlyWeight<Key, Value>::mStore.end() )
101 {
102 return reinterpret_cast<Value*> ( it->second );
103 }
104 return nullptr;
105 }
106
109 const Handle GetHandle() const
110 {
111 return Handle ( mKey );
112 }
113
116 bool IsValid() const
117 {
118 return Get() != nullptr;
119 }
120
124 const Value* const operator->() const
125 {
126 auto result = Get();
127 if ( !result )
128 {
129 throw std::runtime_error ( "Invalid FlyWeight Object." );
130 }
131 return result;
132 }
133
137 const Value& operator*() const
138 {
139 auto result = Get();
140 if ( !result )
141 {
142 throw std::runtime_error ( "Invalid FlyWeight Object." );
143 }
144 return *result;
145 }
146
150 const Value* const operator&() const
151 {
152 auto result = Get();
153 if ( !result )
154 {
155 throw std::runtime_error ( "Invalid FlyWeight Object." );
156 }
157 return result;
158 }
159 };
160
165 const Handle Pack ( const Key& aKey )
166 {
167 static std::mutex m;
168 std::lock_guard<std::mutex> hold ( m );
169 if ( aKey == Key{} )
170 {
171 throw std::runtime_error ( "The null/empty key is reserved for unpacked objects." );
172 }
173 mKey = aKey;
174 Handle handle{mKey};
175 if ( handle.Get() )
176 {
177 throw std::runtime_error ( "An object with the same key has already been packed." );
178 }
179 mStore[mKey] = this;
180 return handle;
181 }
182
183 void Unpack()
184 {
185 static std::mutex m;
186 std::lock_guard<std::mutex> hold ( m );
187 mStore.erase ( mKey );
188 mKey = Key{};
189 }
190
194 const Handle GetHandle() const
195 {
196 if ( mKey == Key{} )
197 {
198 throw std::runtime_error ( "Object is not packed." );
199 }
200 return Handle{mKey};
201 }
202 };
203
204 template <class Key, class Value>
205 std::unordered_map<Key, FlyWeight<Key, Value>*> FlyWeight<Key, Value>::mStore{};
206}
207#endif
Lightweight handle providing read-only access to a packed FlyWeight object.
Definition FlyWeight.hpp:80
const Handle GetHandle() const
Get a copy of this Handle.
const Value *const operator&() const
Address-of operator for obtaining a pointer to the stored Value.
bool IsValid() const
Check whether the referenced FlyWeight object is currently packed.
const Value *const operator->() const
Arrow operator for accessing the stored Value.
const Value & operator*() const
Dereference operator for accessing the stored Value.
const Value *const Get() const
Retrieve a pointer to the stored Value.
Definition FlyWeight.hpp:97
Handle(const Key &aKey)
Construct a Handle for the given key.
Definition FlyWeight.hpp:87
const Handle Pack(const Key &aKey)
Register this object in the store with the given key.
void Unpack()
Remove this object from the store and reset its key.
const Handle GetHandle() const
Obtain a Handle to this packed object.
<- This is here just for the literals
Definition AABB.hpp:31