blob: 217f0d34ffaaa34f92a8eaadbebee2cf3f3e496d [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_INTERACTION_IMPLEMENTATION_LIST_H_
#define UI_BASE_INTERACTION_IMPLEMENTATION_LIST_H_
#include <concepts>
#include <iterator>
#include <memory>
#include <vector>
#include "ui/base/interaction/safe_castable.h"
namespace ui {
// Holds a list of implementation-specific singletons, which all derive from
// `BaseClass` (which must be SafeCastable).
//
// Semantically, this behaves as a very simple ordered STL collection of
// `BaseClass`. Insertion is only done via MaybeRegister().
template <class BaseClass>
requires std::derived_from<BaseClass, SafeCastable>
class ImplementationList {
public:
using ListType = std::vector<std::unique_ptr<BaseClass>>;
// Implements a simple forward iterator over instances.
template <class It = typename ListType::iterator>
class Iterator {
public:
using difference_type = std::iter_difference_t<It>;
Iterator() = default;
~Iterator() = default;
Iterator(const Iterator&) = default;
Iterator& operator=(const Iterator&) = default;
BaseClass& operator*() { return *(it_->get()); }
BaseClass* operator->() { return it_->get(); }
Iterator& operator++() {
++it_;
return *this;
}
Iterator operator++(int) { return Iterator(it_++); }
friend bool operator==(const Iterator&, const Iterator&) = default;
private:
friend class ImplementationList<BaseClass>;
explicit Iterator(It it) : it_(it) {}
It it_;
};
// STL collection properties.
using value_type = BaseClass;
using reference = BaseClass&;
using pointer = BaseClass*;
using iterator = Iterator<>;
using const_iterator = Iterator<typename ListType::const_iterator>;
using reverse_iterator = Iterator<typename ListType::reverse_iterator>;
using const_reverse_iterator =
Iterator<typename ListType::const_reverse_iterator>;
using size_type = typename ListType::size_type;
ImplementationList() = default;
~ImplementationList() = default;
// STL collection implementation.
size_type size() const { return instances_.size(); }
iterator begin() { return iterator(instances_.begin()); }
iterator end() { return iterator(instances_.end()); }
reverse_iterator rbegin() { return reverse_iterator(instances_.rbegin()); }
reverse_iterator rend() { return reverse_iterator(instances_.rend()); }
const_iterator begin() const { return const_iterator(instances_.begin()); }
const_iterator end() const { return const_iterator(instances_.end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(instances_.rbegin());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(instances_.rend());
}
BaseClass& operator[](size_type index) { return *instances_[index]; }
const BaseClass& operator[](size_type index) const {
return *instances_[index];
}
// Adds an instance of `DerivedClass` if it is not already present.
// Additional arguments in `params` will only be consumed if the class needs
// to be added, so do not allocate resources that are not scoped and movable
// (i.e. pass a std::unique_ptr rather than "new X", so the object will be
// properly cleaned up if it is not used).
//
// Returns the object of the specified type if created, or null if already
// present (you can still use GetImplementation() to retrieve it).
template <class DerivedClass, typename... Args>
requires std::derived_from<DerivedClass, BaseClass>
DerivedClass* MaybeRegister(Args&&... args) {
if (auto* derived = GetImplementation<DerivedClass>()) {
return nullptr;
}
auto ptr = std::make_unique<DerivedClass>(std::forward<Args>(args)...);
DerivedClass* const result = ptr.get();
instances_.push_back(std::move(ptr));
return result;
}
// Retrieves a particular implementation by type, or null if none is
// registered. Uses the `IsA` relation to determine if `DerivedClass` is
// present.
template <class DerivedClass>
requires std::derived_from<DerivedClass, BaseClass>
DerivedClass* GetImplementation() {
for (const auto& instance : instances_) {
if (instance->template IsA<DerivedClass>()) {
return static_cast<DerivedClass*>(instance.get());
}
}
return nullptr;
}
private:
ListType instances_;
};
} // namespace ui
#endif // UI_BASE_INTERACTION_IMPLEMENTATION_LIST_H_