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 | |
32 | namespace ailego { |
33 | |
34 | /*! Factory |
35 | */ |
36 | template <typename TBase> |
37 | class 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 | |