1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2016 Realm Inc.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ////////////////////////////////////////////////////////////////////////////
19 #ifndef REALM_OS_EXECUTION_CONTEXT_ID_HPP
20 #define REALM_OS_EXECUTION_CONTEXT_ID_HPP
22 #if defined(__GNUC__) && __GNUC__ < 5
23 // GCC 4.9 doesn't have std::alligned_union so polyfill
24 #include "util/aligned_union.hpp"
26 #include <type_traits>
32 #include <realm/util/assert.hpp>
33 #include <realm/util/optional.hpp>
37 // An identifier for an execution context other than a thread.
38 // Different execution contexts must have different IDs.
39 using AbstractExecutionContextID = uintptr_t;
41 // Identifies an execution context in which a Realm will be used.
42 // Can contain either a std::thread::id or an AbstractExecutionContextID.
44 // FIXME: This can eventually be:
45 // using AnyExecutionContextID = std::variant<std::thread::id, AbstractExecutionContextID>;
46 class AnyExecutionContextID {
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
57 AnyExecutionContextID(util::Optional<AbstractExecutionContextID> maybe_abstract_id)
59 if (maybe_abstract_id)
60 *this = AnyExecutionContextID(*maybe_abstract_id);
62 *this = AnyExecutionContextID(std::this_thread::get_id());
65 AnyExecutionContextID(std::thread::id thread_id) : AnyExecutionContextID(Type::Thread, std::move(thread_id)) { }
66 AnyExecutionContextID(AbstractExecutionContextID abstract_id) : AnyExecutionContextID(Type::Abstract, abstract_id) { }
68 template <typename StorageType>
71 return TypeForStorageType<StorageType>::value == m_type;
74 template <typename StorageType>
75 StorageType get() const
77 REALM_ASSERT_DEBUG(contains<StorageType>());
78 return *reinterpret_cast<const StorageType*>(&m_storage);
81 bool operator==(const AnyExecutionContextID& other) const
83 return m_type == other.m_type && std::memcmp(&m_storage, &other.m_storage, sizeof(m_storage)) == 0;
86 bool operator!=(const AnyExecutionContextID& other) const
88 return !(*this == other);
93 AnyExecutionContextID(Type type, T value) : m_type(type)
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));
101 template <typename> struct TypeForStorageType;
103 #if defined(__GNUC__) && __GNUC__ < 5
104 util::AlignedUnion<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
106 std::aligned_union<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
112 struct AnyExecutionContextID::TypeForStorageType<std::thread::id> {
113 constexpr static Type value = Type::Thread;
117 struct AnyExecutionContextID::TypeForStorageType<AbstractExecutionContextID> {
118 constexpr static Type value = Type::Abstract;
123 #endif // REALM_OS_EXECUTION_CONTEXT_ID_HPP