2
0

LogicalExpression.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. #pragma once
  2. //FIXME: move some of code into .cpp to avoid this include?
  3. #include "JsonNode.h"
  4. namespace LogicalExpressionDetail
  5. {
  6. /// class that defines required types for logical expressions
  7. template<typename ContainedClass>
  8. class ExpressionBase
  9. {
  10. public:
  11. /// Possible logical operations, mostly needed to create different types for boost::variant
  12. enum EOperations
  13. {
  14. ANY_OF,
  15. ALL_OF,
  16. NONE_OF
  17. };
  18. template<EOperations tag> class Element;
  19. typedef Element<ANY_OF> OperatorAny;
  20. typedef Element<ALL_OF> OperatorAll;
  21. typedef Element<NONE_OF> OperatorNone;
  22. typedef ContainedClass Value;
  23. /// Variant that contains all possible elements from logical expression
  24. typedef boost::variant<
  25. OperatorAll,
  26. OperatorAny,
  27. OperatorNone,
  28. Value
  29. > Variant;
  30. /// Variant element, contains list of expressions to which operation "tag" should be applied
  31. template<EOperations tag>
  32. class Element
  33. {
  34. public:
  35. Element() {}
  36. Element(std::vector<Variant> expressions):
  37. expressions(expressions)
  38. {}
  39. std::vector<Variant> expressions;
  40. template <typename Handler>
  41. void serialize(Handler & h, const int version)
  42. {
  43. h & expressions;
  44. }
  45. };
  46. };
  47. /// Visitor to test result (true/false) of the expression
  48. template <typename ContainedClass>
  49. class TestVisitor : public boost::static_visitor<bool>
  50. {
  51. typedef ExpressionBase<ContainedClass> Base;
  52. std::function<bool(const typename Base::Value &)> classTest;
  53. size_t countPassed(const std::vector<typename Base::Variant> & element) const
  54. {
  55. return boost::range::count_if(element, [&](const typename Base::Variant & expr)
  56. {
  57. return boost::apply_visitor(*this, expr);
  58. });
  59. }
  60. public:
  61. TestVisitor(std::function<bool (const typename Base::Value &)> classTest):
  62. classTest(classTest)
  63. {}
  64. bool operator()(const typename Base::OperatorAny & element) const
  65. {
  66. return countPassed(element.expressions) != 0;
  67. }
  68. bool operator()(const typename Base::OperatorAll & element) const
  69. {
  70. return countPassed(element.expressions) == element.expressions.size();
  71. }
  72. bool operator()(const typename Base::OperatorNone & element) const
  73. {
  74. return countPassed(element.expressions) == 0;
  75. }
  76. bool operator()(const typename Base::Value & element) const
  77. {
  78. return classTest(element);
  79. }
  80. };
  81. /// visitor that is trying to generates candidates that must be fulfilled
  82. /// to complete this expression
  83. template <typename ContainedClass>
  84. class CandidatesVisitor : public boost::static_visitor<std::vector<ContainedClass> >
  85. {
  86. typedef ExpressionBase<ContainedClass> Base;
  87. typedef std::vector<typename Base::Value> TValueList;
  88. TestVisitor<ContainedClass> classTest;
  89. public:
  90. CandidatesVisitor(std::function<bool(const typename Base::Value &)> classTest):
  91. classTest(classTest)
  92. {}
  93. TValueList operator()(const typename Base::OperatorAny & element) const
  94. {
  95. TValueList ret;
  96. if (!classTest(element))
  97. {
  98. for (auto & elem : element.expressions)
  99. boost::range::copy(boost::apply_visitor(*this, elem), std::back_inserter(ret));
  100. }
  101. return ret;
  102. }
  103. TValueList operator()(const typename Base::OperatorAll & element) const
  104. {
  105. TValueList ret;
  106. if (!classTest(element))
  107. {
  108. for (auto & elem : element.expressions)
  109. boost::range::copy(boost::apply_visitor(*this, elem), std::back_inserter(ret));
  110. }
  111. return ret;
  112. }
  113. TValueList operator()(const typename Base::OperatorNone & element) const
  114. {
  115. return TValueList(); //TODO. Implementing this one is not straightforward, if ever possible
  116. }
  117. TValueList operator()(const typename Base::Value & element) const
  118. {
  119. if (classTest(element))
  120. return TValueList();
  121. else
  122. return TValueList(1, element);
  123. }
  124. };
  125. /// Simple foreach visitor
  126. template <typename ContainedClass>
  127. class ForEachVisitor : public boost::static_visitor<void>
  128. {
  129. typedef ExpressionBase<ContainedClass> Base;
  130. std::function<void(typename Base::Value &)> visitor;
  131. public:
  132. ForEachVisitor(std::function<void(typename Base::Value &)> visitor):
  133. visitor(visitor)
  134. {}
  135. //FIXME: duplicated code
  136. void operator()(typename Base::OperatorAny & element) const
  137. {
  138. for (auto & entry : element.expressions)
  139. boost::apply_visitor(*this, entry);
  140. }
  141. void operator()(typename Base::OperatorAll & element) const
  142. {
  143. for (auto & entry : element.expressions)
  144. boost::apply_visitor(*this, entry);
  145. }
  146. void operator()(typename Base::OperatorNone & element) const
  147. {
  148. for (auto & entry : element.expressions)
  149. boost::apply_visitor(*this, entry);
  150. }
  151. void operator()(typename Base::Value & element) const
  152. {
  153. visitor(element);
  154. }
  155. };
  156. /// Json parser for expressions
  157. template <typename ContainedClass>
  158. class Reader
  159. {
  160. typedef ExpressionBase<ContainedClass> Base;
  161. std::function<typename Base::Value(const JsonNode &)> classParser;
  162. typename Base::Variant readExpression(const JsonNode & node)
  163. {
  164. assert(!node.Vector().empty());
  165. std::string type = node.Vector()[0].String();
  166. if (type == "anyOf")
  167. return typename Base::OperatorAny(readVector(node));
  168. if (type == "allOf")
  169. return typename Base::OperatorAll(readVector(node));
  170. if (type == "noneOf")
  171. return typename Base::OperatorNone(readVector(node));
  172. return classParser(node);
  173. }
  174. std::vector<typename Base::Variant> readVector(const JsonNode & node)
  175. {
  176. std::vector<typename Base::Variant> ret;
  177. ret.reserve(node.Vector().size()-1);
  178. for (size_t i=1; i < node.Vector().size(); i++)
  179. ret.push_back(readExpression(node.Vector()[i]));
  180. return ret;
  181. }
  182. public:
  183. Reader(std::function<typename Base::Value(const JsonNode &)> classParser):
  184. classParser(classParser)
  185. {}
  186. typename Base::Variant operator ()(const JsonNode & node)
  187. {
  188. return readExpression(node);
  189. }
  190. };
  191. /// Prints expression in human-readable format
  192. template <typename ContainedClass>
  193. class Writer : public boost::static_visitor<JsonNode>
  194. {
  195. typedef ExpressionBase<ContainedClass> Base;
  196. std::function<JsonNode(const typename Base::Value &)> classPrinter;
  197. JsonNode printExpressionList(std::string name, const std::vector<typename Base::Variant> & element) const
  198. {
  199. JsonNode ret;
  200. ret.Vector().resize(1);
  201. ret.Vector().back().String() = name;
  202. for (auto & expr : element)
  203. ret.Vector().push_back(boost::apply_visitor(*this, expr));
  204. return ret;
  205. }
  206. public:
  207. Writer(std::function<JsonNode(const typename Base::Value &)> classPrinter):
  208. classPrinter(classPrinter)
  209. {}
  210. JsonNode operator()(const typename Base::OperatorAny & element) const
  211. {
  212. return printExpressionList("anyOf", element.expressions);
  213. }
  214. JsonNode operator()(const typename Base::OperatorAll & element) const
  215. {
  216. return printExpressionList("allOf", element.expressions);
  217. }
  218. JsonNode operator()(const typename Base::OperatorNone & element) const
  219. {
  220. return printExpressionList("noneOf", element.expressions);
  221. }
  222. JsonNode operator()(const typename Base::Value & element) const
  223. {
  224. return classPrinter(element);
  225. }
  226. };
  227. std::string DLL_LINKAGE getTextForOperator(std::string operation);
  228. /// Prints expression in human-readable format
  229. template <typename ContainedClass>
  230. class Printer : public boost::static_visitor<std::string>
  231. {
  232. typedef ExpressionBase<ContainedClass> Base;
  233. std::function<std::string(const typename Base::Value &)> classPrinter;
  234. std::unique_ptr<TestVisitor<ContainedClass>> statusTest;
  235. mutable std::string prefix;
  236. template<typename Operator>
  237. std::string formatString(std::string toFormat, const Operator & expr) const
  238. {
  239. // highlight not fulfilled expressions, if pretty formatting is on
  240. if (statusTest && !(*statusTest)(expr))
  241. return "{" + toFormat + "}";
  242. return toFormat;
  243. }
  244. std::string printExpressionList(const std::vector<typename Base::Variant> & element) const
  245. {
  246. std::string ret;
  247. prefix.push_back('\t');
  248. for (auto & expr : element)
  249. ret += prefix + boost::apply_visitor(*this, expr) + "\n";
  250. prefix.pop_back();
  251. return ret;
  252. }
  253. public:
  254. Printer(std::function<std::string(const typename Base::Value &)> classPrinter):
  255. classPrinter(classPrinter)
  256. {}
  257. Printer(std::function<std::string(const typename Base::Value &)> classPrinter, std::function<bool(const typename Base::Value &)> toBool):
  258. classPrinter(classPrinter),
  259. statusTest(new TestVisitor<ContainedClass>(toBool))
  260. {}
  261. std::string operator()(const typename Base::OperatorAny & element) const
  262. {
  263. return formatString(getTextForOperator("anyOf"), element) + "\n"
  264. + printExpressionList(element.expressions);
  265. }
  266. std::string operator()(const typename Base::OperatorAll & element) const
  267. {
  268. return formatString(getTextForOperator("allOf"), element) + "\n"
  269. + printExpressionList(element.expressions);
  270. }
  271. std::string operator()(const typename Base::OperatorNone & element) const
  272. {
  273. return formatString(getTextForOperator("noneOf"), element) + "\n"
  274. + printExpressionList(element.expressions);
  275. }
  276. std::string operator()(const typename Base::Value & element) const
  277. {
  278. return formatString(classPrinter(element), element);
  279. }
  280. };
  281. }
  282. ///
  283. /// Class for evaluation of logical expressions generated in runtime
  284. ///
  285. template<typename ContainedClass>
  286. class LogicalExpression
  287. {
  288. typedef LogicalExpressionDetail::ExpressionBase<ContainedClass> Base;
  289. public:
  290. /// Type of values used in expressions, same as ContainedClass
  291. typedef typename Base::Value Value;
  292. /// Operators for use in expressions, all include vectors with operands
  293. typedef typename Base::OperatorAny OperatorAny;
  294. typedef typename Base::OperatorAll OperatorAll;
  295. typedef typename Base::OperatorNone OperatorNone;
  296. /// one expression entry
  297. typedef typename Base::Variant Variant;
  298. private:
  299. Variant data;
  300. public:
  301. /// Base constructor
  302. LogicalExpression()
  303. {}
  304. /// Constructor from variant or (implicitly) from Operator* types
  305. LogicalExpression(const Variant & data):
  306. data(data)
  307. {
  308. }
  309. /// Constructor that receives JsonNode as input and function that can parse Value instances
  310. LogicalExpression(const JsonNode & input, std::function<Value(const JsonNode &)> parser)
  311. {
  312. LogicalExpressionDetail::Reader<Value> reader(parser);
  313. LogicalExpression expr(reader(input));
  314. std::swap(data, expr.data);
  315. }
  316. Variant get()
  317. {
  318. return data;
  319. }
  320. /// Simple visitor that visits all entries in expression
  321. void forEach(std::function<void(Value &)> visitor)
  322. {
  323. LogicalExpressionDetail::ForEachVisitor<Value> testVisitor(visitor);
  324. boost::apply_visitor(testVisitor, data);
  325. }
  326. /// calculates if expression evaluates to "true".
  327. /// Note: empty expressions always return true
  328. bool test(std::function<bool(const Value &)> toBool) const
  329. {
  330. LogicalExpressionDetail::TestVisitor<Value> testVisitor(toBool);
  331. return boost::apply_visitor(testVisitor, data);
  332. }
  333. /// generates list of candidates that can be fulfilled by caller (like AI)
  334. std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
  335. {
  336. LogicalExpressionDetail::CandidatesVisitor<Value> candidateVisitor(toBool);
  337. return boost::apply_visitor(candidateVisitor, data);
  338. }
  339. /// Converts expression in human-readable form
  340. /// Second version will try to do some pretty printing using H3 text formatting "{}"
  341. /// to indicate fulfilled components of an expression
  342. std::string toString(std::function<std::string(const Value &)> toStr) const
  343. {
  344. LogicalExpressionDetail::Printer<Value> printVisitor(toStr);
  345. return boost::apply_visitor(printVisitor, data);
  346. }
  347. std::string toString(std::function<std::string(const Value &)> toStr, std::function<bool(const Value &)> toBool) const
  348. {
  349. LogicalExpressionDetail::Printer<Value> printVisitor(toStr, toBool);
  350. return boost::apply_visitor(printVisitor, data);
  351. }
  352. JsonNode toJson(std::function<JsonNode(const Value &)> toJson) const
  353. {
  354. LogicalExpressionDetail::Writer<Value> writeVisitor(toJson);
  355. return boost::apply_visitor(writeVisitor, data);
  356. }
  357. template <typename Handler>
  358. void serialize(Handler & h, const int version)
  359. {
  360. h & data;
  361. }
  362. };