summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Include/WAVM/Inline/Impl/OptionalStorage.h
blob: e7f69025e5daf7e51737837d23bf192b51eed476 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#pragma once

#include <new>
#include <type_traits>
#include "WAVM/Inline/BasicTypes.h"

namespace WAVM {
	// A type that holds an optional instance of another type. The lifetime of the contained
	// instance is defined by the user of this type, and the user is responsible for calling
	// construct and destruct.
	template<typename Contents,
			 bool hasTrivialDestructor = std::is_trivially_destructible<Contents>::value>
	struct OptionalStorage
	{
		template<typename... Args> void construct(Args&&... args)
		{
			new(&contents) Contents(std::forward<Args>(args)...);
		}

		void destruct() { get().~Contents(); }

#if __cplusplus >= 201703L
		Contents& get() { return *std::launder(reinterpret_cast<Contents*>(&contents)); }
		const Contents& get() const
		{
			return *std::launder(reinterpret_cast<const Contents*>(&contents));
		}
#else
		Contents& get() { return *reinterpret_cast<Contents*>(&contents); }
		const Contents& get() const { return *reinterpret_cast<const Contents*>(&contents); }
#endif

	private:
		typename std::aligned_storage<sizeof(Contents), alignof(Contents)>::type contents;
	};

	// Partial specialization for types with trivial destructors.
	template<typename Contents> struct OptionalStorage<Contents, true>
	{
		template<typename... Args> void construct(Args&&... args)
		{
			new(&contents) Contents(std::forward<Args>(args)...);
		}

		void destruct() {}

#if __cplusplus >= 201703L
		Contents& get() { return *std::launder(reinterpret_cast<Contents*>(&contents)); }
		const Contents& get() const
		{
			return *std::launder(reinterpret_cast<const Contents*>(&contents));
		}
#else
		Contents& get() { return *reinterpret_cast<Contents*>(&contents); }
		const Contents& get() const { return *reinterpret_cast<const Contents*>(&contents); }
#endif

	private:
		typename std::aligned_storage<sizeof(Contents), alignof(Contents)>::type contents;
	};

	namespace OptionalStorageAssertions {
		struct NonTrivialType
		{
			NonTrivialType();
		};
		static_assert(std::is_trivial<OptionalStorage<NonTrivialType>>::value,
					  "OptionalStorage<NonTrivialType> is non-trivial");
	};
}