blob: 7fc9933dc5206f4f6d7296cb5a8d438e7bbc00e5 [file] [edit]
/*
* Copyright (C) 2017-2023 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <wtf/Compiler.h>
#include <wtf/HashTraits.h>
#include <wtf/UUID.h>
#include <wtf/text/WTFString.h>
namespace WTF {
class PrintStream;
template<typename RawValue>
struct ObjectIdentifierThreadSafeAccessTraits {
};
template<>
struct ObjectIdentifierThreadSafeAccessTraits<uint64_t> {
WTF_EXPORT_PRIVATE static uint64_t generateIdentifierInternal();
};
template<>
struct ObjectIdentifierThreadSafeAccessTraits<UUID> {
WTF_EXPORT_PRIVATE static UUID generateIdentifierInternal();
};
template<typename RawValue>
struct ObjectIdentifierMainThreadAccessTraits {
};
template<>
struct ObjectIdentifierMainThreadAccessTraits<uint64_t> {
WTF_EXPORT_PRIVATE static uint64_t NODELETE generateIdentifierInternal();
};
template<>
struct ObjectIdentifierMainThreadAccessTraits<UUID> {
WTF_EXPORT_PRIVATE static UUID generateIdentifierInternal();
};
// Extracted from ObjectIdentifierGeneric to avoid binary bloat.
template<typename RawValue>
class ObjectIdentifierGenericBase {
};
template<>
class ObjectIdentifierGenericBase<uint64_t> {
public:
using RawValue = uint64_t;
bool isHashTableDeletedValue() const { return m_identifier == hashTableDeletedValue(); }
static constexpr bool safeToCompareToHashTableEmptyOrDeletedValue = true;
RawValue toUInt64() const { return toRawValue(); } // Use `toRawValue` instead.
RawValue toRawValue() const { return m_identifier; }
String loggingString() const
{
return String::number(m_identifier);
}
static constexpr bool isValidIdentifier(RawValue identifier) { return identifier && identifier != hashTableDeletedValue(); }
protected:
explicit constexpr ObjectIdentifierGenericBase(RawValue identifier)
: m_identifier(identifier)
{
}
ObjectIdentifierGenericBase() = default;
~ObjectIdentifierGenericBase() = default;
ObjectIdentifierGenericBase(HashTableDeletedValueType) : m_identifier(hashTableDeletedValue()) { }
static constexpr RawValue hashTableDeletedValue() { return std::numeric_limits<RawValue>::max(); }
private:
RawValue m_identifier { 0 };
};
template<>
class ObjectIdentifierGenericBase<UUID> {
public:
using RawValue = UUID;
bool isHashTableDeletedValue() const { return m_identifier == hashTableDeletedValue(); }
static constexpr bool safeToCompareToHashTableEmptyOrDeletedValue = true;
RawValue toRawValue() const { return m_identifier; }
String loggingString() const
{
return m_identifier.toString();
}
static constexpr bool isValidIdentifier(RawValue identifier) { return identifier && !identifier.isHashTableDeletedValue(); }
protected:
explicit constexpr ObjectIdentifierGenericBase(RawValue identifier)
: m_identifier(identifier)
{
}
ObjectIdentifierGenericBase() = default;
~ObjectIdentifierGenericBase() = default;
ObjectIdentifierGenericBase(HashTableDeletedValueType) : m_identifier(hashTableDeletedValue()) { }
static RawValue hashTableDeletedValue() { return UUID { HashTableDeletedValue }; }
private:
RawValue m_identifier { MarkableTraits<UUID>::emptyValue() };
};
template<typename T, typename ThreadSafety, typename RawValue>
class ObjectIdentifierGeneric : public ObjectIdentifierGenericBase<RawValue> {
public:
static ObjectIdentifierGeneric generate()
{
RELEASE_ASSERT(!m_generationProtected);
return ObjectIdentifierGeneric { ThreadSafety::generateIdentifierInternal(), AssumeValidIdValue };
}
static void enableGenerationProtection()
{
m_generationProtected = true;
}
explicit constexpr ObjectIdentifierGeneric(RawValue identifier)
: ObjectIdentifierGenericBase<RawValue>(identifier)
{
RELEASE_ASSERT(ObjectIdentifierGenericBase<RawValue>::isValidIdentifier(identifier));
}
bool isHashTableEmptyValue() const { return !ObjectIdentifierGenericBase<RawValue>::toRawValue(); }
// Do not call this constructor explicitly, it should only be used by the Hashtable implementation.
ObjectIdentifierGeneric(HashTableDeletedValueType) : ObjectIdentifierGenericBase<RawValue>(HashTableDeletedValue) { }
private:
friend struct HashTraits<ObjectIdentifierGeneric>;
friend struct MarkableTraits<ObjectIdentifierGeneric>;
template<typename U, typename V> friend struct ObjectIdentifierGenericHash;
enum AssumeValidId { AssumeValidIdValue };
explicit constexpr ObjectIdentifierGeneric(RawValue identifier, AssumeValidId)
: ObjectIdentifierGenericBase<RawValue>(identifier)
{
ASSERT(!!identifier);
}
enum InvalidId { InvalidIdValue };
ObjectIdentifierGeneric(InvalidId)
{
}
inline static bool m_generationProtected { false };
};
template<typename T, typename ThreadSafety, typename RawValue>
struct MarkableTraits<ObjectIdentifierGeneric<T, ThreadSafety, RawValue>> {
static bool isEmptyValue(ObjectIdentifierGeneric<T, ThreadSafety, RawValue> identifier) { return !identifier.toRawValue(); }
static constexpr ObjectIdentifierGeneric<T, ThreadSafety, RawValue> emptyValue() { return ObjectIdentifierGeneric<T, ThreadSafety, RawValue>::InvalidIdValue; }
};
template<typename T, typename RawValue> using ObjectIdentifier = ObjectIdentifierGeneric<T, ObjectIdentifierMainThreadAccessTraits<RawValue>, RawValue>;
template<typename T, typename RawValue> using AtomicObjectIdentifier = ObjectIdentifierGeneric<T, ObjectIdentifierThreadSafeAccessTraits<RawValue>, RawValue>;
template<typename T> using UUIDObjectIdentifier = AtomicObjectIdentifier<T, UUID>;
inline void add(Hasher& hasher, const ObjectIdentifierGenericBase<uint64_t>& identifier)
{
add(hasher, identifier.toRawValue());
}
inline void add(Hasher& hasher, const ObjectIdentifierGenericBase<UUID>& identifier)
{
add(hasher, identifier.toRawValue());
}
template<typename T, typename U, typename V> struct HashTraits<ObjectIdentifierGeneric<T, U, V>> : SimpleClassHashTraits<ObjectIdentifierGeneric<T, U, V>> {
using ValueType = ObjectIdentifierGeneric<T, U, V>;
using PeekType = std::optional<ValueType>;
using TakeType = std::optional<ValueType>;
static ValueType emptyValue() { return ValueType { ValueType::InvalidIdValue }; }
static bool isEmptyValue(ValueType value) { return value.isHashTableEmptyValue(); }
static PeekType peek(ValueType identifier)
{
if (isEmptyValue(identifier))
return std::nullopt;
return identifier;
}
static TakeType take(ValueType identifier)
{
if (isEmptyValue(identifier))
return std::nullopt;
return identifier;
}
};
WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const ObjectIdentifierGenericBase<uint64_t>&);
WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const ObjectIdentifierGenericBase<UUID>&);
template<typename RawValue>
class ObjectIdentifierGenericBaseStringTypeAdapter {
};
template<>
class ObjectIdentifierGenericBaseStringTypeAdapter<uint64_t> {
public:
unsigned length() const { return lengthOfIntegerAsString(m_identifier); }
bool is8Bit() const { return true; }
template<typename CharacterType> void writeTo(std::span<CharacterType> destination) const { writeIntegerToBuffer(m_identifier, destination); }
protected:
explicit ObjectIdentifierGenericBaseStringTypeAdapter(uint64_t identifier)
: m_identifier(identifier) { }
private:
uint64_t m_identifier;
};
template<typename T, typename ThreadSafety>
class StringTypeAdapter<ObjectIdentifierGeneric<T, ThreadSafety, uint64_t>> : public ObjectIdentifierGenericBaseStringTypeAdapter<uint64_t> {
public:
explicit StringTypeAdapter(ObjectIdentifierGeneric<T, ThreadSafety, uint64_t> identifier)
: ObjectIdentifierGenericBaseStringTypeAdapter(identifier.toRawValue()) { }
};
template<typename T, typename ThreadSafety>
class StringTypeAdapter<ObjectIdentifierGeneric<T, ThreadSafety, UUID>> : public StringTypeAdapter<UUID> {
public:
explicit StringTypeAdapter(ObjectIdentifierGeneric<T, ThreadSafety, UUID> identifier)
: StringTypeAdapter<UUID>(identifier.toRawValue()) { }
};
template<typename T, typename ThreadSafety, typename RawValue>
bool operator==(const ObjectIdentifierGeneric<T, ThreadSafety, RawValue>& a, const ObjectIdentifierGeneric<T, ThreadSafety, RawValue>& b)
{
return a.toRawValue() == b.toRawValue();
}
template<typename T, typename ThreadSafety>
std::strong_ordering operator<=>(const ObjectIdentifierGeneric<T, ThreadSafety, uint64_t>& a, const ObjectIdentifierGeneric<T, ThreadSafety, uint64_t>& b)
{
return a.toRawValue() <=> b.toRawValue();
}
} // namespace WTF
using WTF::AtomicObjectIdentifier;
using WTF::UUIDObjectIdentifier;
using WTF::ObjectIdentifierGenericBase;
using WTF::ObjectIdentifierGeneric;
using WTF::ObjectIdentifier;