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
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// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
43// <http://www.gnu.org/licenses/>.
44
45
56#ifndef INCLUDE_KI_ANY_H_
57#define INCLUDE_KI_ANY_H_
58
59#include <initializer_list>
60#include <new>
61#include <typeinfo>
62#include <utility>
63
64namespace ki
65{
66
67/*
68 * Disambiguation helpers
69 */
70
71template <typename>
72inline constexpr bool is_in_place_type_v = false;
73
74template <typename T>
75inline constexpr bool is_in_place_type_v<std::in_place_type_t<T>> = true;
76
80class bad_any_cast final : public std::bad_cast
81{
82public:
83 const char* what() const noexcept override { return "bad ki::any_cast"; }
84};
85
92class any
93{
94 // Holds either a pointer to a heap object or the contained object itself
95 union Storage
96 {
97 constexpr Storage() : m_ptr{ nullptr } {}
98
99 // Prevent trivial copies of this type as the buffer might hold a non-POD
100 Storage( const Storage& ) = delete;
101 Storage& operator=( const Storage& ) = delete;
102
103 void* m_ptr;
104 unsigned char m_buffer[sizeof( m_ptr )];
105 };
106
107 template <typename T, bool Safe = std::is_nothrow_move_constructible_v<T>,
108 bool Fits = ( sizeof( T ) <= sizeof( Storage ) )
109 && ( alignof( T ) <= alignof( Storage ) )>
110 using Use_Internal_Storage = std::integral_constant<bool, Safe && Fits>;
111
112 template <typename T>
113 struct Manager_Internal; // uses small-object optimization
114
115 template <typename T>
116 struct Manager_External; // creates contained object on the heap
117
118 template <typename T>
119 using Manager = std::conditional_t<Use_Internal_Storage<T>::value, Manager_Internal<T>,
121
122 template <typename T, typename V = std::decay_t<T>>
123 using decay_if_not_any = std::enable_if_t<!std::is_same_v<V, any>, V>;
124
126 template <typename T, typename... Args, typename Mgr = Manager<T>>
127 void do_emplace( Args&&... args )
128 {
129 reset();
130 Mgr::do_create( m_storage, std::forward<Args>( args )... );
131 m_manager = &Mgr::m_manage_fn;
132 }
133
135 template <typename T, typename U, typename... Args, typename Mgr = Manager<T>>
136 void do_emplace( std::initializer_list<U> il, Args&&... args )
137 {
138 reset();
139 Mgr::do_create( m_storage, il, std::forward<Args>( args )... );
140 m_manager = &Mgr::m_manage_fn;
141 }
142
143 template <typename Res, typename T, typename... Args>
145 std::enable_if<std::is_copy_constructible_v<T> && std::is_constructible_v<T, Args...>,
146 Res>;
147
148 template <typename T, typename... Args>
149 using any_constructible_t = typename any_constructible<bool, T, Args...>::type;
150
151 template <typename V, typename... Args>
152 using any_emplace_t = typename any_constructible<V&, V, Args...>::type;
153
154public:
156 constexpr any() noexcept : m_manager( nullptr ) {}
157
159 any( const any& other )
160 {
161 if( !other.has_value() )
162 {
163 m_manager = nullptr;
164 }
165 else
166 {
167 Arg arg;
168 arg.m_any = this;
169 other.m_manager( Op_Clone, &other, &arg );
170 }
171 }
172
174 any( any&& other ) noexcept
175 {
176 if( !other.has_value() )
177 {
178 m_manager = nullptr;
179 }
180 else
181 {
182 Arg arg;
183 arg.m_any = this;
184 other.m_manager( Op_Xfer, &other, &arg );
185 }
186 }
187
189 template <typename T, typename V = decay_if_not_any<T>, typename Mgr = Manager<V>,
190 std::enable_if_t<std::is_copy_constructible_v<V> && !is_in_place_type_v<V>, bool> =
191 true>
192
193 any( T&& value ) : m_manager( &Mgr::m_manage_fn )
194 {
195 Mgr::do_create( m_storage, std::forward<T>( value ) );
196 }
197
199 template <typename T, typename... Args, typename V = std::decay_t<T>, typename Mgr = Manager<V>,
200 any_constructible_t<V, Args&&...> = false>
201 explicit any( std::in_place_type_t<T>, Args&&... args ) : m_manager( &Mgr::m_manage_fn )
202 {
203 Mgr::do_create( m_storage, std::forward<Args>( args )... );
204 }
205
207 template <typename T, typename U, typename... Args, typename V = std::decay_t<T>,
208 typename Mgr = Manager<V>,
209 any_constructible_t<V, std::initializer_list<U>&, Args&&...> = false>
210 explicit any( std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args ) :
211 m_manager( &Mgr::m_manage_fn )
212 {
213 Mgr::do_create( m_storage, il, std::forward<Args>( args )... );
214 }
215
217 ~any() { reset(); }
218
220 any& operator=( const any& rhs )
221 {
222 *this = any( rhs );
223 return *this;
224 }
225
227 any& operator=( any&& rhs ) noexcept
228 {
229 if( !rhs.has_value() )
230 {
231 reset();
232 }
233 else if( this != &rhs )
234 {
235 reset();
236 Arg arg;
237 arg.m_any = this;
238 rhs.m_manager( Op_Xfer, &rhs, &arg );
239 }
240
241 return *this;
242 }
243
245 template <typename T>
246 std::enable_if_t<std::is_copy_constructible_v<decay_if_not_any<T>>, any&> operator=( T&& rhs )
247 {
248 *this = any( std::forward<T>( rhs ) );
249 return *this;
250 }
251
253 template <typename T, typename... Args>
254 any_emplace_t<std::decay_t<T>, Args...> emplace( Args&&... args )
255 {
256 using V = std::decay_t<T>;
257 do_emplace<V>( std::forward<Args>( args )... );
259 }
260
262 template <typename T, typename U, typename... Args>
263 any_emplace_t<std::decay_t<T>, std::initializer_list<U>&, Args&&...>
264 emplace( std::initializer_list<U> il, Args&&... args )
265 {
266 using V = std::decay_t<T>;
267 do_emplace<V, U>( il, std::forward<Args>( args )... );
269 }
270
272 void reset() noexcept
273 {
274 if( has_value() )
275 {
276 m_manager( Op_Destroy, this, nullptr );
277 m_manager = nullptr;
278 }
279 }
280
282 void swap( any& rhs ) noexcept
283 {
284 if( !has_value() && !rhs.has_value() )
285 return;
286
287 if( has_value() && rhs.has_value() )
288 {
289 if( this == &rhs )
290 return;
291
292 any tmp;
293 Arg arg;
294 arg.m_any = &tmp;
295 rhs.m_manager( Op_Xfer, &rhs, &arg );
296 arg.m_any = &rhs;
297 m_manager( Op_Xfer, this, &arg );
298 arg.m_any = this;
299 tmp.m_manager( Op_Xfer, &tmp, &arg );
300 }
301 else
302 {
303 any* empty = !has_value() ? this : &rhs;
304 any* full = !has_value() ? &rhs : this;
305 Arg arg;
306 arg.m_any = empty;
307 full->m_manager( Op_Xfer, full, &arg );
308 }
309 }
310
312 bool has_value() const noexcept { return m_manager != nullptr; }
313
314
316 const std::type_info& type() const noexcept
317 {
318 if( !has_value() )
319 return typeid( void );
320
321 Arg arg;
322 m_manager( Op_Get_Type_Info, this, &arg );
323 return *arg.m_typeinfo;
324 }
325
327 template <typename T>
328 static constexpr bool is_valid_any_cast()
329 {
330 return std::is_reference_v<T> || std::is_copy_constructible_v<T>;
331 }
333
334private:
335 enum Op
336 {
341 Op_Xfer
342 };
343
344 union Arg
345 {
346 void* m_obj;
347 const std::type_info* m_typeinfo;
349 };
350
351 void ( *m_manager )( Op, const any*, Arg* );
353
355 template <typename T>
356 friend void* any_caster( const any* any );
358
359 // Manages in-place contained object
360 template <typename T>
362 {
363 static void m_manage_fn( Op which, const any* any, Arg* arg );
364
365 template <typename U>
366 static void do_create( Storage& storage, U&& value )
367 {
368 void* addr = &storage.m_buffer;
369 ::new( addr ) T( std::forward<U>( value ) );
370 }
371
372 template <typename... Args>
373 static void do_create( Storage& storage, Args&&... args )
374 {
375 void* addr = &storage.m_buffer;
376 ::new( addr ) T( std::forward<Args>( args )... );
377 }
378
379 static T* do_access( const Storage& storage )
380 {
381 // The contained object is in storage.m_buffer
382 const void* addr = &storage.m_buffer;
383 return static_cast<T*>( const_cast<void*>( addr ) );
384 }
385 };
386
387 // Manages externally (heap) contained object
388 template <typename T>
390 {
391 static void m_manage_fn( Op which, const any* any, Arg* arg );
392
393 template <typename U>
394 static void do_create( Storage& storage, U&& value )
395 {
396 storage.m_ptr = new T( std::forward<U>( value ) );
397 }
398 template <typename... Args>
399 static void do_create( Storage& storage, Args&&... args )
400 {
401 storage.m_ptr = new T( std::forward<Args>( args )... );
402 }
403 static T* do_access( const Storage& storage )
404 {
405 // The contained object is in *storage.m_ptr
406 return static_cast<T*>( storage.m_ptr );
407 }
408 };
409};
410
412inline void swap( any& x, any& y ) noexcept
413{
414 x.swap( y );
415}
416
418template <typename T, typename... Args>
419std::enable_if_t<std::is_constructible_v<any, std::in_place_type_t<T>, Args...>, any>
420make_any( Args&&... args )
421{
422 return any( std::in_place_type<T>, std::forward<Args>( args )... );
423}
424
426template <typename T, typename U, typename... Args>
427std::enable_if_t<
428 std::is_constructible_v<any, std::in_place_type_t<T>, std::initializer_list<U>&, Args...>,
429 any>
430make_any( std::initializer_list<U> il, Args&&... args )
431{
432 return any( std::in_place_type<T>, il, std::forward<Args>( args )... );
433}
434
445template <typename ValueType>
446ValueType any_cast( const any& any )
447{
448 using U = std::remove_cvref_t<ValueType>;
449
450 static_assert( any::is_valid_any_cast<ValueType>(),
451 "Template argument must be a reference or CopyConstructible type" );
452 static_assert( std::is_constructible_v<ValueType, const U&>,
453 "Template argument must be constructible from a const value" );
454
455 auto p = any_cast<U>( &any );
456
457 if( p )
458 return static_cast<ValueType>( *p );
459
460 throw bad_any_cast{};
461}
462
474template <typename ValueType>
475ValueType any_cast( any& any )
476{
477 using U = std::remove_cvref_t<ValueType>;
478
479 static_assert( any::is_valid_any_cast<ValueType>(),
480 "Template argument must be a reference or CopyConstructible type" );
481 static_assert( std::is_constructible_v<ValueType, U&>,
482 "Template argument must be constructible from an lvalue" );
483
484 auto p = any_cast<U>( &any );
485
486 if( p )
487 return static_cast<ValueType>( *p );
488
489 throw bad_any_cast{};
490}
491
492template <typename ValueType>
493ValueType any_cast( any&& any )
494{
495 using U = std::remove_cvref_t<ValueType>;
496
497 static_assert( any::is_valid_any_cast<ValueType>(),
498 "Template argument must be a reference or CopyConstructible type" );
499 static_assert( std::is_constructible_v<ValueType, U>,
500 "Template argument must be constructible from an rvalue" );
501
502 auto p = any_cast<U>( &any );
503
504 if( p )
505 return static_cast<ValueType>( std::move( *p ) );
506
507 throw bad_any_cast{};
508}
509
511
513template <typename T>
514void* any_caster( const any* any )
515{
516 // any_cast<T> returns non-null if any->type() == typeid(T) and
517 // typeid(T) ignores cv-qualifiers so remove them:
518 using U = std::remove_cv_t<T>;
519
520 if constexpr( !std::is_same_v<std::decay_t<U>, U> )
521 {
522 // The contained value has a decayed type, so if decay_t<U> is not U,
523 // then it's not possible to have a contained value of type U
524 return nullptr;
525 }
526 else if constexpr( !std::is_copy_constructible_v<U> )
527 {
528 // Only copy constructible types can be used for contained values
529 return nullptr;
530 }
531 else if( any->m_manager == &any::Manager<U>::m_manage_fn
532 || any->type().hash_code() == typeid( T ).hash_code() )
533 {
534 return any::Manager<U>::do_access( any->m_storage );
535 }
536
537 return nullptr;
538}
540
552template <typename ValueType>
553const ValueType* any_cast( const any* any ) noexcept
554{
555 static_assert( !std::is_void_v<ValueType> );
556
557 // As an optimization, don't bother instantiating any_caster for
558 // function types, since std::any can only hold objects
559 if constexpr( std::is_object_v<ValueType> )
560 {
561 if( any )
562 return static_cast<ValueType*>( any_caster<ValueType>( any ) );
563 }
564
565 return nullptr;
566}
567
568template <typename ValueType>
569ValueType* any_cast( any* any ) noexcept
570{
571 static_assert( !std::is_void_v<ValueType> );
572
573 if constexpr( std::is_object_v<ValueType> )
574 if( any )
575 return static_cast<ValueType*>( any_caster<ValueType>( any ) );
576 return nullptr;
577}
579
580template <typename T>
582{
583 // The contained object is in m_storage.m_buffer
584 auto ptr = reinterpret_cast<const T*>( &any->m_storage.m_buffer );
585 switch( which )
586 {
587 case Op_Access: arg->m_obj = const_cast<T*>( ptr ); break;
588 case Op_Get_Type_Info: arg->m_typeinfo = &typeid( T ); break;
589 case Op_Clone:
590 ::new( &arg->m_any->m_storage.m_buffer ) T( *ptr );
591 arg->m_any->m_manager = any->m_manager;
592 break;
593 case Op_Destroy: ptr->~T(); break;
594 case Op_Xfer:
595 ::new( &arg->m_any->m_storage.m_buffer ) T( std::move( *const_cast<T*>( ptr ) ) );
596 ptr->~T();
597 arg->m_any->m_manager = any->m_manager;
598 const_cast<ki::any*>( any )->m_manager = nullptr;
599 break;
600 }
601}
602
603template <typename T>
605{
606 // The contained object is *m_storage.m_ptr
607 auto ptr = static_cast<const T*>( any->m_storage.m_ptr );
608 switch( which )
609 {
610 case Op_Access: arg->m_obj = const_cast<T*>( ptr ); break;
611 case Op_Get_Type_Info: arg->m_typeinfo = &typeid( T ); break;
612 case Op_Clone:
613 arg->m_any->m_storage.m_ptr = new T( *ptr );
614 arg->m_any->m_manager = any->m_manager;
615 break;
616 case Op_Destroy: delete ptr; break;
617 case Op_Xfer:
619 arg->m_any->m_manager = any->m_manager;
620 const_cast<ki::any*>( any )->m_manager = nullptr;
621 break;
622 }
623}
624
625} // namespace ki
626
627#endif // INCLUDE_KI_ANY_H_
A type-safe container of any type.
Definition: ki_any.h:93
std::enable_if< std::is_copy_constructible_v< T > &&std::is_constructible_v< T, Args... >, Res > any_constructible
Definition: ki_any.h:146
typename any_constructible< bool, T, Args... >::type any_constructible_t
Definition: ki_any.h:149
any(const any &other)
Copy constructor, copies the state of other.
Definition: ki_any.h:159
bool has_value() const noexcept
Report whether there is a contained object or not.
Definition: ki_any.h:312
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:210
constexpr any() noexcept
Default constructor, creates an empty object.
Definition: ki_any.h:156
void do_emplace(Args &&... args)
Emplace with an object created from args as the contained object.
Definition: ki_any.h:127
void reset() noexcept
If not empty, destroys the contained object.
Definition: ki_any.h:272
@ Op_Get_Type_Info
Definition: ki_any.h:338
@ Op_Destroy
Definition: ki_any.h:340
@ Op_Clone
Definition: ki_any.h:339
@ Op_Access
Definition: ki_any.h:337
@ Op_Xfer
Definition: ki_any.h:341
any(T &&value)
Construct with a copy of value as the contained object.
Definition: ki_any.h:193
void swap(any &rhs) noexcept
Exchange state with another object.
Definition: ki_any.h:282
typename any_constructible< V &, V, Args... >::type any_emplace_t
Definition: ki_any.h:152
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:264
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:254
std::conditional_t< Use_Internal_Storage< T >::value, Manager_Internal< T >, Manager_External< T > > Manager
Definition: ki_any.h:120
Storage m_storage
Definition: ki_any.h:352
any & operator=(const any &rhs)
Copy the state of another object.
Definition: ki_any.h:220
~any()
Destructor, calls reset().
Definition: ki_any.h:217
any(any &&other) noexcept
Move constructor, transfer the state from other.
Definition: ki_any.h:174
std::enable_if_t<!std::is_same_v< V, any >, V > decay_if_not_any
Definition: ki_any.h:123
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:246
any & operator=(any &&rhs) noexcept
Move assignment operator.
Definition: ki_any.h:227
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:136
any(std::in_place_type_t< T >, Args &&... args)
Construct with an object created from args as the contained object.
Definition: ki_any.h:201
void(* m_manager)(Op, const any *, Arg *)
Definition: ki_any.h:351
const std::type_info & type() const noexcept
The typeid of the contained object, or typeid(void) if empty.
Definition: ki_any.h:316
Exception class thrown by a failed any_cast.
Definition: ki_any.h:81
const char * what() const noexcept override
Definition: ki_any.h:83
static bool empty(const wxTextEntryBase *aCtrl)
Definition: ki_any.h:65
constexpr bool is_in_place_type_v
Definition: ki_any.h:72
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:420
ValueType any_cast(const any &any)
Access the contained object.
Definition: ki_any.h:446
static void do_create(Storage &storage, U &&value)
Definition: ki_any.h:394
static void m_manage_fn(Op which, const any *any, Arg *arg)
Definition: ki_any.h:604
static T * do_access(const Storage &storage)
Definition: ki_any.h:403
static void do_create(Storage &storage, Args &&... args)
Definition: ki_any.h:399
static void do_create(Storage &storage, Args &&... args)
Definition: ki_any.h:373
static T * do_access(const Storage &storage)
Definition: ki_any.h:379
static void m_manage_fn(Op which, const any *any, Arg *arg)
Definition: ki_any.h:581
static void do_create(Storage &storage, U &&value)
Definition: ki_any.h:366
any * m_any
Definition: ki_any.h:348
const std::type_info * m_typeinfo
Definition: ki_any.h:347
void * m_obj
Definition: ki_any.h:346
void * m_ptr
Definition: ki_any.h:103
constexpr Storage()
Definition: ki_any.h:97
Storage & operator=(const Storage &)=delete
Storage(const Storage &)=delete
unsigned char m_buffer[sizeof(m_ptr)]
Definition: ki_any.h:104