1/**
2 * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15
16 * \author Hechong.xyf
17 * \date Mar 2018
18 * \brief Interface of AiLego Utility Factory
19 */
20
21#ifndef __AILEGO_PATTERN_FACTORY_H__
22#define __AILEGO_PATTERN_FACTORY_H__
23
24#include <cstring>
25#include <functional>
26#include <map>
27#include <memory>
28#include <string>
29#include <tuple>
30#include <vector>
31
32namespace ailego {
33
34/*! Factory
35 */
36template <typename TBase>
37class Factory {
38 public:
39 /*! Factory Register
40 */
41 template <typename TImpl, typename = typename std::enable_if<
42 std::is_base_of<TBase, TImpl>::value>::type>
43 class Register {
44 public:
45 //! Constructor
46 Register(const char *key) {
47 Factory::Instance()->set(key, [] { return Register::Construct(); });
48 }
49
50 //! Constructor
51 template <typename... TArgs>
52 Register(const char *key, TArgs &&...args) {
53 std::tuple<TArgs...> tuple(std::forward<TArgs>(args)...);
54
55 Factory::Instance()->set(key, [tuple] {
56 return Register::Construct(
57 tuple, typename TupleIndexMaker<sizeof...(TArgs)>::Type());
58 });
59 }
60
61 protected:
62 //! Tuple Index Maker
63 template <size_t N, size_t... I>
64 struct TupleIndexMaker : TupleIndexMaker<N - 1, N - 1, I...> {};
65
66 //! Tuple Index
67 template <size_t...>
68 struct TupleIndex {};
69
70 //! Tuple Index Maker (special)
71 template <size_t... I>
72 struct TupleIndexMaker<0, I...> {
73 typedef TupleIndex<I...> Type;
74 };
75
76 //! Construct a register object
77 template <typename... TArgs, size_t... I>
78 static TImpl *Construct(const std::tuple<TArgs...> &tuple,
79 TupleIndex<I...>) {
80 return new (std::nothrow) TImpl(std::get<I>(tuple)...);
81 }
82
83 //! Construct a register object
84 static TImpl *Construct(void) {
85 return new (std::nothrow) TImpl();
86 }
87 };
88
89 //! Produce an instance (c_ptr)
90 static TBase *Make(const char *key) {
91 return Factory::Instance()->produce(key);
92 }
93
94 //! Produce an instance (shared_ptr)
95 static std::shared_ptr<TBase> MakeShared(const char *key) {
96 return std::shared_ptr<TBase>(Factory::Make(key));
97 }
98
99 //! Produce an instance (unique_ptr)
100 static std::unique_ptr<TBase> MakeUnique(const char *key) {
101 return std::unique_ptr<TBase>(Factory::Make(key));
102 }
103
104 //! Test if the class is exist
105 static bool Has(const char *key) {
106 return Factory::Instance()->has(key);
107 }
108
109 //! Retrieve classes in factory
110 static std::vector<std::string> Classes(void) {
111 return Factory::Instance()->classes();
112 }
113
114 protected:
115 //! Constructor
116 Factory(void) : map_() {}
117
118 //! Retrieve the singleton factory
119 static Factory *Instance(void) {
120 static Factory factory;
121 return (&factory);
122 }
123
124 //! Inserts a new class into map
125 template <typename TFunc>
126 void set(const char *key, TFunc &&func) {
127 map_[key] = std::forward<TFunc>(func);
128 }
129
130 //! Produce an instance
131 TBase *produce(const char *key) {
132 auto iter = map_.find(key);
133 if (iter != map_.end()) {
134 return iter->second();
135 }
136 return nullptr;
137 }
138
139 //! Test if the class is exist
140 bool has(const char *key) {
141 return (map_.find(key) != map_.end());
142 }
143
144 //! Retrieve classes in factory
145 std::vector<std::string> classes(void) const {
146 std::vector<std::string> vec;
147 for (const auto &it : map_) {
148 vec.push_back(std::string(it.first));
149 }
150 return vec;
151 }
152
153 private:
154 //! Disable them
155 Factory(const Factory &);
156 Factory(Factory &&);
157 Factory &operator=(const Factory &);
158
159 /*! Key Comparer
160 */
161 struct KeyComparer {
162 bool operator()(const char *lhs, const char *rhs) const {
163 return (std::strcmp(lhs, rhs) < 0);
164 }
165 };
166
167 //! Don't use variable buffer as key store.
168 //! The key must be use a static buffer to store.
169 std::map<const char *, std::function<TBase *()>, KeyComparer> map_;
170};
171
172//! Factory Register
173#define AILEGO_FACTORY_REGISTER(__NAME__, __BASE__, __IMPL__, ...) \
174 static ailego::Factory<__BASE__>::Register<__IMPL__> \
175 __ailegoFactoryRegister_##__NAME__(#__NAME__, ##__VA_ARGS__)
176
177} // namespace ailego
178
179#endif // __AILEGO_PATTERN_FACTORY_H__
180