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, you may find one here:
18 * https://www.gnu.org/licenses/gpl-3.0.en.html
19 * or you may search the http://www.gnu.org website for the version 32 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#ifndef PROPERTY_HOLDER_H
25#define PROPERTY_HOLDER_H
26
27#include <any>
28#include <string>
29#include <unordered_map>
30#include <type_traits>
31#include <optional>
32#include <concepts>
33#include <cstdint>
34
35
76template<typename T>
77concept PropertyValueType = std::copy_constructible<T> && std::destructible<T>;
78
80{
81public:
83 static constexpr uint64_t MAGIC_VALUE = 0x50524F5048444C52ULL;
84
90 {
91 }
92
99 {
100 }
101
105 PROPERTY_HOLDER( PROPERTY_HOLDER&& other ) noexcept :
107 m_properties( std::move( other.m_properties ) )
108 {
109 }
110
115 {
116 if( this != &other )
118
119 return *this;
120 }
121
126 {
127 if( this != &other )
128 m_properties = std::move( other.m_properties );
129
130 return *this;
131 }
132
137 {
138 m_magic = 0xDEADBEEFDEADBEEFULL; // Clear magic to detect use-after-free
139 }
140
145 bool IsValid() const noexcept { return m_magic == MAGIC_VALUE; }
146
152 static PROPERTY_HOLDER* SafeCast( void* aPtr ) noexcept
153 {
154 if( !aPtr )
155 return nullptr;
156
157 try
158 {
159 PROPERTY_HOLDER* aCandidate = reinterpret_cast<PROPERTY_HOLDER*>( aPtr );
160 if( aCandidate->m_magic == MAGIC_VALUE )
161 {
162 return aCandidate;
163 }
164 }
165 catch( ... )
166 {
167 // Any exception means invalid memory
168 }
169 return nullptr;
170 }
171
177 static const PROPERTY_HOLDER* SafeCast( const void* aPtr ) noexcept
178 {
179 if( !aPtr )
180 return nullptr;
181
182 try
183 {
184 const PROPERTY_HOLDER* aCandidate = reinterpret_cast<const PROPERTY_HOLDER*>( aPtr );
185 if( aCandidate->m_magic == MAGIC_VALUE )
186 {
187 return aCandidate;
188 }
189 }
190 catch( ... )
191 {
192 // Any exception means invalid memory
193 }
194 return nullptr;
195 }
196
202 static bool SafeDelete( void* aPtr ) noexcept
203 {
204 PROPERTY_HOLDER* aHolder = SafeCast( aPtr );
205
206 if( aHolder )
207 {
208 delete aHolder;
209 return true;
210 }
211
212 return false;
213 }
214
215 static bool SafeDelete( PROPERTY_HOLDER* aHolder ) noexcept
216 {
217 if( aHolder )
218 {
219 delete aHolder;
220 return true;
221 }
222
223 return false;
224 }
225
233 template <typename T>
234 bool SetProperty( const std::string& aKey, T&& aValue )
235 {
236 if( !IsValid() )
237 return false;
238
239 m_properties[aKey] = std::forward<T>( aValue );
240 return true;
241 }
242
249 template <typename T>
250 std::optional<T> GetProperty( const std::string& aKey ) const
251 {
252 if( !IsValid() )
253 return std::nullopt;
254
255 auto it = m_properties.find( aKey );
256 if( it == m_properties.end() )
257 {
258 return std::nullopt;
259 }
260
261 try
262 {
263 return std::any_cast<T>( it->second );
264 }
265 catch( const std::bad_any_cast& )
266 {
267 return std::nullopt;
268 }
269 }
270
278 template<typename T>
279 T GetPropertyOr(const std::string& aKey, T&& aDefaultValue) const
280 {
281 if( auto aValue = GetProperty<T>( aKey ) )
282 return *aValue;
283
284 return std::forward<T>(aDefaultValue);
285 }
286
292 bool HasProperty( const std::string& aKey ) const
293 {
294 if( !IsValid() )
295 return false;
296
297 return m_properties.find( aKey ) != m_properties.end();
298 }
299
305 bool RemoveProperty( const std::string& aKey )
306 {
307 if( !IsValid() )
308 return false;
309
310 return m_properties.erase( aKey ) > 0;
311 }
312
317 bool Clear()
318 {
319 if( !IsValid() )
320 return false;
321
322 m_properties.clear();
323 return true;
324 }
325
330 size_t Size() const
331 {
332 if( !IsValid() )
333 return 0;
334 return m_properties.size();
335 }
336
341 bool Empty() const
342 {
343 if( !IsValid() )
344 return true;
345 return m_properties.empty();
346 }
347
352 std::vector<std::string> GetKeys() const
353 {
354 if( !IsValid() )
355 return {};
356
357 std::vector<std::string> keys;
358 keys.reserve( m_properties.size() );
359
360 for( const auto& [key, value] : m_properties )
361 keys.push_back( key );
362
363 return keys;
364 }
365
371 std::optional<std::reference_wrapper<const std::type_info>> GetPropertyType( const std::string& aKey ) const
372 {
373 if( !IsValid() )
374 return std::nullopt;
375
376 auto it = m_properties.find( aKey );
377
378 if( it == m_properties.end() )
379 return std::nullopt;
380
381 return std::cref( it->second.type() );
382 }
383
390 template <typename T>
391 bool HasPropertyOfType( const std::string& aKey ) const
392 {
393 if( !IsValid() )
394 return false;
395
396 auto it = m_properties.find( aKey );
397
398 if( it == m_properties.end() )
399 return false;
400
401 return it->second.type() == typeid( T );
402 }
403
407 template<PropertyValueType T>
408 bool SetTypedProperty(const std::string& aKey, T&& aValue)
409 {
410 return SetProperty(aKey, std::forward<T>(aValue));
411 }
412
413private:
414 uint64_t m_magic;
421 std::unordered_map<std::string, std::any> m_properties;
422};
423
443{
444public:
451
452 // Convenience methods that delegate to the property holder
453 template<typename T>
454 void SetProperty(const std::string& aKey, T&& aValue)
455 {
456 m_propertyHolder.SetProperty(aKey, std::forward<T>(aValue));
457 }
458
459 template<typename T>
460 std::optional<T> GetProperty(const std::string& aKey) const
461 {
462 return m_propertyHolder.GetProperty<T>(aKey);
463 }
464
465 template<typename T>
466 T GetPropertyOr(const std::string& aKey, T&& aDefaultValue) const
467 {
468 return m_propertyHolder.GetPropertyOr(aKey, std::forward<T>(aDefaultValue));
469 }
470
471 bool HasProperty(const std::string& aKey) const
472 {
473 return m_propertyHolder.HasProperty(aKey);
474 }
475
476 bool RemoveProperty(const std::string& aKey)
477 {
478 return m_propertyHolder.RemoveProperty(aKey);
479 }
480
481 template<typename T>
482 bool HasPropertyOfType(const std::string& aKey) const
483 {
485 }
486
487private:
489};
490
491#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.