1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2018 Adam C. Emerson <aemerson@redhat.com>
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software
11   	 * Foundation.  See file COPYING.
12   	 *
13   	 */
14   	
15   	#ifndef INCLUDE_STATIC_ANY
16   	#define INCLUDE_STATIC_ANY
17   	
18   	#include <any>
19   	#include <cstddef>
20   	#include <initializer_list>
21   	#include <memory>
22   	#include <typeinfo>
23   	#include <type_traits>
24   	
25   	#include <boost/smart_ptr/shared_ptr.hpp>
26   	#include <boost/smart_ptr/make_shared.hpp>
27   	
28   	namespace ceph {
29   	
30   	namespace _any {
31   	
32   	// Shared Functionality
33   	// --------------------
34   	//
35   	// Common implementation details. Most functionality is here. We
36   	// assume that destructors do not throw. Some of them might and
37   	// they'll invoke terminate and that's fine.
38   	//
39   	// We are using the Curiously Recurring Template Pattern! We require
40   	// that all classes inheriting from us provide:
41   	//
42   	//   - `static constexpr size_t capacity`: Maximum capacity. No object
43   	//                                         larger than this may be
44   	//                                         stored. `dynamic` for dynamic.
45   	//   - `void* ptr() const noexcept`: returns a pointer to storage.
46   	//                                   (`alloc_storage` must have been called.
47   	//                                   `free_storage` must not have been called
48   	//                                   since.)
49   	//   - `void* alloc_storage(const std::size_t)`: allocate storage
50   	//   - `void free_storage() noexcept`: free storage. Must be idempotent.
51   	//
52   	// We provide most of the public interface, as well as the operator function,
53   	// cast_helper, and the type() call.
54   	
55   	// Set `capacity` to this value to indicate that there is no fixed
56   	// capacity.
57   	//
58   	inline constexpr std::size_t dynamic = ~0;
59   	
60   	// Driver Function
61   	// ---------------
62   	//
63   	// The usual type-erasure control function trick. This one is simpler
64   	// than usual since we punt on moving and copying. We could dispense
65   	// with this and just store a deleter and a pointer to a typeinfo, but
66   	// that would be twice the space.
67   	//
68   	// Moved out here so the type of `func_t` isn't dependent on the
69   	// enclosing class.
70   	//
71   	enum class op { type, destroy };
72   	template<typename T>
73   	inline void op_func(const op o, void* p) noexcept {
74   	  static const std::type_info& type = typeid(T);
75   	  switch (o) {
76   	  case op::type:
77   	    *(reinterpret_cast<const std::type_info**>(p)) = &type;
78   	    break;
79   	  case op::destroy:
80   	    reinterpret_cast<T*>(p)->~T();
81   	    break;
82   	  }
83   	}
84   	using func_t = void (*)(const op, void* p) noexcept;
85   	
86   	// The base class 
87   	// --------------
88   	//
89   	// The `storage_t` parameter gives the type of the value that manages
90   	// storage and allocation. We use it to create a protected data member
91   	// (named `storage`). This allows us to sidestep the problem in
92   	// initialization order where, where exposed constructors were using
93   	// trying to allocate or free storage *before* the data members of the
94   	// derived class were initialized.
95   	//
96   	// Making storage_t a member type of the derived class won't work, due
97   	// to C++'s rules for nested types being *horrible*. Just downright
98   	// *horrible*.
99   	//
100  	template<typename D, typename storage_t>
101  	class base {
102  	  // Make definitions from our superclass visible
103  	  // --------------------------------------------
104  	  //
105  	  // And check that they fit the requirements. At least those that are
106  	  // statically checkable.
107  	  //
108  	  static constexpr std::size_t capacity = D::capacity;
109  	
110  	  void* ptr() const noexcept {
111  	    static_assert(
112  	      noexcept(static_cast<const D*>(this)->ptr()) &&
113  	      std::is_same_v<decltype(static_cast<const D*>(this)->ptr()), void*>,
114  	      "‘void* ptr() const noexcept’ missing from superclass");
115  	    return static_cast<const D*>(this)->ptr();
116  	  }
117  	
118  	  void* alloc_storage(const std::size_t z) {
119  	    static_assert(
120  	      std::is_same_v<decltype(static_cast<D*>(this)->alloc_storage(z)), void*>,
121  	      "‘void* alloc_storage(const size_t)’ missing from superclass.");
122  	    return static_cast<D*>(this)->alloc_storage(z);
123  	  }
124  	
125  	  void free_storage() noexcept {
126  	    static_assert(
127  	      noexcept(static_cast<D*>(this)->free_storage()) &&
128  	      std::is_void_v<decltype(static_cast<D*>(this)->free_storage())>,
129  	      "‘void free_storage() noexcept’ missing from superclass.");
130  	    static_cast<D*>(this)->free_storage();
131  	  }
132  	
133  	
134  	  // Pile O' Templates
135  	  // -----------------
136  	  //
137  	  // These are just verbose and better typed once than twice. They're
138  	  // used for SFINAE and declaring noexcept.
139  	  //
140  	  template<class T>
141  	  struct is_in_place_type_helper : std::false_type {};
142  	  template<class T>
143  	  struct is_in_place_type_helper<std::in_place_type_t<T>> : std::true_type {};
144  	
145  	  template<class T>
146  	  static constexpr bool is_in_place_type_v =
147  	    is_in_place_type_helper<std::decay_t<T>>::value;
148  	
149  	  // SFINAE condition for value initialized
150  	  // constructors/assigners. This is analogous to the standard's
151  	  // requirement that this overload only participate in overload
152  	  // resolution if std::decay_t<T> is not the same type as the
153  	  // any-type, nor a specialization of std::in_place_type_t
154  	  //
155  	  template<typename T>
156  	  using value_condition_t = std::enable_if_t<
157  	    !std::is_same_v<std::decay_t<T>, D> &&
158  	    !is_in_place_type_v<std::decay_t<T>>>;
159  	
160  	  // This `noexcept` condition for value construction lets
161  	  // `immobile_any`'s value constructor/assigner be noexcept, so long
162  	  // as the type's copy or move constructor cooperates.
163  	  //
164  	  template<typename T>
165  	  static constexpr bool value_noexcept_v =
166  	    std::is_nothrow_constructible_v<std::decay_t<T>, T> && capacity != dynamic;
167  	
168  	  // SFINAE condition for in-place constructors/assigners
169  	  //
170  	  template<typename T, typename... Args>
171  	  using in_place_condition_t = std::enable_if_t<std::is_constructible_v<
172  							  std::decay_t<T>, Args...>>;
173  	
174  	  // Analogous to the above. Give noexcept to immobile_any::emplace
175  	  // when possible.
176  	  //
177  	  template<typename T, typename... Args>
178  	  static constexpr bool in_place_noexcept_v =
179  	    std::is_nothrow_constructible_v<std::decay_t<T>, Args...> &&
180  	    capacity != dynamic;
181  	
182  	private:
183  	
184  	  // Functionality!
185  	  // --------------
186  	
187  	  // The driver function for the currently stored object. Whether this
188  	  // is null is the canonical way to know whether an instance has a
189  	  // value.
190  	  //
191  	  func_t func = nullptr;
192  	
193  	  // Construct an object within ourselves. As you can see we give the
194  	  // weak exception safety guarantee.
195  	  //
196  	  template<typename T, typename ...Args>
197  	  std::decay_t<T>& construct(Args&& ...args) {
198  	    using Td = std::decay_t<T>;
199  	    static_assert(capacity == dynamic || sizeof(Td) <= capacity,
200  			  "Supplied type is too large for this specialization.");
201  	    try {
202  	      func = &op_func<Td>;
203  	      return *new (reinterpret_cast<Td*>(alloc_storage(sizeof(Td))))
204  		Td(std::forward<Args>(args)...);
205  	    } catch (...) {
206  	      reset();
207  	      throw;
208  	    }
209  	  }
210  	
211  	protected:
212  	
213  	  // We hold the storage, even if the superclass class manipulates it,
214  	  // so that its default initialization comes soon enough for us to
215  	  // use it in our constructors.
216  	  //
217  	  storage_t storage;
218  	
219  	public:
220  	
221  	  base() noexcept = default;
222  	  ~base() noexcept {
223  	    reset();
224  	  }
225  	
226  	protected:
227  	  // Since some of our derived classes /can/ be copied or moved.
228  	  //
229  	  base(const base& rhs) noexcept : func(rhs.func) {
230  	    if constexpr (std::is_copy_assignable_v<storage_t>) {
231  	      storage = rhs.storage;
232  	    }
233  	  }
234  	  base& operator =(const base& rhs) noexcept {
235  	    reset();
236  	    func = rhs.func;
237  	    if constexpr (std::is_copy_assignable_v<storage_t>) {
238  	      storage = rhs.storage;
239  	    }
240  	    return *this;
241  	  }
242  	
243  	  base(base&& rhs) noexcept : func(std::move(rhs.func)) {
244  	    if constexpr (std::is_move_assignable_v<storage_t>) {
245  	      storage = std::move(rhs.storage);
246  	    }
247  	    rhs.func = nullptr;
248  	  }
249  	  base& operator =(base&& rhs) noexcept {
250  	    reset();
251  	    func = rhs.func;
252  	    if constexpr (std::is_move_assignable_v<storage_t>) {
253  	      storage = std::move(rhs.storage);
254  	    }
255  	    rhs.func = nullptr;
256  	    return *this;
257  	  }
258  	
259  	public:
260  	
261  	  // Value construct/assign
262  	  // ----------------------
263  	  //
264  	  template<typename T,
265  		   typename = value_condition_t<T>>
266  	  base(T&& t) noexcept(value_noexcept_v<T>) {
267  	    construct<T>(std::forward<T>(t));
268  	  }
269  	
270  	  // On exception, *this is set to empty.
271  	  //
272  	  template<typename T,
273  	           typename = value_condition_t<T>>
274  	  base& operator =(T&& t) noexcept(value_noexcept_v<T>) {
275  	    reset();
276  	    construct<T>(std::forward<T>(t));
277  	    return *this;
278  	  }
279  	
280  	  // In-place construct/assign
281  	  // -------------------------
282  	  //
283  	  // I really hate the way the C++ standard library treats references
284  	  // as if they were stepchildren in a Charles Dickens novel. I am
285  	  // quite upset that std::optional lacks a specialization for
286  	  // references. There's no legitimate reason for it. The whole
287  	  // 're-seat or refuse' debate is simply a canard. The optional is
288  	  // effectively a container, so of course it can be emptied or
289  	  // reassigned. No, pointers are not an acceptable substitute. A
290  	  // pointer gives an address in memory which may be null and which
291  	  // may represent an object or may a location in which an object is
292  	  // to be created. An optional reference, on the other hand, is a
293  	  // reference to an initialized, live object or /empty/. This is an
294  	  // obvious difference that should be communicable to any programmer
295  	  // reading the code through the type system.
296  	  //
297  	  // `std::any`, even in the case of in-place construction,
298  	  // only stores the decayed type. I suspect this was to get around
299  	  // the question of whether, for a std::any holding a T&,
300  	  // std::any_cast<T> should return a copy or throw
301  	  // std::bad_any_cast.
302  	  //
303  	  // I think the appropriate response in that case would be to make a
304  	  // copy if the type supports it and fail otherwise. Once a concrete
305  	  // type is known the problem solves itself.
306  	  //
307  	  // If one were inclined, one could easily load the driver function
308  	  // with a heavy subset of the type traits (those that depend only on
309  	  // the type in question) and simply /ask/ whether it's a reference.
310  	  //
311  	  // At the moment, I'm maintaining compatibility with the standard
312  	  // library except for copy/move semantics.
313  	  //
314  	  template<typename T,
315  	           typename... Args,
316  	           typename = in_place_condition_t<T, Args...>>
317  	  base(std::in_place_type_t<T>,
318  	       Args&& ...args) noexcept(in_place_noexcept_v<T, Args...>) {
319  	    construct<T>(std::forward<Args>(args)...);
320  	  }
321  	
322  	  // On exception, *this is set to empty.
323  	  //
324  	  template<typename T,
325  	           typename... Args,
326  	           typename = in_place_condition_t<T>>
327  	  std::decay_t<T>& emplace(Args&& ...args) noexcept(in_place_noexcept_v<
328  							    T, Args...>) {
329  	    reset();
330  	    return construct<T>(std::forward<Args>(args)...);
331  	  }
332  	
333  	  template<typename T,
334  	           typename U,
335  	           typename... Args,
336  	           typename = in_place_condition_t<T, std::initializer_list<U>,
337  						   Args...>>
338  	  base(std::in_place_type_t<T>,
339  	       std::initializer_list<U> i,
340  	       Args&& ...args) noexcept(in_place_noexcept_v<T, std::initializer_list<U>,
341  					Args...>) {
342  	    construct<T>(i, std::forward<Args>(args)...);
343  	  }
344  	
345  	  // On exception, *this is set to empty.
346  	  //
347  	  template<typename T,
348  	           typename U,
349  	           typename... Args,
350  	           typename = in_place_condition_t<T, std::initializer_list<U>,
351  						   Args...>>
352  	  std::decay_t<T>& emplace(std::initializer_list<U> i,
353  	                           Args&& ...args) noexcept(in_place_noexcept_v<T,
354  							    std::initializer_list<U>,
355  							    Args...>) {
356  	    reset();
357  	    return construct<T>(i,std::forward<Args>(args)...);
358  	  }
359  	
360  	  // Empty ourselves, using the subclass to free any storage.
361  	  //
362  	  void reset() noexcept {
363  	    if (has_value()) {
364  	      func(op::destroy, ptr());
365  	      func = nullptr;
366  	    }
367  	    free_storage();
368  	  }
369  	
370  	  template<typename U = storage_t,
371  		   typename = std::enable_if<std::is_swappable_v<storage_t>>>
372  	  void swap(base& rhs) {
373  	    using std::swap;
374  	    swap(func, rhs.func);
375  	    swap(storage, rhs.storage);
376  	  }
377  	
378  	  // All other functions should use this function to test emptiness
379  	  // rather than examining `func` directly.
380  	  //
381  	  bool has_value() const noexcept {
382  	    return !!func;
383  	  }
384  	
385  	  // Returns the type of the value stored, if any.
386  	  //
387  	  const std::type_info& type() const noexcept {
388  	    if (has_value()) {
389  	      const std::type_info* t;
390  	      func(op::type, reinterpret_cast<void*>(&t));
391  	      return *t;
392  	    } else {
393  	      return typeid(void);
394  	    }
395  	  }
396  	
397  	  template<typename T, typename U, typename V>
398  	  friend inline void* cast_helper(const base<U, V>& b) noexcept;
399  	};
400  	
401  	// Function used by all `any_cast` functions
402  	//
403  	// Returns a void* to the contents if they exist and match the
404  	// requested type, otherwise `nullptr`.
405  	//
406  	template<typename T, typename U, typename V>
407  	inline void* cast_helper(const base<U, V>& b) noexcept {
408  	  if (b.func && ((&op_func<T> == b.func) ||
409  			 (b.type() == typeid(T)))) {
410  	    return b.ptr();
411  	  } else {
412  	    return nullptr;
413  	  }
414  	}
415  	}
416  	
417  	// `any_cast`
418  	// ==========
419  	//
420  	// Just the usual gamut of `any_cast` overloads. These get a bit
421  	// repetitive and it would be nice to think of a way to collapse them
422  	// down a bit.
423  	//
424  	
425  	// The pointer pair!
426  	//
427  	template<typename T, typename U, typename V>
428  	inline T* any_cast(_any::base<U, V>* a) noexcept {
429  	  if (a) {
430  	    return static_cast<T*>(_any::cast_helper<std::decay_t<T>>(*a));
431  	  }
432  	  return nullptr;
433  	}
434  	
435  	template<typename T, typename U, typename V>
436  	inline const T* any_cast(const _any::base<U, V>* a) noexcept {
437  	  if (a) {
438  	    return static_cast<T*>(_any::cast_helper<std::decay_t<T>>(*a));
439  	  }
440  	  return nullptr;
441  	}
442  	
443  	// While we disallow copying the immobile any itself, we can allow
444  	// anything with an extracted value that the type supports.
445  	//
446  	template<typename T, typename U, typename V>
447  	inline T any_cast(_any::base<U, V>& a) {
448  	  static_assert(std::is_reference_v<T> ||
449  	                std::is_copy_constructible_v<T>,
450  	                "The supplied type must be either a reference or "
451  	                "copy constructible.");
452  	  auto p = any_cast<std::decay_t<T>>(&a);
453  	  if (p) {
454  	    return static_cast<T>(*p);
455  	  }
456  	  throw std::bad_any_cast();
457  	}
458  	
459  	template<typename T, typename U, typename V>
460  	inline T any_cast(const _any::base<U, V>& a) {
461  	  static_assert(std::is_reference_v<T> ||
462  	                std::is_copy_constructible_v<T>,
463  	                "The supplied type must be either a reference or "
464  	                "copy constructible.");
465  	  auto p = any_cast<std::decay_t<T>>(&a);
466  	  if (p) {
467  	    return static_cast<T>(*p);
468  	  }
469  	  throw std::bad_any_cast();
470  	}
471  	
472  	template<typename T, typename U, typename V>
473  	inline std::enable_if_t<(std::is_move_constructible_v<T> ||
474  				 std::is_copy_constructible_v<T>) &&
475  				!std::is_rvalue_reference_v<T>, T>
476  	any_cast(_any::base<U, V>&& a) {
477  	  auto p = any_cast<std::decay_t<T>>(&a);
478  	  if (p) {
479  	    return std::move((*p));
480  	  }
481  	  throw std::bad_any_cast();
482  	}
483  	
484  	template<typename T, typename U, typename V>
485  	inline std::enable_if_t<std::is_rvalue_reference_v<T>, T>
486  	any_cast(_any::base<U, V>&& a) {
487  	  auto p = any_cast<std::decay_t<T>>(&a);
488  	  if (p) {
489  	    return static_cast<T>(*p);
490  	  }
491  	  throw std::bad_any_cast();
492  	}
493  	
494  	// `immobile_any`
495  	// ==============
496  	//
497  	// Sometimes, uncopyable objects exist and I want to do things with
498  	// them. The C++ standard library is really quite keen on insisting
499  	// things be copyable before it deigns to work. I find this annoying.
500  	//
501  	// Also, the allocator, while useful, is really not considerate of
502  	// other people's time. Every time we go to visit it, it takes us
503  	// quite an awfully long time to get away again. As such, I've been
504  	// trying to avoid its company whenever it is convenient and seemly.
505  	//
506  	// We accept any type that will fit in the declared capacity. You may
507  	// store types with throwing destructors, but terminate will be
508  	// invoked when they throw.
509  	//
510  	template<std::size_t S>
511  	class immobile_any : public _any::base<immobile_any<S>,
512  					       std::aligned_storage_t<S>> {
513  	  using base = _any::base<immobile_any<S>, std::aligned_storage_t<S>>;
514  	  friend base;
515  	
516  	  using _any::base<immobile_any<S>, std::aligned_storage_t<S>>::storage;
517  	
518  	  // Superclass requirements!
519  	  // ------------------------
520  	  //
521  	  // Simple as anything. We have a buffer of fixed size and return the
522  	  // pointer to it when asked.
523  	  //
524  	  static constexpr std::size_t capacity = S;
525  	  void* ptr() const noexcept {
526  	    return const_cast<void*>(static_cast<const void*>(&storage));
527  	  }
528  	  void* alloc_storage(std::size_t) noexcept {
529  	    return ptr();
530  	  }
531  	  void free_storage() noexcept {}
532  	
533  	  static_assert(capacity != _any::dynamic,
534  			"That is not a valid size for an immobile_any.");
535  	
536  	public:
537  	
538  	  immobile_any() noexcept = default;
539  	
540  	  immobile_any(const immobile_any&) = delete;
541  	  immobile_any& operator =(const immobile_any&) = delete;
542  	  immobile_any(immobile_any&&) = delete;
543  	  immobile_any& operator =(immobile_any&&) = delete;
544  	
(1) Event no_matching_constructor: no instance of constructor "ceph::_any::base<D, storage_t>::base [with D=ceph::immobile_any<576UL>, storage_t=std::aligned_storage_t<576UL, 16UL>]" matches the argument list
(2) Event caretline: ^
(3) Event argument_list_types_add_on: argument types are: (std::in_place_type_t<<unnamed>::MempoolObs>, CephContext *)
Also see events: [compiler_generated_function_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context]
545  	  using base::base;
546  	  using base::operator =;
547  	
548  	  void swap(immobile_any&) = delete;
549  	};
550  	
551  	template<typename T, std::size_t S, typename... Args>
552  	inline immobile_any<S> make_immobile_any(Args&& ...args) {
553  	  return immobile_any<S>(std::in_place_type<T>, std::forward<Args>(args)...);
554  	}
555  	
556  	template<typename T, std::size_t S, typename U, typename... Args>
557  	inline immobile_any<S> make_immobile_any(std::initializer_list<U> i, Args&& ...args) {
558  	  return immobile_any<S>(std::in_place_type<T>, i, std::forward<Args>(args)...);
559  	}
560  	
561  	// `unique_any`
562  	// ============
563  	//
564  	// Oh dear. Now we're getting back into allocation. You don't think
565  	// the allocator noticed all those mean things we said about it, do
566  	// you?
567  	//
568  	// Well. Okay, allocator. Sometimes when it's the middle of the night
569  	// and you're writing template code you say things you don't exactly
570  	// mean. If it weren't for you, we wouldn't have any memory to run all
571  	// our programs in at all. Really, I'm just being considerate of
572  	// *your* needs, trying to avoid having to run to you every time we
573  	// instantiate a type, making a few that can be self-sufficient…uh…
574  	//
575  	// **Anyway**, this is movable but not copyable, as you should expect
576  	// from anything with ‘unique’ in the name.
577  	//
578  	class unique_any : public _any::base<unique_any, std::unique_ptr<std::byte[]>> {
579  	  using base = _any::base<unique_any, std::unique_ptr<std::byte[]>>;
580  	  friend base;
581  	
582  	  using base::storage;
583  	
584  	  // Superclass requirements
585  	  // -----------------------
586  	  //
587  	  // Our storage is a single chunk of RAM owned by a
588  	  // `std::unique_ptr`.
589  	  //
590  	  static constexpr std::size_t capacity = _any::dynamic;
591  	  void* ptr() const noexcept {
592  	    return static_cast<void*>(storage.get());
593  	    return nullptr;
594  	  }
595  	
596  	  void* alloc_storage(const std::size_t z) {
597  	    storage.reset(new std::byte[z]);
598  	    return ptr();
599  	  }
600  	
601  	  void free_storage() noexcept {
602  	    storage.reset();
603  	  }
604  	
605  	public:
606  	
607  	  unique_any() noexcept = default;
608  	  ~unique_any() noexcept = default;
609  	
610  	  unique_any(const unique_any&) = delete;
611  	  unique_any& operator =(const unique_any&) = delete;
612  	
613  	  // We can rely on the behavior of `unique_ptr` and the base class to
614  	  // give us a default move constructor that does the right thing.
615  	  //
616  	  unique_any(unique_any&& rhs) noexcept = default;
617  	  unique_any& operator =(unique_any&& rhs) = default;
618  	
619  	  using base::base;
620  	  using base::operator =;
621  	};
622  	
623  	inline void swap(unique_any& lhs, unique_any& rhs) noexcept {
624  	  lhs.swap(rhs);
625  	}
626  	
627  	template<typename T, typename... Args>
628  	inline unique_any make_unique_any(Args&& ...args) {
629  	  return unique_any(std::in_place_type<T>, std::forward<Args>(args)...);
630  	}
631  	
632  	template<typename T, typename U, typename... Args>
633  	inline unique_any make_unique_any(std::initializer_list<U> i, Args&& ...args) {
634  	  return unique_any(std::in_place_type<T>, i, std::forward<Args>(args)...);
635  	}
636  	
637  	// `shared_any`
638  	// ============
639  	//
640  	// Once more with feeling!
641  	//
642  	// This is both copyable *and* movable. In case you need that sort of
643  	// thing. It seemed a reasonable completion.
644  	//
645  	class shared_any : public _any::base<shared_any, boost::shared_ptr<std::byte[]>> {
646  	  using base = _any::base<shared_any, boost::shared_ptr<std::byte[]>>;
647  	  friend base;
648  	
649  	  using base::storage;
650  	
651  	  // Superclass requirements
652  	  // -----------------------
653  	  //
654  	  // Our storage is a single chunk of RAM allocated from the
655  	  // heap. This time it's owned by a `boost::shared_ptr` so we can use
656  	  // `boost::make_shared_noinit`. (This lets us get the optimization
657  	  // that allocates array and control block in one without wasting
658  	  // time on `memset`.)
659  	  //
660  	  static constexpr std::size_t capacity = _any::dynamic;
661  	  void* ptr() const noexcept {
662  	    return static_cast<void*>(storage.get());
663  	  }
664  	
665  	  void* alloc_storage(std::size_t n) {
666  	    storage = boost::make_shared_noinit<std::byte[]>(n);
667  	    return ptr();
668  	  }
669  	
670  	  void free_storage() noexcept {
671  	    storage.reset();
672  	  }
673  	
674  	public:
675  	
676  	  shared_any() noexcept = default;
677  	  ~shared_any() noexcept = default;
678  	
679  	  shared_any(const shared_any& rhs) noexcept = default;
680  	  shared_any& operator =(const shared_any&) noexcept = default;
681  	
682  	  shared_any(shared_any&& rhs) noexcept = default;
683  	  shared_any& operator =(shared_any&& rhs) noexcept = default;
684  	
685  	  using base::base;
686  	  using base::operator =;
687  	};
688  	
689  	inline void swap(shared_any& lhs, shared_any& rhs) noexcept {
690  	  lhs.swap(rhs);
691  	}
692  	
693  	template<typename T, typename... Args>
694  	inline shared_any make_shared_any(Args&& ...args) {
695  	  return shared_any(std::in_place_type<T>, std::forward<Args>(args)...);
696  	}
697  	
698  	template<typename T, typename U, typename... Args>
699  	inline shared_any make_shared_any(std::initializer_list<U> i, Args&& ...args) {
700  	  return shared_any(std::in_place_type<T>, i, std::forward<Args>(args)...);
701  	}
702  	}
703  	
704  	#endif // INCLUDE_STATIC_ANY
705