Scine::Core  3.0.0
Module management and core interface definitions
 All Classes Files Functions Variables Typedefs Pages
DerivedModule.h
Go to the documentation of this file.
1 
9 #ifndef CORE_DERIVED_MODULE_
10 #define CORE_DERIVED_MODULE_
11 
12 #include "boost/any.hpp"
13 #include "boost/mpl/at.hpp"
14 #include "boost/mpl/find_if.hpp"
15 #include "boost/mpl/for_each.hpp"
16 #include "boost/mpl/map.hpp"
17 #include "boost/mpl/size.hpp"
18 #include "boost/mpl/size_t.hpp"
19 #include "boost/mpl/vector.hpp"
20 #include <algorithm>
21 #include <array>
22 #include <memory>
23 #include <stdexcept>
24 #include <string>
25 #include <vector>
26 
27 namespace Scine {
28 namespace Core {
29 namespace DerivedModule {
30 
31 namespace detail {
32 
33 inline bool caseInsensitiveEqual(const std::string& a, const std::string& b) {
34  return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b),
35  [](const char x, const char y) -> bool { return ::tolower(x) == ::tolower(y); });
36 }
37 
38 // When at end of sequence and Exec has not been called, return the none()
39 template<bool done = true>
40 struct exec_if_impl {
41  template<typename Iter, typename LastIter, typename Pred, typename Exec>
42  static auto execute(Iter* /* i */, LastIter* /* l */, const Pred& /* p */, const Exec & /* e */) ->
43  typename Exec::ResultType {
44  return Exec::none();
45  }
46 };
47 
48 // Non-end iterator of type sequence: Test predicate
49 template<>
50 struct exec_if_impl<false> {
51  template<typename Iter, typename LastIter, typename Pred, typename Exec>
52  static auto execute(Iter* /* i */, LastIter* /* l */, const Pred& p, const Exec& e) -> typename Exec::ResultType {
53  using Item = typename boost::mpl::deref<Iter>::type;
54 
55  if (!p(static_cast<Item*>(0))) {
56  using Next = typename boost::mpl::next<Iter>::type;
57  return exec_if_impl<boost::is_same<Next, LastIter>::value>::execute(static_cast<Next*>(0),
58  static_cast<LastIter*>(0), p, e);
59  }
60  else {
61  return e(static_cast<Item*>(0));
62  }
63  }
64 };
65 
82 template<typename Sequence, typename Predicate, typename Executable>
83 inline auto exec_if(const Predicate& p, const Executable& e, Sequence* = 0) -> typename Executable::ResultType {
84  BOOST_MPL_ASSERT((boost::mpl::is_sequence<Sequence>));
85  using First = typename boost::mpl::begin<Sequence>::type;
86  using Last = typename boost::mpl::end<Sequence>::type;
87 
88  return exec_if_impl<boost::is_same<First, Last>::value>::execute(static_cast<First*>(0), static_cast<Last*>(0), p, e);
89 }
90 
91 // Predicate type for exec_if
93  MapPairInterfaceIdentifierMatches(std::string id) : identifier(std::move(id)) {
94  }
95 
96  template<typename PairType>
97  bool operator()(PairType* = 0) const {
98  using InterfaceType = typename boost::mpl::first<PairType>::type;
99  return caseInsensitiveEqual(identifier, InterfaceType::interface);
100  }
101 
102  std::string identifier;
103 };
104 
105 // Predicate type for exec_if
107  ModelTypeIdentifierMatches(std::string id) : identifier(std::move(id)) {
108  }
109 
110  template<typename ModelType>
111  bool operator()(ModelType* = 0) const {
112  return caseInsensitiveEqual(identifier, ModelType::model);
113  }
114 
115  std::string identifier;
116 };
117 
118 // Executable type for exec_if
119 template<typename InterfaceType>
121  using InterfaceTypePtr = std::shared_ptr<InterfaceType>;
122  using ResultType = boost::any;
123 
124  template<typename ModelType>
125  ResultType operator()(ModelType* = 0) const {
126  return static_cast<InterfaceTypePtr>(std::make_shared<ModelType>());
127  }
128 
129  static ResultType none() {
130  return {};
131  }
132 };
133 
134 // Executable type for exec_if
135 struct ResolveModel {
136  ResolveModel(std::string id) : identifier(std::move(id)) {
137  }
138 
139  using ResultType = boost::any;
140 
141  template<typename PairType>
142  boost::any operator()(PairType* = 0) const {
143  using InterfaceType = typename boost::mpl::first<PairType>::type;
144  using ModelTypeList = typename boost::mpl::second<PairType>::type;
145 
146  return detail::exec_if<ModelTypeList>(detail::ModelTypeIdentifierMatches{identifier},
148  }
149 
150  static ResultType none() {
151  return {};
152  }
153 
154  std::string identifier;
155 };
156 
157 // Executable type for exec_if
159  using ResultType = bool;
160 
161  template<typename T>
162  ResultType operator()(T* = 0) const {
163  return true;
164  }
165 
166  static ResultType none() {
167  return false;
168  }
169 };
170 
171 // Executable type for exec_if
172 struct ModelExists {
173  ModelExists(std::string id) : identifier(std::move(id)) {
174  }
175 
176  using ResultType = bool;
177 
178  template<typename PairType>
179  ResultType operator()(PairType* = 0) const {
180  using ModelTypeList = typename boost::mpl::second<PairType>::type;
181 
182  return exec_if<ModelTypeList>(detail::ModelTypeIdentifierMatches{identifier}, MatchFoundExecutor{});
183  }
184 
185  static ResultType none() {
186  return false;
187  }
188 
189  std::string identifier;
190 };
191 
192 // Executable type for exec_if
193 struct ListModels {
194  using ResultType = std::vector<std::string>;
195 
196  template<typename PairType>
197  ResultType operator()(PairType* = 0) const {
198  using ModelTypeList = typename boost::mpl::second<PairType>::type;
199 
200  std::vector<std::string> models;
201  models.reserve(boost::mpl::size<ModelTypeList>::value);
202  // "Iterate" through this entry's list of model types
203  boost::mpl::for_each<ModelTypeList, boost::mpl::make_identity<boost::mpl::_1>>([&](auto t) {
204  using ModelType = typename decltype(t)::type;
205  models.push_back(ModelType::model);
206  });
207 
208  return models;
209  }
210 
211  static ResultType none() {
212  return {};
213  }
214 };
215 
216 // Compile-time compare C-style strings
217 constexpr bool strEqual(const char* a, const char* b) {
218  return *a == *b && (*a == '\0' || strEqual(a + 1, b + 1));
219 }
220 
221 // For a list of model types, test whether any identifiers are duplicate
222 template<typename... ModelTypes>
223 constexpr bool identifiersOverlap() {
224  constexpr std::size_t S = sizeof...(ModelTypes);
225 
226  const std::array<const char*, S> typeIdentifiers{ModelTypes::model...};
227 
228  for (unsigned i = 0; i < S; ++i) {
229  for (unsigned j = i + 1; j < S; ++j) {
230  if (strEqual(typeIdentifiers.at(i), typeIdentifiers.at(j))) {
231  return true;
232  }
233  }
234  }
235 
236  return false;
237 }
238 
239 // expansion of all types in the mpl vector to variadic pack for identifiersOverlap
240 template<typename MPLVector, std::size_t... Inds>
241 constexpr bool identifierOverlapForwarder(std::index_sequence<Inds...> /* inds */) {
242  return identifiersOverlap<typename boost::mpl::at<MPLVector, boost::mpl::size_t<Inds>>::type...>();
243 }
244 
245 // MPL Metafunction predicate suitable for find_if, and also for our none_of
247  template<typename MPLMapIterPair>
248  struct apply
249  : std::integral_constant<
250  bool, identifierOverlapForwarder<typename boost::mpl::second<MPLMapIterPair>::type>(
251  std::make_index_sequence<boost::mpl::size<typename boost::mpl::second<MPLMapIterPair>::type>::type::value>{})> {
252  };
253 };
254 
255 // MPL Metafunction predicate suitable for our none_of
257  template<typename MPLMapIterPair>
258  struct apply
259  : std::integral_constant<bool, boost::mpl::size<typename boost::mpl::second<MPLMapIterPair>::type>::value == 0> {};
260 };
261 
262 template<typename Sequence, typename Predicate>
263 struct none_of
264  : boost::is_same<typename boost::mpl::end<Sequence>::type, typename boost::mpl::find_if<Sequence, Predicate>::type> {};
265 
266 // Value type stating whether all model lists in an mpl map have at least one member type
267 template<typename MPLMap>
268 struct ModelListsAreNotEmpty : std::integral_constant<bool, none_of<MPLMap, ModelTypeListIsEmpty>::value> {};
269 
270 // Value type stating whether all model lists in an mpl map have no model identifier duplicates
271 template<typename MPLMap>
272 struct NoModelIdentifiersOverlap : std::integral_constant<bool, none_of<MPLMap, IdentifierOverlapPredicate>::value> {};
273 
274 } // namespace detail
275 
335 template<typename MPLMap>
336 boost::any resolve(const std::string& interface, const std::string& model) {
337  static_assert(detail::ModelListsAreNotEmpty<MPLMap>::value, "Model type lists may not be empty!");
338 
340  "Model identifiers overlap within a single model type list! Model identifiers must be unique within an "
341  "interface!");
342 
343  return detail::exec_if<MPLMap>(detail::MapPairInterfaceIdentifierMatches{interface}, detail::ResolveModel{model});
344 }
345 
356 template<typename MPLMap>
357 bool has(const std::string& interface, const std::string& model) noexcept {
358  return detail::exec_if<MPLMap>(detail::MapPairInterfaceIdentifierMatches{interface}, detail::ModelExists{model});
359 }
360 
369 template<typename MPLMap>
370 std::vector<std::string> announceInterfaces() noexcept {
371  std::vector<std::string> interface;
372  interface.reserve(boost::mpl::size<MPLMap>::value);
373 
374  boost::mpl::for_each<MPLMap, boost::mpl::make_identity<boost::mpl::_1>>([&](auto p) {
375  using PairType = typename decltype(p)::type;
376  using InterfaceType = typename boost::mpl::first<PairType>::type;
377  interface.push_back(InterfaceType::interface);
378  });
379 
380  return interface;
381 }
382 
393 template<typename MPLMap>
394 std::vector<std::string> announceModels(const std::string& interface) noexcept {
395  return detail::exec_if<MPLMap>(detail::MapPairInterfaceIdentifierMatches{interface}, detail::ListModels{});
396 }
397 
398 } // namespace DerivedModule
399 } // namespace Core
400 } // namespace Scine
401 
402 #endif
Definition: DerivedModule.h:263
Definition: DerivedModule.h:193