KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ki_any.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20// This code is a modified version of the GCC standard library implementation (see original licence below):
21
22// Copyright (C) 2014-2024 Free Software Foundation, Inc.
23//
24// This file is part of the GNU ISO C++ Library. This library is free
25// software; you can redistribute it and/or modify it under the
26// terms of the GNU General Public License as published by the
27// Free Software Foundation; either version 3, or (at your option)
28// any later version.
29//
30// This library is distributed in the hope that it will be useful,
31// but WITHOUT ANY WARRANTY; without even the implied warranty of
32// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33// GNU General Public License for more details.
34//
35// Under Section 7 of GPL version 3, you are granted additional
36// permissions described in the GCC Runtime Library Exception, version
37// 3.1, as published by the Free Software Foundation.
38//
39// You should have received a copy of the GNU General Public License and
40// a copy of the GCC Runtime Library Exception along with this program;
41// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
42// <http://www.gnu.org/licenses/>.
43
44
52#ifndef INCLUDE_KI_ANY_H_
53#define INCLUDE_KI_ANY_H_
54
55#include <initializer_list>
56#include <new>
57#include <typeinfo>
58#include <utility>
59
60namespace ki
61{
62
63/*
64 * Disambiguation helpers
65 */
66
67template <typename>
68inline constexpr bool is_in_place_type_v = false;
69
70template <typename T>
71inline constexpr bool is_in_place_type_v<std::in_place_type_t<T>> = true;
72
76class bad_any_cast final : public std::bad_cast
77{
78public:
79 const char* what() const noexcept override { return "bad ki::any_cast"; }
80};
81
88class any
89{
90 // Holds either a pointer to a heap object or the contained object itself
91 union Storage
92 {
93 constexpr Storage() : m_ptr{ nullptr } {}
94
95 // Prevent trivial copies of this type as the buffer might hold a non-POD
96 Storage( const Storage& ) = delete;
97 Storage& operator=( const Storage& ) = delete;
98
99 void* m_ptr;
100 unsigned char m_buffer[sizeof( m_ptr )];
101 };
102
103 template <typename T, bool Safe = std::is_nothrow_move_constructible_v<T>,
104 bool Fits = ( sizeof( T ) <= sizeof( Storage ) )
105 && ( alignof( T ) <= alignof( Storage ) )>
106 using Use_Internal_Storage = std::integral_constant<bool, Safe && Fits>;
107
108 template <typename T>
109 struct Manager_Internal; // uses small-object optimization
110
111 template <typename T>
112 struct Manager_External; // creates contained object on the heap
113
114 template <typename T>
115 using Manager = std::conditional_t<Use_Internal_Storage<T>::value, Manager_Internal<T>,
117
118 template <typename T, typename V = std::decay_t<T>>
119 using decay_if_not_any = std::enable_if_t<!std::is_same_v<V, any>, V>;
120
122 template <typename T, typename... Args, typename Mgr = Manager<T>>
123 void do_emplace( Args&&... args )
124 {
125 reset();
126 Mgr::do_create( m_storage, std::forward<Args>( args )... );
127 m_manager = &Mgr::m_manage_fn;
128 }
129
131 template <typename T, typename U, typename... Args, typename Mgr = Manager<T>>
132 void do_emplace( std::initializer_list<U> il, Args&&... args )
133 {
134 reset();
135 Mgr::do_create( m_storage, il, std::forward<Args>( args )... );
136 m_manager = &Mgr::m_manage_fn;
137 }
138
139 template <typename Res, typename T, typename... Args>
141 std::enable_if<std::is_copy_constructible_v<T> && std::is_constructible_v<T, Args...>,
142 Res>;
143
144 template <typename T, typename... Args>
145 using any_constructible_t = typename any_constructible<bool, T, Args...>::type;
146
147 template <typename V, typename... Args>
148 using any_emplace_t = typename any_constructible<V&, V, Args...>::type;
149
150public:
152 constexpr any() noexcept : m_manager( nullptr ) {}
153
155 any( const any& other )
156 {
157 if( !other.has_value() )
158 {
159 m_manager = nullptr;
160 }
161 else
162 {
163 Arg arg;
164 arg.m_any = this;
165 other.m_manager( Op_Clone, &other, &arg );
166 }
167 }
168
170 any( any&& other ) noexcept
171 {
172 if( !other.has_value() )
173 {
174 m_manager = nullptr;
175 }
176 else
177 {
178 Arg arg;
179 arg.m_any = this;
180 other.m_manager( Op_Xfer, &other, &arg );
181 }
182 }
183
185 template <typename T, typename V = decay_if_not_any<T>, typename Mgr = Manager<V>,
186 std::enable_if_t<std::is_copy_constructible_v<V> && !is_in_place_type_v<V>, bool> =
187 true>
188
189 any( T&& value ) : m_manager( &Mgr::m_manage_fn )
190 {
191 Mgr::do_create( m_storage, std::forward<T>( value ) );
192 }
193
195 template <typename T, typename... Args, typename V = std::decay_t<T>, typename Mgr = Manager<V>,
196 any_constructible_t<V, Args&&...> = false>
197 explicit any( std::in_place_type_t<T>, Args&&... args ) : m_manager( &Mgr::m_manage_fn )
198 {
199 Mgr::do_create( m_storage, std::forward<Args>( args )... );
200 }
201
203 template <typename T, typename U, typename... Args, typename V = std::decay_t<T>,
204 typename Mgr = Manager<V>,
205 any_constructible_t<V, std::initializer_list<U>&, Args&&...> = false>
206 explicit any( std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args ) :
207 m_manager( &Mgr::m_manage_fn )
208 {
209 Mgr::do_create( m_storage, il, std::forward<Args>( args )... );
210 }
211
213 ~any() { reset(); }
214
216 any& operator=( const any& rhs )
217 {
218 *this = any( rhs );
219 return *this;
220 }
221
223 any& operator=( any&& rhs ) noexcept
224 {
225 if( !rhs.has_value() )
226 {
227 reset();
228 }
229 else if( this != &rhs )
230 {
231 reset();
232 Arg arg;
233 arg.m_any = this;
234 rhs.m_manager( Op_Xfer, &rhs, &arg );
235 }
236
237 return *this;
238 }
239
241 template <typename T>
242 std::enable_if_t<std::is_copy_constructible_v<decay_if_not_any<T>>, any&> operator=( T&& rhs )
243 {
244 *this = any( std::forward<T>( rhs ) );
245 return *this;
246 }
247
249 template <typename T, typename... Args>
250 any_emplace_t<std::decay_t<T>, Args...> emplace( Args&&... args )
251 {
252 using V = std::decay_t<T>;
253 do_emplace<V>( std::forward<Args>( args )... );
255 }
256
258 template <typename T, typename U, typename... Args>
259 any_emplace_t<std::decay_t<T>, std::initializer_list<U>&, Args&&...>
260 emplace( std::initializer_list<U> il, Args&&... args )
261 {
262 using V = std::decay_t<T>;
263 do_emplace<V, U>( il, std::forward<Args>( args )... );
265 }
266
268 void reset() noexcept
269 {
270 if( has_value() )
271 {
272 m_manager( Op_Destroy, this, nullptr );
273 m_manager = nullptr;
274 }
275 }
276
278 void swap( any& rhs ) noexcept
279 {
280 if( !has_value() && !rhs.has_value() )
281 return;
282
283 if( has_value() && rhs.has_value() )
284 {
285 if( this == &rhs )
286 return;
287
288 any tmp;
289 Arg arg;
290 arg.m_any = &tmp;
291 rhs.m_manager( Op_Xfer, &rhs, &arg );
292 arg.m_any = &rhs;
293 m_manager( Op_Xfer, this, &arg );
294 arg.m_any = this;
295 tmp.m_manager( Op_Xfer, &tmp, &arg );
296 }
297 else
298 {
299 any* empty = !has_value() ? this : &rhs;
300 any* full = !has_value() ? &rhs : this;
301 Arg arg;
302 arg.m_any = empty;
303 full->m_manager( Op_Xfer, full, &arg );
304 }
305 }
306
308 bool has_value() const noexcept { return m_manager != nullptr; }
309
310
312 const std::type_info& type() const noexcept
313 {
314 if( !has_value() )
315 return typeid( void );
316
317 Arg arg;
318 m_manager( Op_Get_Type_Info, this, &arg );
319 return *arg.m_typeinfo;
320 }
321
323 template <typename T>
324 static constexpr bool is_valid_any_cast()
325 {
326 return std::is_reference_v<T> || std::is_copy_constructible_v<T>;
327 }
329
330private:
331 enum Op
332 {
337 Op_Xfer
338 };
339
340 union Arg
341 {
342 void* m_obj;
343 const std::type_info* m_typeinfo;
345 };
346
347 void ( *m_manager )( Op, const any*, Arg* );
349
351 template <typename T>
352 friend void* any_caster( const any* any );
354
355 // Manages in-place contained object
356 template <typename T>
358 {
359 static void m_manage_fn( Op which, const any* any, Arg* arg );
360
361 template <typename U>
362 static void do_create( Storage& storage, U&& value )
363 {
364 void* addr = &storage.m_buffer;
365 ::new( addr ) T( std::forward<U>( value ) );
366 }
367
368 template <typename... Args>
369 static void do_create( Storage& storage, Args&&... args )
370 {
371 void* addr = &storage.m_buffer;
372 ::new( addr ) T( std::forward<Args>( args )... );
373 }
374
375 static T* do_access( const Storage& storage )
376 {
377 // The contained object is in storage.m_buffer
378 const void* addr = &storage.m_buffer;
379 return static_cast<T*>( const_cast<void*>( addr ) );
380 }
381 };
382
383 // Manages externally (heap) contained object
384 template <typename T>
386 {
387 static void m_manage_fn( Op which, const any* any, Arg* arg );
388
389 template <typename U>
390 static void do_create( Storage& storage, U&& value )
391 {
392 storage.m_ptr = new T( std::forward<U>( value ) );
393 }
394 template <typename... Args>
395 static void do_create( Storage& storage, Args&&... args )
396 {
397 storage.m_ptr = new T( std::forward<Args>( args )... );
398 }
399 static T* do_access( const Storage& storage )
400 {
401 // The contained object is in *storage.m_ptr
402 return static_cast<T*>( storage.m_ptr );
403 }
404 };
405};
406
408inline void swap( any& x, any& y ) noexcept
409{
410 x.swap( y );
411}
412
414template <typename T, typename... Args>
415std::enable_if_t<std::is_constructible_v<any, std::in_place_type_t<T>, Args...>, any>
416make_any( Args&&... args )
417{
418 return any( std::in_place_type<T>, std::forward<Args>( args )... );
419}
420
422template <typename T, typename U, typename... Args>
423std::enable_if_t<
424 std::is_constructible_v<any, std::in_place_type_t<T>, std::initializer_list<U>&, Args...>,
425 any>
426make_any( std::initializer_list<U> il, Args&&... args )
427{
428 return any( std::in_place_type<T>, il, std::forward<Args>( args )... );
429}
430
441template <typename ValueType>
442ValueType any_cast( const any& any )
443{
444 using U = std::remove_cvref_t<ValueType>;
445
446 static_assert( any::is_valid_any_cast<ValueType>(),
447 "Template argument must be a reference or CopyConstructible type" );
448 static_assert( std::is_constructible_v<ValueType, const U&>,
449 "Template argument must be constructible from a const value" );
450
451 auto p = any_cast<U>( &any );
452
453 if( p )
454 return static_cast<ValueType>( *p );
455
456 throw bad_any_cast{};
457}
458
470template <typename ValueType>
471ValueType any_cast( any& any )
472{
473 using U = std::remove_cvref_t<ValueType>;
474
475 static_assert( any::is_valid_any_cast<ValueType>(),
476 "Template argument must be a reference or CopyConstructible type" );
477 static_assert( std::is_constructible_v<ValueType, U&>,
478 "Template argument must be constructible from an lvalue" );
479
480 auto p = any_cast<U>( &any );
481
482 if( p )
483 return static_cast<ValueType>( *p );
484
485 throw bad_any_cast{};
486}
487
488template <typename ValueType>
489ValueType any_cast( any&& any )
490{
491 using U = std::remove_cvref_t<ValueType>;
492
493 static_assert( any::is_valid_any_cast<ValueType>(),
494 "Template argument must be a reference or CopyConstructible type" );
495 static_assert( std::is_constructible_v<ValueType, U>,
496 "Template argument must be constructible from an rvalue" );
497
498 auto p = any_cast<U>( &any );
499
500 if( p )
501 return static_cast<ValueType>( std::move( *p ) );
502
503 throw bad_any_cast{};
504}
505
507
509template <typename T>
510void* any_caster( const any* any )
511{
512 // any_cast<T> returns non-null if any->type() == typeid(T) and
513 // typeid(T) ignores cv-qualifiers so remove them:
514 using U = std::remove_cv_t<T>;
515
516 if constexpr( !std::is_same_v<std::decay_t<U>, U> )
517 {
518 // The contained value has a decayed type, so if decay_t<U> is not U,
519 // then it's not possible to have a contained value of type U
520 return nullptr;
521 }
522 else if constexpr( !std::is_copy_constructible_v<U> )
523 {
524 // Only copy constructible types can be used for contained values
525 return nullptr;
526 }
527 else if( any->m_manager == &any::Manager<U>::m_manage_fn
528 || any->type().hash_code() == typeid( T ).hash_code() )
529 {
530 return any::Manager<U>::do_access( any->m_storage );
531 }
532
533 return nullptr;
534}
536
548template <typename ValueType>
549const ValueType* any_cast( const any* any ) noexcept
550{
551 static_assert( !std::is_void_v<ValueType> );
552
553 // As an optimization, don't bother instantiating any_caster for
554 // function types, since std::any can only hold objects
555 if constexpr( std::is_object_v<ValueType> )
556 {
557 if( any )
558 return static_cast<ValueType*>( any_caster<ValueType>( any ) );
559 }
560
561 return nullptr;
562}
563
564template <typename ValueType>
565ValueType* any_cast( any* any ) noexcept
566{
567 static_assert( !std::is_void_v<ValueType> );
568
569 if constexpr( std::is_object_v<ValueType> )
570 if( any )
571 return static_cast<ValueType*>( any_caster<ValueType>( any ) );
572 return nullptr;
573}
575
576template <typename T>
578{
579 // The contained object is in m_storage.m_buffer
580 auto ptr = reinterpret_cast<const T*>( &any->m_storage.m_buffer );
581 switch( which )
582 {
583 case Op_Access: arg->m_obj = const_cast<T*>( ptr ); break;
584 case Op_Get_Type_Info: arg->m_typeinfo = &typeid( T ); break;
585 case Op_Clone:
586 ::new( &arg->m_any->m_storage.m_buffer ) T( *ptr );
587 arg->m_any->m_manager = any->m_manager;
588 break;
589 case Op_Destroy: ptr->~T(); break;
590 case Op_Xfer:
591 ::new( &arg->m_any->m_storage.m_buffer ) T( std::move( *const_cast<T*>( ptr ) ) );
592 ptr->~T();
593 arg->m_any->m_manager = any->m_manager;
594 const_cast<ki::any*>( any )->m_manager = nullptr;
595 break;
596 }
597}
598
599template <typename T>
601{
602 // The contained object is *m_storage.m_ptr
603 auto ptr = static_cast<const T*>( any->m_storage.m_ptr );
604 switch( which )
605 {
606 case Op_Access: arg->m_obj = const_cast<T*>( ptr ); break;
607 case Op_Get_Type_Info: arg->m_typeinfo = &typeid( T ); break;
608 case Op_Clone:
609 arg->m_any->m_storage.m_ptr = new T( *ptr );
610 arg->m_any->m_manager = any->m_manager;
611 break;
612 case Op_Destroy: delete ptr; break;
613 case Op_Xfer:
615 arg->m_any->m_manager = any->m_manager;
616 const_cast<ki::any*>( any )->m_manager = nullptr;
617 break;
618 }
619}
620
621} // namespace ki
622
623#endif // INCLUDE_KI_ANY_H_
A type-safe container of any type.
Definition: ki_any.h:89
std::enable_if< std::is_copy_constructible_v< T > &&std::is_constructible_v< T, Args... >, Res > any_constructible
Definition: ki_any.h:142
typename any_constructible< bool, T, Args... >::type any_constructible_t
Definition: ki_any.h:145
any(const any &other)
Copy constructor, copies the state of other.
Definition: ki_any.h:155
bool has_value() const noexcept
Reports whether there is a contained object or not.
Definition: ki_any.h:308
any(std::in_place_type_t< T >, std::initializer_list< U > il, Args &&... args)
Construct with an object created from il and args as the contained object.
Definition: ki_any.h:206
constexpr any() noexcept
Default constructor, creates an empty object.
Definition: ki_any.h:152
void do_emplace(Args &&... args)
Emplace with an object created from args as the contained object.
Definition: ki_any.h:123
void reset() noexcept
If not empty, destroys the contained object.
Definition: ki_any.h:268
@ Op_Get_Type_Info
Definition: ki_any.h:334
@ Op_Destroy
Definition: ki_any.h:336
@ Op_Clone
Definition: ki_any.h:335
@ Op_Access
Definition: ki_any.h:333
@ Op_Xfer
Definition: ki_any.h:337
any(T &&value)
Construct with a copy of value as the contained object.
Definition: ki_any.h:189
void swap(any &rhs) noexcept
Exchange state with another object.
Definition: ki_any.h:278
typename any_constructible< V &, V, Args... >::type any_emplace_t
Definition: ki_any.h:148
any_emplace_t< std::decay_t< T >, std::initializer_list< U > &, Args &&... > emplace(std::initializer_list< U > il, Args &&... args)
Emplace with an object created from il and args as the contained object.
Definition: ki_any.h:260
any_emplace_t< std::decay_t< T >, Args... > emplace(Args &&... args)
Emplace with an object created from args as the contained object.
Definition: ki_any.h:250
std::conditional_t< Use_Internal_Storage< T >::value, Manager_Internal< T >, Manager_External< T > > Manager
Definition: ki_any.h:116
Storage m_storage
Definition: ki_any.h:348
any & operator=(const any &rhs)
Copy the state of another object.
Definition: ki_any.h:216
~any()
Destructor, calls reset()
Definition: ki_any.h:213
any(any &&other) noexcept
Move constructor, transfer the state from other.
Definition: ki_any.h:170
std::enable_if_t<!std::is_same_v< V, any >, V > decay_if_not_any
Definition: ki_any.h:119
std::enable_if_t< std::is_copy_constructible_v< decay_if_not_any< T > >, any & > operator=(T &&rhs)
Store a copy of rhs as the contained object.
Definition: ki_any.h:242
any & operator=(any &&rhs) noexcept
Move assignment operator.
Definition: ki_any.h:223
void do_emplace(std::initializer_list< U > il, Args &&... args)
Emplace with an object created from il and args as the contained object.
Definition: ki_any.h:132
any(std::in_place_type_t< T >, Args &&... args)
Construct with an object created from args as the contained object.
Definition: ki_any.h:197
void(* m_manager)(Op, const any *, Arg *)
Definition: ki_any.h:347
const std::type_info & type() const noexcept
The typeid of the contained object, or typeid(void) if empty.
Definition: ki_any.h:312
Exception class thrown by a failed any_cast.
Definition: ki_any.h:77
const char * what() const noexcept override
Definition: ki_any.h:79
static bool empty(const wxTextEntryBase *aCtrl)
An implementation of std::any_cast, which uses type_info::hash_code to check validity of cast types.
Definition: ki_any.h:61
constexpr bool is_in_place_type_v
Definition: ki_any.h:68
std::enable_if_t< std::is_constructible_v< any, std::in_place_type_t< T >, Args... >, any > make_any(Args &&... args)
Create a any holding a T constructed from args...
Definition: ki_any.h:416
ValueType any_cast(const any &any)
Access the contained object.
Definition: ki_any.h:442
static void do_create(Storage &storage, U &&value)
Definition: ki_any.h:390
static void m_manage_fn(Op which, const any *any, Arg *arg)
Definition: ki_any.h:600
static T * do_access(const Storage &storage)
Definition: ki_any.h:399
static void do_create(Storage &storage, Args &&... args)
Definition: ki_any.h:395
static void do_create(Storage &storage, Args &&... args)
Definition: ki_any.h:369
static T * do_access(const Storage &storage)
Definition: ki_any.h:375
static void m_manage_fn(Op which, const any *any, Arg *arg)
Definition: ki_any.h:577
static void do_create(Storage &storage, U &&value)
Definition: ki_any.h:362
any * m_any
Definition: ki_any.h:344
const std::type_info * m_typeinfo
Definition: ki_any.h:343
void * m_obj
Definition: ki_any.h:342
void * m_ptr
Definition: ki_any.h:99
constexpr Storage()
Definition: ki_any.h:93
Storage & operator=(const Storage &)=delete
Storage(const Storage &)=delete
unsigned char m_buffer[sizeof(m_ptr)]
Definition: ki_any.h:100