diff --git a/src/xenia/base/factory.h b/src/xenia/base/factory.h new file mode 100644 index 000000000..895a5cf55 --- /dev/null +++ b/src/xenia/base/factory.h @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BASE_FACTORY_H_ +#define XENIA_BASE_FACTORY_H_ + +#include +#include +#include +#include + +namespace xe { + +template +class Factory { + private: + struct Creator { + std::string name; + std::function is_available; + std::function(Args...)> instantiate; + }; + + std::vector creators_; + + public: + void Add(const std::string_view name, std::function is_available, + std::function(Args...)> instantiate) { + creators_.push_back({std::string(name), is_available, instantiate}); + } + + void Add(const std::string_view name, + std::function(Args...)> instantiate) { + auto always_available = []() { return true; }; + Add(name, always_available, instantiate); + } + + template + void Add(const std::string_view name) { + Add(name, DT::IsAvailable, [](Args... args) { + return std::make_unique
(std::forward(args)...); + }); + } + + std::unique_ptr Create(const std::string_view name, Args... args) { + if (!name.empty() && name != "any") { + auto it = std::find_if( + creators_.cbegin(), creators_.cend(), + [&name](const auto& f) { return name.compare(f.name) == 0; }); + if (it != creators_.cend() && (*it).is_available()) { + return (*it).instantiate(std::forward(args)...); + } + return nullptr; + } else { + for (const auto& creator : creators_) { + if (!creator.is_available()) continue; + auto instance = creator.instantiate(std::forward(args)...); + if (!instance) continue; + return instance; + } + return nullptr; + } + } + + std::vector> CreateAll(const std::string_view name, + Args... args) { + std::vector> instances; + if (!name.empty() && name != "any") { + auto it = std::find_if( + creators_.cbegin(), creators_.cend(), + [&name](const auto& f) { return name.compare(f.name) == 0; }); + if (it != creators_.cend() && (*it).is_available()) { + auto instance = (*it).instantiate(std::forward(args)...); + if (instance) { + instances.emplace_back(std::move(instance)); + } + } + } else { + for (const auto& creator : creators_) { + if (!creator.is_available()) continue; + auto instance = creator.instantiate(std::forward(args)...); + if (instance) { + instances.emplace_back(std::move(instance)); + } + } + } + return instances; + } +}; + +} // namespace xe + +#endif \ No newline at end of file