KiCad PCB EDA Suite
Loading...
Searching...
No Matches
property_holder.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef PROPERTY_HOLDER_H
21#define PROPERTY_HOLDER_H
22
23#include <any>
24#include <string>
25#include <unordered_map>
26#include <type_traits>
27#include <optional>
28#include <concepts>
29#include <cstdint>
30
31
67
68
72template<typename T>
73concept PropertyValueType = std::copy_constructible<T> && std::destructible<T>;
74
76{
77public:
79 static constexpr uint64_t MAGIC_VALUE = 0x50524F5048444C52ULL;
80
86 {
87 }
88
95 {
96 }
97
101 PROPERTY_HOLDER( PROPERTY_HOLDER&& other ) noexcept :
103 m_properties( std::move( other.m_properties ) )
104 {
105 }
106
111 {
112 if( this != &other )
114
115 return *this;
116 }
117
122 {
123 if( this != &other )
124 m_properties = std::move( other.m_properties );
125
126 return *this;
127 }
128
133 {
134 m_magic = 0xDEADBEEFDEADBEEFULL; // Clear magic to detect use-after-free
135 }
136
141 bool IsValid() const noexcept { return m_magic == MAGIC_VALUE; }
142
148 static PROPERTY_HOLDER* SafeCast( void* aPtr ) noexcept
149 {
150 if( !aPtr )
151 return nullptr;
152
153 try
154 {
155 PROPERTY_HOLDER* aCandidate = reinterpret_cast<PROPERTY_HOLDER*>( aPtr );
156 if( aCandidate->m_magic == MAGIC_VALUE )
157 {
158 return aCandidate;
159 }
160 }
161 catch( ... )
162 {
163 // Any exception means invalid memory
164 }
165 return nullptr;
166 }
167
173 static const PROPERTY_HOLDER* SafeCast( const void* aPtr ) noexcept
174 {
175 if( !aPtr )
176 return nullptr;
177
178 try
179 {
180 const PROPERTY_HOLDER* aCandidate = reinterpret_cast<const PROPERTY_HOLDER*>( aPtr );
181 if( aCandidate->m_magic == MAGIC_VALUE )
182 {
183 return aCandidate;
184 }
185 }
186 catch( ... )
187 {
188 // Any exception means invalid memory
189 }
190 return nullptr;
191 }
192
198 static bool SafeDelete( void* aPtr ) noexcept
199 {
200 PROPERTY_HOLDER* aHolder = SafeCast( aPtr );
201
202 if( aHolder )
203 {
204 delete aHolder;
205 return true;
206 }
207
208 return false;
209 }
210
211 static bool SafeDelete( PROPERTY_HOLDER* aHolder ) noexcept
212 {
213 if( aHolder )
214 {
215 delete aHolder;
216 return true;
217 }
218
219 return false;
220 }
221
229 template <typename T>
230 bool SetProperty( const std::string& aKey, T&& aValue )
231 {
232 if( !IsValid() )
233 return false;
234
235 m_properties[aKey] = std::forward<T>( aValue );
236 return true;
237 }
238
245 template <typename T>
246 std::optional<T> GetProperty( const std::string& aKey ) const
247 {
248 if( !IsValid() )
249 return std::nullopt;
250
251 auto it = m_properties.find( aKey );
252 if( it == m_properties.end() )
253 {
254 return std::nullopt;
255 }
256
257 try
258 {
259 return std::any_cast<T>( it->second );
260 }
261 catch( const std::bad_any_cast& )
262 {
263 return std::nullopt;
264 }
265 }
266
274 template<typename T>
275 T GetPropertyOr(const std::string& aKey, T&& aDefaultValue) const
276 {
277 if( auto aValue = GetProperty<T>( aKey ) )
278 return *aValue;
279
280 return std::forward<T>(aDefaultValue);
281 }
282
288 bool HasProperty( const std::string& aKey ) const
289 {
290 if( !IsValid() )
291 return false;
292
293 return m_properties.find( aKey ) != m_properties.end();
294 }
295
301 bool RemoveProperty( const std::string& aKey )
302 {
303 if( !IsValid() )
304 return false;
305
306 return m_properties.erase( aKey ) > 0;
307 }
308
313 bool Clear()
314 {
315 if( !IsValid() )
316 return false;
317
318 m_properties.clear();
319 return true;
320 }
321
326 size_t Size() const
327 {
328 if( !IsValid() )
329 return 0;
330 return m_properties.size();
331 }
332
337 bool Empty() const
338 {
339 if( !IsValid() )
340 return true;
341 return m_properties.empty();
342 }
343
348 std::vector<std::string> GetKeys() const
349 {
350 if( !IsValid() )
351 return {};
352
353 std::vector<std::string> keys;
354 keys.reserve( m_properties.size() );
355
356 for( const auto& [key, value] : m_properties )
357 keys.push_back( key );
358
359 return keys;
360 }
361
367 std::optional<std::reference_wrapper<const std::type_info>> GetPropertyType( const std::string& aKey ) const
368 {
369 if( !IsValid() )
370 return std::nullopt;
371
372 auto it = m_properties.find( aKey );
373
374 if( it == m_properties.end() )
375 return std::nullopt;
376
377 return std::cref( it->second.type() );
378 }
379
386 template <typename T>
387 bool HasPropertyOfType( const std::string& aKey ) const
388 {
389 if( !IsValid() )
390 return false;
391
392 auto it = m_properties.find( aKey );
393
394 if( it == m_properties.end() )
395 return false;
396
397 return it->second.type() == typeid( T );
398 }
399
403 template<PropertyValueType T>
404 bool SetTypedProperty(const std::string& aKey, T&& aValue)
405 {
406 return SetProperty(aKey, std::forward<T>(aValue));
407 }
408
409private:
410 uint64_t m_magic;
417 std::unordered_map<std::string, std::any> m_properties;
418};
419
439{
440public:
447
448 // Convenience methods that delegate to the property holder
449 template<typename T>
450 void SetProperty(const std::string& aKey, T&& aValue)
451 {
452 m_propertyHolder.SetProperty(aKey, std::forward<T>(aValue));
453 }
454
455 template<typename T>
456 std::optional<T> GetProperty(const std::string& aKey) const
457 {
458 return m_propertyHolder.GetProperty<T>(aKey);
459 }
460
461 template<typename T>
462 T GetPropertyOr(const std::string& aKey, T&& aDefaultValue) const
463 {
464 return m_propertyHolder.GetPropertyOr(aKey, std::forward<T>(aDefaultValue));
465 }
466
467 bool HasProperty(const std::string& aKey) const
468 {
469 return m_propertyHolder.HasProperty(aKey);
470 }
471
472 bool RemoveProperty(const std::string& aKey)
473 {
474 return m_propertyHolder.RemoveProperty(aKey);
475 }
476
477 template<typename T>
478 bool HasPropertyOfType(const std::string& aKey) const
479 {
480 return m_propertyHolder.HasPropertyOfType<T>(aKey);
481 }
482
483private:
485};
486
487#endif // PROPERTY_HOLDER_H
bool SetProperty(const std::string &aKey, T &&aValue)
Set a property with the given key and value.
bool SetTypedProperty(const std::string &aKey, T &&aValue)
Type-safe property setter that only accepts valid property types.
static bool SafeDelete(void *aPtr) noexcept
Safely delete a PROPERTY_HOLDER from client data.
std::optional< std::reference_wrapper< const std::type_info > > GetPropertyType(const std::string &aKey) const
Get the type information for a property.
PROPERTY_HOLDER(const PROPERTY_HOLDER &other)
Copy constructor - maintains magic value.
bool Empty() const
Check if there are no properties stored.
std::vector< std::string > GetKeys() const
Get all property keys.
static PROPERTY_HOLDER * SafeCast(void *aPtr) noexcept
Safely cast a void pointer to PROPERTY_HOLDER*.
bool RemoveProperty(const std::string &aKey)
Remove a property.
~PROPERTY_HOLDER()
Destructor - clears magic value to detect use-after-free.
static constexpr uint64_t MAGIC_VALUE
Magic value for memory validation (ASCII: "PROP" + "HLDR")
PROPERTY_HOLDER & operator=(PROPERTY_HOLDER &&other) noexcept
Move assignment operator.
static bool SafeDelete(PROPERTY_HOLDER *aHolder) noexcept
std::optional< T > GetProperty(const std::string &aKey) const
Get a property value with type checking.
std::unordered_map< std::string, std::any > m_properties
Internal storage for properties using string keys and any values.
T GetPropertyOr(const std::string &aKey, T &&aDefaultValue) const
Get a property value with a default fallback.
bool HasPropertyOfType(const std::string &aKey) const
Check if a property exists and has the expected type.
PROPERTY_HOLDER & operator=(const PROPERTY_HOLDER &other)
Copy assignment operator.
static const PROPERTY_HOLDER * SafeCast(const void *aPtr) noexcept
Safely cast a const void pointer to const PROPERTY_HOLDER*.
bool HasProperty(const std::string &aKey) const
Check if a property exists.
bool IsValid() const noexcept
Check if this instance has a valid magic value.
PROPERTY_HOLDER(PROPERTY_HOLDER &&other) noexcept
Move constructor - maintains magic value.
bool Clear()
Clear all properties.
PROPERTY_HOLDER()
Default constructor - initializes magic value.
size_t Size() const
Get the number of stored properties.
uint64_t m_magic
Magic value for memory validation.
Mixin class to add property support to any class.
const PROPERTY_HOLDER & GetPropertyHolder() const
T GetPropertyOr(const std::string &aKey, T &&aDefaultValue) const
PROPERTY_HOLDER m_propertyHolder
std::optional< T > GetProperty(const std::string &aKey) const
void SetProperty(const std::string &aKey, T &&aValue)
PROPERTY_HOLDER & GetPropertyHolder()
Get the property holder for this object.
bool HasPropertyOfType(const std::string &aKey) const
bool HasProperty(const std::string &aKey) const
bool RemoveProperty(const std::string &aKey)
A C++20 property system for arbitrary key-value storage with type safety.