/** * This file is part of GpgFrontend. * * GpgFrontend is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Foobar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . * * The initial version of the source code is inherited from gpg4usb-team. * Their source code version also complies with GNU General Public License. * * The source code version of this software was modified and released * by Saturneric starting on May 12, 2021. * */ #ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H #define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H #include #include #include #include #include #include #include namespace GpgFrontend { template class SingletonFunctionObject { public: static T& GetInstance(int channel = 0) { if (!channel) { std::lock_guard guard(_instance_mutex); if (_instance == nullptr) _instance = std::make_unique(); return *_instance; } else { // read _instances_map decltype(_instances_map.end()) _it; { std::shared_lock lock(_instances_mutex); _it = _instances_map.find(channel); } if (_it != _instances_map.end()) return *_it->second; else return CreateInstance(channel); } } static T& CreateInstance(int channel, std::unique_ptr p_obj = nullptr) { if (!channel) return *_instance; // read _instances_map decltype(_instances_map.end()) _it; { std::shared_lock lock(_instances_mutex); _it = _instances_map.find(channel); } if (_it == _instances_map.end()) { { std::lock_guard guard(_default_channel_mutex); int tmp = channel; std::swap(_default_channel, tmp); if (p_obj == nullptr) p_obj = std::make_unique(); std::swap(_default_channel, tmp); } T* obj = p_obj.get(); // change _instances_map { std::unique_lock lock(_instances_mutex); _instances_map.insert({channel, std::move(p_obj)}); } return *obj; } else { return *_it->second; } } static int GetDefaultChannel() { return _default_channel; } int GetChannel() const { return channel_; } SingletonFunctionObject(T&&) = delete; SingletonFunctionObject(const T&) = delete; void operator=(const T&) = delete; protected: SingletonFunctionObject() {} SingletonFunctionObject(int channel) : channel_(channel) {} virtual ~SingletonFunctionObject() = default; private: int channel_ = _default_channel; static int _default_channel; static std::mutex _default_channel_mutex; static std::mutex _instance_mutex; static std::shared_mutex _instances_mutex; static std::unique_ptr _instance; static std::map> _instances_map; }; template int SingletonFunctionObject::_default_channel = 0; template std::mutex SingletonFunctionObject::_default_channel_mutex; template std::mutex SingletonFunctionObject::_instance_mutex; template std::shared_mutex SingletonFunctionObject::_instances_mutex; template std::unique_ptr SingletonFunctionObject::_instance = nullptr; template std::map> SingletonFunctionObject::_instances_map; } // namespace GpgFrontend #endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H