File indexing completed on 2025-01-05 04:01:22

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include "base.hpp"
0010 #include "mime/mime_serializer.hpp"
0011 
0012 namespace glaxnimate::io {
0013 
0014 namespace detail {
0015 
0016 inline bool compare_ie_ptr(const ImportExport* ptr_a, const ImportExport* ptr_b) noexcept
0017 {
0018     return ptr_a->priority() > ptr_b->priority();
0019 }
0020 
0021 inline bool compare_ie_unique_ptr(const std::unique_ptr<ImportExport>& ptr_a, const std::unique_ptr<ImportExport>& ptr_b) noexcept
0022 {
0023     return compare_ie_ptr(ptr_a.get(), ptr_b.get());
0024 }
0025 
0026 } // namespace detail
0027 
0028 class IoRegistry
0029 {
0030 public:
0031     static IoRegistry& instance()
0032     {
0033         static IoRegistry factory;
0034         return factory;
0035     }
0036 
0037     ImportExport* register_object(std::unique_ptr<ImportExport> ie)
0038     {
0039         using namespace detail;
0040         auto iter = std::upper_bound(object_list.begin(), object_list.end(), ie, &compare_ie_unique_ptr);
0041         ImportExport* format = ie.get();
0042         object_list.insert(iter, std::move(ie));
0043         if ( format->can_save() )
0044             exporters_.insert(std::upper_bound(exporters_.begin(), exporters_.end(), format, &compare_ie_ptr), format);
0045         if ( format->can_open() )
0046             importers_.insert(std::upper_bound(importers_.begin(), importers_.end(), format, &compare_ie_ptr), format);
0047         return format;
0048     }
0049 
0050     void unregister(ImportExport* object)
0051     {
0052         for ( auto it = object_list.begin(); it != object_list.end(); ++it )
0053         {
0054             if ( it->get() == object )
0055             {
0056                 object_list.erase(it);
0057                 break;
0058             }
0059         }
0060         importers_.erase(std::remove(importers_.begin(), importers_.end(), object), importers_.end());
0061         exporters_.erase(std::remove(exporters_.begin(), exporters_.end(), object), exporters_.end());
0062     }
0063 
0064     mime::MimeSerializer* register_object(std::unique_ptr<mime::MimeSerializer> ie)
0065     {
0066         mime_list.push_back(std::move(ie));
0067         mime::MimeSerializer* format = mime_list.back().get();
0068         mime_pointers.push_back(format);
0069         return format;
0070     }
0071 
0072     const std::vector<ImportExport*>& importers() const { return importers_; }
0073     const std::vector<ImportExport*>& exporters() const { return exporters_; }
0074     const std::vector<mime::MimeSerializer*>& serializers() const { return mime_pointers; }
0075 
0076     const std::vector<std::unique_ptr<ImportExport>>& registered() const
0077     {
0078         return object_list;
0079     }
0080 
0081     ImportExport* from_extension(const QString& extension, ImportExport::Direction direction) const
0082     {
0083         int top_priority = std::numeric_limits<int>::min();
0084         ImportExport* best = nullptr;
0085         for ( const auto& p : object_list )
0086         {
0087             if ( p->can_handle_extension(extension, direction) && p->priority() > top_priority )
0088             {
0089                 best = p.get();
0090                 top_priority = p->priority();
0091             }
0092         }
0093 
0094         return best;
0095     }
0096 
0097     ImportExport* from_filename(const QString& filename, ImportExport::Direction direction) const
0098     {
0099         int top_priority = std::numeric_limits<int>::min();
0100         ImportExport* best = nullptr;
0101 
0102         for ( const auto& p : object_list )
0103         {
0104             if ( p->can_handle_filename(filename, direction) && p->priority() > top_priority )
0105             {
0106                 best = p.get();
0107                 top_priority = p->priority();
0108             }
0109         }
0110 
0111         return best;
0112     }
0113 
0114     ImportExport* from_slug(const QString& slug) const
0115     {
0116         for ( const auto& p : object_list )
0117             if ( p->slug() == slug )
0118                 return p.get();
0119 
0120         return nullptr;
0121     }
0122 
0123     mime::MimeSerializer* serializer_from_slug(const QString& slug) const
0124     {
0125         for ( const auto& serializer : mime_list )
0126         {
0127             if ( serializer->slug() == slug )
0128                 return serializer.get();
0129         }
0130 
0131         return nullptr;
0132     }
0133 
0134 private:
0135     std::vector<std::unique_ptr<ImportExport>> object_list;
0136     std::vector<ImportExport*> importers_;
0137     std::vector<ImportExport*> exporters_;
0138     std::vector<std::unique_ptr<mime::MimeSerializer>> mime_list;
0139     std::vector<mime::MimeSerializer*> mime_pointers;
0140 
0141     IoRegistry() = default;
0142     ~IoRegistry() = default;
0143 };
0144 
0145 
0146 template<class Derived>
0147 class Autoreg
0148 {
0149 public:
0150     template<class... Args>
0151     Autoreg(Args&&... args)
0152     : registered { static_cast<Derived*>(
0153         IoRegistry::instance().register_object(std::make_unique<Derived>(std::forward<Args>(args)...))
0154     ) } {}
0155 
0156     Derived* const registered;
0157 };
0158 
0159 } // namespace glaxnimate::io