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