LogicalExpression.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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 DLL_LINKAGE ExpressionBase
  9. {
  10. /// Possible logical operations, mostly needed to create different types for boost::variant
  11. enum EOperations
  12. {
  13. ANY_OF,
  14. ALL_OF,
  15. NONE_OF
  16. };
  17. public:
  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 DLL_LINKAGE 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 DLL_LINKAGE 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 DLL_LINKAGE 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. /// Json parser for expressions
  126. template <typename ContainedClass>
  127. class DLL_LINKAGE Reader
  128. {
  129. typedef ExpressionBase<ContainedClass> Base;
  130. std::function<typename Base::Value(const JsonNode &)> classParser;
  131. typename Base::Variant readExpression(const JsonNode & node)
  132. {
  133. assert(!node.Vector().empty());
  134. std::string type = node.Vector()[0].String();
  135. if (type == "anyOf")
  136. return typename Base::OperatorAny(readVector(node));
  137. if (type == "allOf")
  138. return typename Base::OperatorAll(readVector(node));
  139. if (type == "noneOf")
  140. return typename Base::OperatorNone(readVector(node));
  141. return classParser(node);
  142. }
  143. std::vector<typename Base::Variant> readVector(const JsonNode & node)
  144. {
  145. std::vector<typename Base::Variant> ret;
  146. ret.reserve(node.Vector().size()-1);
  147. for (size_t i=1; i < node.Vector().size(); i++)
  148. ret.push_back(readExpression(node.Vector()[i]));
  149. return ret;
  150. }
  151. public:
  152. Reader(std::function<typename Base::Value(const JsonNode &)> classParser):
  153. classParser(classParser)
  154. {}
  155. typename Base::Variant operator ()(const JsonNode & node)
  156. {
  157. return readExpression(node);
  158. }
  159. };
  160. std::string getTextForOperator(std::string operation);
  161. /// Prints expression in human-readable format
  162. template <typename ContainedClass>
  163. class DLL_LINKAGE Printer : public boost::static_visitor<std::string>
  164. {
  165. typedef ExpressionBase<ContainedClass> Base;
  166. std::function<std::string(const typename Base::Value &)> classPrinter;
  167. std::unique_ptr<TestVisitor<ContainedClass>> statusTest;
  168. mutable std::string prefix;
  169. template<typename Operator>
  170. std::string formatString(std::string toFormat, const Operator & expr) const
  171. {
  172. // highlight not fulfilled expressions, if pretty formatting is on
  173. if (statusTest && !(*statusTest)(expr))
  174. return "{" + toFormat + "}";
  175. return toFormat;
  176. }
  177. std::string printExpressionList(const std::vector<typename Base::Variant> & element) const
  178. {
  179. std::string ret;
  180. prefix.push_back('\t');
  181. for (auto & expr : element)
  182. ret += prefix + boost::apply_visitor(*this, expr) + "\n";
  183. prefix.pop_back();
  184. return ret;
  185. }
  186. public:
  187. Printer(std::function<std::string(const typename Base::Value &)> classPrinter):
  188. classPrinter(classPrinter)
  189. {}
  190. Printer(std::function<std::string(const typename Base::Value &)> classPrinter, std::function<bool(const typename Base::Value &)> toBool):
  191. classPrinter(classPrinter),
  192. statusTest(new TestVisitor<ContainedClass>(toBool))
  193. {}
  194. std::string operator()(const typename Base::OperatorAny & element) const
  195. {
  196. return formatString(getTextForOperator("anyOf"), element) + "\n"
  197. + printExpressionList(element.expressions);
  198. }
  199. std::string operator()(const typename Base::OperatorAll & element) const
  200. {
  201. return formatString(getTextForOperator("allOf"), element) + "\n"
  202. + printExpressionList(element.expressions);
  203. }
  204. std::string operator()(const typename Base::OperatorNone & element) const
  205. {
  206. return formatString(getTextForOperator("noneOf"), element) + "\n"
  207. + printExpressionList(element.expressions);
  208. }
  209. std::string operator()(const typename Base::Value & element) const
  210. {
  211. return formatString(classPrinter(element), element);
  212. }
  213. };
  214. }
  215. ///
  216. /// Class for evaluation of logical expressions generated in runtime
  217. ///
  218. template<typename ContainedClass>
  219. class DLL_LINKAGE LogicalExpression
  220. {
  221. typedef LogicalExpressionDetail::ExpressionBase<ContainedClass> Base;
  222. public:
  223. /// Type of values used in expressions, same as ContainedClass
  224. typedef typename Base::Value Value;
  225. /// Operators for use in expressions, all include vectors with operands
  226. typedef typename Base::OperatorAny OperatorAny;
  227. typedef typename Base::OperatorAll OperatorAll;
  228. typedef typename Base::OperatorNone OperatorNone;
  229. /// one expression entry
  230. typedef typename Base::Variant Variant;
  231. private:
  232. Variant data;
  233. public:
  234. /// Base constructor
  235. LogicalExpression()
  236. {}
  237. /// Constructor from variant or (implicitly) from Operator* types
  238. LogicalExpression(const Variant & data):
  239. data(data)
  240. {
  241. }
  242. /// Constructor that receives JsonNode as input and function that can parse Value instances
  243. LogicalExpression(const JsonNode & input, std::function<Value(const JsonNode &)> parser)
  244. {
  245. LogicalExpressionDetail::Reader<Value> reader(parser);
  246. LogicalExpression expr(reader(input));
  247. std::swap(data, expr.data);
  248. }
  249. /// calculates if expression evaluates to "true".
  250. /// Note: empty expressions always return true
  251. bool test(std::function<bool(const Value &)> toBool) const
  252. {
  253. LogicalExpressionDetail::TestVisitor<Value> testVisitor(toBool);
  254. return boost::apply_visitor(testVisitor, data);
  255. }
  256. /// generates list of candidates that can be fulfilled by caller (like AI)
  257. std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
  258. {
  259. LogicalExpressionDetail::CandidatesVisitor<Value> candidateVisitor(toBool);
  260. return boost::apply_visitor(candidateVisitor, data);
  261. }
  262. /// Converts expression in human-readable form
  263. /// Second version will try to do some pretty printing using H3 text formatting "{}"
  264. /// to indicate fulfilled components of an expression
  265. std::string toString(std::function<std::string(const Value &)> toStr) const
  266. {
  267. LogicalExpressionDetail::Printer<Value> printVisitor(toStr);
  268. return boost::apply_visitor(printVisitor, data);
  269. }
  270. std::string toString(std::function<std::string(const Value &)> toStr, std::function<bool(const Value &)> toBool) const
  271. {
  272. LogicalExpressionDetail::Printer<Value> printVisitor(toStr, toBool);
  273. return boost::apply_visitor(printVisitor, data);
  274. }
  275. template <typename Handler>
  276. void serialize(Handler & h, const int version)
  277. {
  278. h & data;
  279. }
  280. };