1 /* ConditionSet.h 2 Copyright (c) 2014 by Michael Zahniser 3 4 Endless Sky is free software: you can redistribute it and/or modify it under the 5 terms of the GNU General Public License as published by the Free Software 6 Foundation, either version 3 of the License, or (at your option) any later version. 7 8 Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY 9 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 10 PARTICULAR PURPOSE. See the GNU General Public License for more details. 11 */ 12 13 #ifndef CONDITION_SET_H_ 14 #define CONDITION_SET_H_ 15 16 #include <map> 17 #include <string> 18 #include <vector> 19 20 class DataNode; 21 class DataWriter; 22 23 24 25 // A condition set is a collection of operations on the player's set of named 26 // "conditions". This includes "test" operations that just check the values of 27 // those conditions, and other operations that can be "applied" to change the 28 // values. 29 class ConditionSet { 30 public: 31 using Conditions = std::map<std::string, int64_t>; 32 ConditionSet() noexcept = default; 33 // Construct and Load() at the same time. 34 ConditionSet(const DataNode &node); 35 36 // Load a set of conditions from the children of this node. Prints a 37 // warning if an and/or node contains assignment expressions. 38 void Load(const DataNode &node); 39 // Save a set of conditions. 40 void Save(DataWriter &out) const; 41 42 // Check if there are any entries in this set. 43 bool IsEmpty() const; 44 45 // Read a single condition from a data node. 46 void Add(const DataNode &node); 47 bool Add(const std::string &firstToken, const std::string &secondToken); 48 // Add simple conditions having only a single operator. 49 bool Add(const std::string &name, const std::string &op, const std::string &value); 50 // Add complex conditions having multiple operators, including parentheses. 51 bool Add(const std::vector<std::string> &lhs, const std::string &op, const std::vector<std::string> &rhs); 52 53 // Check if the given condition values satisfy this set of expressions. First applies 54 // all assignment expressions to create any temporary conditions, then evaluates. 55 bool Test(const Conditions &conditions) const; 56 // Modify the given set of conditions with this ConditionSet. 57 // (Order of operations is like the order of specification: all sibling 58 // expressions are applied, then any and/or nodes are applied.) 59 void Apply(Conditions &conditions) const; 60 61 62 private: 63 // Compare this set's expressions and the union of created and supplied conditions. 64 bool TestSet(const Conditions &conditions, const Conditions &created) const; 65 // Evaluate this set's assignment expressions and store the result in "created" (for use by TestSet). 66 void TestApply(const Conditions &conditions, Conditions &created) const; 67 68 69 private: 70 // This class represents a single expression involving a condition, 71 // either testing what value it has, or modifying it in some way. 72 class Expression { 73 public: 74 Expression(const std::vector<std::string> &left, const std::string &op, const std::vector<std::string> &right); 75 Expression(const std::string &left, const std::string &op, const std::string &right); 76 77 void Save(DataWriter &out) const; 78 // Convert this expression into a string, for traces. 79 std::string ToString() const; 80 81 // Determine if this Expression instantiated properly. 82 bool IsEmpty() const; 83 84 // Returns the left side of this Expression. 85 std::string Name() const; 86 // True if this Expression performs a comparison and false if it performs an assignment. 87 bool IsTestable() const; 88 89 // Functions to use this expression: 90 bool Test(const Conditions &conditions, const Conditions &created) const; 91 void Apply(Conditions &conditions, Conditions &created) const; 92 void TestApply(const Conditions &conditions, Conditions &created) const; 93 94 95 private: 96 // A SubExpression results from applying operator-precedence parsing to one side of 97 // an Expression. The operators and tokens needed to recreate the given side are 98 // stored, and can be interleaved to restore the original string. Based on them, a 99 // sequence of "Operations" is created for runtime evaluation. 100 class SubExpression { 101 public: 102 SubExpression(const std::vector<std::string> &side); 103 SubExpression(const std::string &side); 104 105 // Interleave tokens and operators to reproduce the initial string. 106 const std::string ToString() const; 107 // Interleave tokens and operators, but do not combine. 108 const std::vector<std::string> ToStrings() const; 109 110 bool IsEmpty() const; 111 112 // Substitute numbers for any string values and then compute the result. 113 int64_t Evaluate(const Conditions &conditions, const Conditions &created) const; 114 115 116 private: 117 void ParseSide(const std::vector<std::string> &side); 118 void GenerateSequence(); 119 bool AddOperation(std::vector<int> &data, size_t &index, const size_t &opIndex); 120 121 122 private: 123 // An Operation has a pointer to its binary function, and the data indices for 124 // its operands. The result is always placed on the back of the data vector. 125 class Operation { 126 public: 127 explicit Operation(const std::string &op, size_t &a, size_t &b); 128 129 int64_t (*fun)(int64_t, int64_t); 130 size_t a; 131 size_t b; 132 }; 133 134 135 private: 136 // Iteration of the sequence vector yields the result. 137 std::vector<Operation> sequence; 138 // The tokens vector converts into a data vector of numeric values during evaluation. 139 std::vector<std::string> tokens; 140 std::vector<std::string> operators; 141 // The number of true (non-parentheses) operators. 142 int operatorCount = 0; 143 }; 144 145 146 private: 147 // String representation of the Expression's binary function. 148 std::string op; 149 // Pointer to a binary function that defines the assignment or 150 // comparison operation to be performed between SubExpressions. 151 int64_t (*fun)(int64_t, int64_t); 152 153 // SubExpressions contain one or more tokens and any number of simple operators. 154 SubExpression left; 155 SubExpression right; 156 }; 157 158 159 private: 160 // Sets of condition tests can contain nested sets of tests. Each set is 161 // either an "and" grouping (meaning every condition must be true to satisfy 162 // it) or an "or" grouping where only one condition needs to be true. 163 bool isOr = false; 164 // If this set contains assignment expressions. If true, the Test() 165 // method must first apply them before testing any conditions. 166 bool hasAssign = false; 167 // Conditions that this set tests or applies. 168 std::vector<Expression> expressions; 169 // Nested sets of conditions to be tested. 170 std::vector<ConditionSet> children; 171 }; 172 173 174 175 #endif 176