Files
POCloud-iOS/Pods/Realm/include/execution_context_id.hpp
Patrick McDonagh 909925a334 Initial Commit
2018-05-25 12:56:07 -05:00

124 lines
3.9 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or utilied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#ifndef REALM_OS_EXECUTION_CONTEXT_ID_HPP
#define REALM_OS_EXECUTION_CONTEXT_ID_HPP
#if defined(__GNUC__) && __GNUC__ < 5
// GCC 4.9 doesn't have std::alligned_union so polyfill
#include "util/aligned_union.hpp"
#else
#include <type_traits>
#endif
#include <cstring>
#include <thread>
#include <realm/util/assert.hpp>
#include <realm/util/optional.hpp>
namespace realm {
// An identifier for an execution context other than a thread.
// Different execution contexts must have different IDs.
using AbstractExecutionContextID = uintptr_t;
// Identifies an execution context in which a Realm will be used.
// Can contain either a std::thread::id or an AbstractExecutionContextID.
//
// FIXME: This can eventually be:
// using AnyExecutionContextID = std::variant<std::thread::id, AbstractExecutionContextID>;
class AnyExecutionContextID {
enum class Type {
Thread,
Abstract,
};
public:
// Convert from the representation used by Realm::Config, where the absence of an
// explicit abstract execution context indicates that the current thread's identifier
// should be used.
AnyExecutionContextID(util::Optional<AbstractExecutionContextID> maybe_abstract_id)
{
if (maybe_abstract_id)
*this = AnyExecutionContextID(*maybe_abstract_id);
else
*this = AnyExecutionContextID(std::this_thread::get_id());
}
AnyExecutionContextID(std::thread::id thread_id) : AnyExecutionContextID(Type::Thread, std::move(thread_id)) { }
AnyExecutionContextID(AbstractExecutionContextID abstract_id) : AnyExecutionContextID(Type::Abstract, abstract_id) { }
template <typename StorageType>
bool contains() const
{
return TypeForStorageType<StorageType>::value == m_type;
}
template <typename StorageType>
StorageType get() const
{
REALM_ASSERT_DEBUG(contains<StorageType>());
return *reinterpret_cast<const StorageType*>(&m_storage);
}
bool operator==(const AnyExecutionContextID& other) const
{
return m_type == other.m_type && std::memcmp(&m_storage, &other.m_storage, sizeof(m_storage)) == 0;
}
bool operator!=(const AnyExecutionContextID& other) const
{
return !(*this == other);
}
private:
template <typename T>
AnyExecutionContextID(Type type, T value) : m_type(type)
{
// operator== relies on being able to compare the raw bytes of m_storage,
// so zero everything before intializing the portion in use.
std::memset(&m_storage, 0, sizeof(m_storage));
new (&m_storage) T(std::move(value));
}
template <typename> struct TypeForStorageType;
#if defined(__GNUC__) && __GNUC__ < 5
util::AlignedUnion<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
#else
std::aligned_union<1, std::thread::id, AbstractExecutionContextID>::type m_storage;
#endif
Type m_type;
};
template <>
struct AnyExecutionContextID::TypeForStorageType<std::thread::id> {
constexpr static Type value = Type::Thread;
};
template <>
struct AnyExecutionContextID::TypeForStorageType<AbstractExecutionContextID> {
constexpr static Type value = Type::Abstract;
};
} // namespace realm
#endif // REALM_OS_EXECUTION_CONTEXT_ID_HPP