blob: 283eb8e76ca02a52682bc118f8276d80e489ccbe [file] [edit]
//
// Copyright 2026 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ObjectMap.h: Defines the egl::ObjectMap template class for thread-safe EGL object maps.
#ifndef LIBANGLE_OBJECT_MAP_H_
#define LIBANGLE_OBJECT_MAP_H_
#include <type_traits>
#include <vector>
#include "common/FastVector.h"
#include "common/PackedEnums.h"
#include "common/SimpleMutex.h"
#include "common/hash_containers.h"
#include "libANGLE/Error.h"
namespace egl
{
namespace priv
{
template <typename ContextMutexType>
class ContextMapImpl;
template <typename ObjectType, typename MutexType = angle::SimpleMutex>
class ObjectMap : angle::NonCopyable
{
public:
using Map = angle::HashMap<GLuint, ObjectType *>;
using ResourceVector = angle::FastVector<ObjectType *, 8>;
ObjectMap() = default;
~ObjectMap() = default;
bool empty() const
{
std::lock_guard<MutexType> lock(mMutex);
return mObjects.empty();
}
ObjectType *first() const
{
std::lock_guard<MutexType> lock(mMutex);
return mObjects.empty() ? nullptr : mObjects.begin()->second;
}
ObjectType *find(typename ResourceTypeToID<ObjectType>::IDType handle) const
{
std::lock_guard<MutexType> lock(mMutex);
auto iter = mObjects.find(handle.value);
return iter != mObjects.end() ? iter->second : nullptr;
}
void insert(typename ResourceTypeToID<ObjectType>::IDType handle, ObjectType *object)
{
std::lock_guard<MutexType> lock(mMutex);
mObjects.insert(std::pair(handle.value, object));
}
bool erase(typename ResourceTypeToID<ObjectType>::IDType handle)
{
std::lock_guard<MutexType> lock(mMutex);
auto iter = mObjects.find(handle.value);
if (iter != mObjects.end())
{
mObjects.erase(iter);
return true;
}
return false;
}
ResourceVector extractAll()
{
std::lock_guard<MutexType> lock(mMutex);
ResourceVector objects;
objects.reserve(mObjects.size());
for (const auto &pair : mObjects)
{
objects.push_back(pair.second);
}
mObjects.clear();
return objects;
}
template <typename OtherMutexType>
void moveTo(ObjectMap<ObjectType, OtherMutexType> *destination)
{
if (static_cast<void *>(this) == static_cast<void *>(destination))
{
return;
}
Map temp;
{
std::lock_guard<MutexType> lock(mMutex);
temp = std::move(mObjects);
mObjects.clear();
}
if (!temp.empty())
{
std::lock_guard<OtherMutexType> destLock(destination->mMutex);
destination->mObjects.insert(temp.begin(), temp.end());
}
}
template <typename Callback>
auto forEach(Callback &&callback) const
{
using ReturnType = std::invoke_result_t<Callback, ObjectType *>;
constexpr bool kReturnsError = std::is_same_v<ReturnType, egl::Error> ||
std::is_same_v<ReturnType, angle::Result> ||
std::is_same_v<ReturnType, bool>;
using ErrorType = std::conditional_t<kReturnsError, ReturnType, egl::Error>;
auto invoke = [&](ObjectType *object) -> ErrorType {
if constexpr (kReturnsError)
{
return callback(object);
}
else
{
callback(object);
return egl::NoError();
}
};
ErrorType result = []() {
if constexpr (std::is_same_v<ErrorType, angle::Result>)
{
return angle::Result::Continue;
}
else if constexpr (std::is_same_v<ErrorType, bool>)
{
return true;
}
else
{
return egl::NoError();
}
}();
if constexpr (std::is_same_v<MutexType, angle::NoOpMutex>)
{
// This lock really is a no-op. It is there to satisfy the template
// requirement.
std::lock_guard<MutexType> lock(mMutex);
for (const auto &pair : mObjects)
{
if (!IsError(result))
{
result = invoke(pair.second);
}
}
}
else
{
// Collect objects while holding the lock to avoid holding it for the entire
// duration of the callback which may end up with deadlock if callback ends up calling
// into this ObjectMap.
ResourceVector objects;
{
std::lock_guard<MutexType> lock(mMutex);
objects.reserve(mObjects.size());
for (const auto &pair : mObjects)
{
pair.second->addRef();
objects.push_back(pair.second);
}
}
for (ObjectType *object : objects)
{
if (!IsError(result))
{
result = invoke(object);
}
object->release();
}
}
if constexpr (kReturnsError)
{
return result;
}
}
protected:
template <typename OtherObjectType, typename OtherMutexType>
friend class ObjectMap;
template <typename ContextMutexType>
friend class ContextMapImpl;
mutable MutexType mMutex;
Map mObjects;
};
} // namespace priv
} // namespace egl
#endif // LIBANGLE_OBJECT_MAP_H_