added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / execution_context_id.hpp
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2016 Realm Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or utilied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 ////////////////////////////////////////////////////////////////////////////
18
19 #ifndef REALM_OS_EXECUTION_CONTEXT_ID_HPP
20 #define REALM_OS_EXECUTION_CONTEXT_ID_HPP
21
22 #if defined(__GNUC__) && __GNUC__ < 5
23 // GCC 4.9 doesn't have std::alligned_union so polyfill
24 #include "util/aligned_union.hpp"
25 #else
26 #include <type_traits>
27 #endif
28
29 #include <cstring>
30 #include <thread>
31
32 #include <realm/util/assert.hpp>
33 #include <realm/util/optional.hpp>
34
35 namespace realm {
36
37 // An identifier for an execution context other than a thread.
38 // Different execution contexts must have different IDs.
39 using AbstractExecutionContextID = uintptr_t;
40
41 // Identifies an execution context in which a Realm will be used.
42 // Can contain either a std::thread::id or an AbstractExecutionContextID.
43 //
44 // FIXME: This can eventually be:
45 //        using AnyExecutionContextID = std::variant<std::thread::id, AbstractExecutionContextID>;
46 class AnyExecutionContextID {
47     enum class Type {
48         Thread,
49         Abstract,
50     };
51
52 public:
53
54     // Convert from the representation used by Realm::Config, where the absence of an
55     // explicit abstract execution context indicates that the current thread's identifier
56     // should be used.
57     AnyExecutionContextID(util::Optional<AbstractExecutionContextID> maybe_abstract_id)
58     {
59         if (maybe_abstract_id)
60             *this = AnyExecutionContextID(*maybe_abstract_id);
61         else
62             *this = AnyExecutionContextID(std::this_thread::get_id());
63     }
64
65     AnyExecutionContextID(std::thread::id thread_id) : AnyExecutionContextID(Type::Thread, std::move(thread_id)) { }
66     AnyExecutionContextID(AbstractExecutionContextID abstract_id) : AnyExecutionContextID(Type::Abstract, abstract_id) { }
67
68     template <typename StorageType>
69     bool contains() const
70     {
71         return TypeForStorageType<StorageType>::value == m_type;
72     }
73
74     template <typename StorageType>
75     StorageType get() const
76     {
77         REALM_ASSERT_DEBUG(contains<StorageType>());
78         return *reinterpret_cast<const StorageType*>(&m_storage);
79     }
80
81     bool operator==(const AnyExecutionContextID& other) const
82     {
83         return m_type == other.m_type && std::memcmp(&m_storage, &other.m_storage, sizeof(m_storage)) == 0;
84     }
85
86     bool operator!=(const AnyExecutionContextID& other) const
87     {
88         return !(*this == other);
89     }
90
91 private:
92     template <typename T>
93     AnyExecutionContextID(Type type, T value) : m_type(type)
94     {
95         // operator== relies on being able to compare the raw bytes of m_storage,
96         // so zero everything before intializing the portion in use.
97         std::memset(&m_storage, 0, sizeof(m_storage));
98         new (&m_storage) T(std::move(value));
99     }
100
101     template <typename> struct TypeForStorageType;
102
103 #if defined(__GNUC__) && __GNUC__ < 5
104     util::AlignedUnion<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
105 #else
106     std::aligned_union<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
107 #endif
108     Type m_type;
109 };
110
111 template <>
112 struct AnyExecutionContextID::TypeForStorageType<std::thread::id> {
113     constexpr static Type value = Type::Thread;
114 };
115
116 template <>
117 struct AnyExecutionContextID::TypeForStorageType<AbstractExecutionContextID> {
118     constexpr static Type value = Type::Abstract;
119 };
120
121 } // namespace realm
122
123 #endif // REALM_OS_EXECUTION_CONTEXT_ID_HPP