added combined conditions, fix for Condition::create()

This commit is contained in:
john30
2015-10-18 10:16:29 +02:00
parent 9ccfc72dca
commit 0492a4db1e
2 changed files with 195 additions and 64 deletions
+93 -37
View File
@@ -628,23 +628,23 @@ string strtolower(const string& str)
}
result_t Condition::create(vector<string>::iterator& it, const vector<string>::iterator end, Condition*& returnValue)
result_t Condition::create(vector<string>::iterator& it, const vector<string>::iterator end, SimpleCondition*& returnValue)
{
if (it==end)
// name,circuit,messagename,[comment],[fieldname],[ZZ],values (name already skipped by caller)
if (it+6>end) {
it = end; // for error reporting
return RESULT_ERR_EOF;
string circuit = *(it++);
}
string circuit = *(it++); // circuit
if (circuit.length()==0)
return RESULT_ERR_INVALID_ARG;
if (it==end)
return RESULT_ERR_EOF;
string name = *(it++);
string name = *(it++); // messagename
if (name.length()==0)
return RESULT_ERR_INVALID_ARG;
if (it==end)
return RESULT_ERR_EOF;
string field = *(it++);
it++; // comment
string field = *(it++); // fieldname
string zz = *(it++); // ZZ
//TODO use ZZ as optional param for ident, create ident message if necessary
istringstream stream(*(it++));
string str;
vector<unsigned int> valueRanges;
@@ -660,7 +660,7 @@ result_t Condition::create(vector<string>::iterator& it, const vector<string>::i
if (upto)
valueRanges.push_back(0);
bool inclusive = str[1]=='=';
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, 0, UINT_MAX, result);
unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1, inclusive?UINT_MAX:(UINT_MAX-1), result);
if (result!=RESULT_OK)
return result;
valueRanges.push_back(inclusive ? val : (val+(upto?-1:1)));
@@ -681,19 +681,28 @@ result_t Condition::create(vector<string>::iterator& it, const vector<string>::i
if (result!=RESULT_OK)
return result;
valueRanges.push_back(val);
if (pos>0)
if (pos==0)
valueRanges.push_back(val); // single value
}
}
if (valueRanges.empty())
return RESULT_ERR_INVALID_LIST;
returnValue = new Condition(circuit, name, field, valueRanges);
returnValue = new SimpleCondition(circuit, name, field, valueRanges);
return RESULT_OK;
}
result_t Condition::resolve(MessageMap* messages, ostringstream& errorMessage)
CombinedCondition* SimpleCondition::combineAnd(Condition* other)
{
CombinedCondition* ret = new CombinedCondition();
return ret->combineAnd(this)->combineAnd(other);
}
result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage)
{
if (m_message!=NULL)
return RESULT_OK; // already resolved
Message* message = messages->find(m_circuit, m_name, false);
if (!message)
message = messages->find(m_circuit, m_name, false, true);
@@ -708,10 +717,12 @@ result_t Condition::resolve(MessageMap* messages, ostringstream& errorMessage)
}
}
m_message = message;
message->setUsedByCondition();
messages->addPollMessage(message, true);
return RESULT_OK;
}
bool Condition::isTrue()
bool SimpleCondition::isTrue()
{
if (!m_message)
return false;
@@ -734,6 +745,27 @@ bool Condition::isTrue()
}
result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage)
{
for (vector<Condition*>::iterator it = m_conditions.begin(); it!=m_conditions.end(); it++) {
Condition* condition = *it;
result_t ret = condition->resolve(messages, errorMessage);
if (ret!=RESULT_OK)
return ret;
}
return RESULT_OK;
}
bool CombinedCondition::isTrue()
{
for (vector<Condition*>::iterator it = m_conditions.begin(); it!=m_conditions.end(); it++) {
if (!(*it)->isTrue())
return false;
}
return true;
}
result_t MessageMap::add(Message* message)
{
unsigned long long key = message->getKey();
@@ -802,7 +834,7 @@ result_t MessageMap::addDefaultFromFile(vector< vector<string> >& defaults, vect
if (row.size()>1 && defaultCircuit.length()>0 && row[1].length()==0)
row[1] = defaultCircuit; // set default circuit
Condition* condition = NULL;
SimpleCondition* condition = NULL;
result_t result = Condition::create(++begin, row.end(), condition);
if (result!=RESULT_OK) {
if (condition)
@@ -811,7 +843,6 @@ result_t MessageMap::addDefaultFromFile(vector< vector<string> >& defaults, vect
}
if (!condition)
return RESULT_ERR_INVALID_ARG;
m_conditions[key] = condition;
return RESULT_OK;
}
@@ -825,22 +856,43 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
vector<string>::iterator restart = begin;
Condition* condition = NULL;
string types = *restart;
if (types.length()>0 && types[0]=='[') {
// condition
size_t pos = types.find(']');
if (pos!=string::npos) {
string key = filename+":"+types.substr(1, pos-1);
map<string, Condition*>::iterator it = m_conditions.find(key); // TODO add support for global conditions without filename
if (it==m_conditions.end())
return RESULT_ERR_NOTFOUND;
size_t pos;
if (types.length()>0 && types[0]=='[' && (pos=types.find_last_of(']'))!=string::npos) {
// check if combined or simple condition is already known
const string combinedkey = filename+":"+types.substr(1, pos-1);
map<string, Condition*>::iterator it = m_conditions.find(combinedkey);
if (it!=m_conditions.end()) {
condition = it->second;
types = types.substr(pos+1);
} else {
bool store = false;
while ((pos=types.find(']'))!=string::npos) {
// simple condition
string key = filename+":"+types.substr(1, pos-1);
map<string, Condition*>::iterator it = m_conditions.find(key);
if (it==m_conditions.end())
return RESULT_ERR_NOTFOUND;
if (condition) {
condition = condition->combineAnd(it->second);
store = true;
} else
condition = it->second;
types = types.substr(pos+1);
if (types.length()==0 || types[0]!='[')
break;
}
if (store) {
m_conditions[combinedkey] = condition; // store combined condition
}
}
}
if (types.length() == 0)
types.append("r");
result_t result = RESULT_ERR_EOF;
else if (types.find(']')!=string::npos)
return RESULT_ERR_INVALID_ARG;
result_t result = RESULT_ERR_EOF;
istringstream stream(types);
string type;
vector<Message*> messages;
@@ -868,7 +920,7 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
return result;
}
result_t MessageMap::resolveConditions(string& errorMessage, bool verbose) {
result_t MessageMap::resolveConditions(bool verbose) {
result_t overallResult = RESULT_OK;
ostringstream error;
for (map<string, Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
@@ -879,16 +931,12 @@ result_t MessageMap::resolveConditions(string& errorMessage, bool verbose) {
overallResult = result;
error << ", ";
} else {
errorMessage = error.str();
m_lastError = error.str();
return result;
}
} else {
Message* message = condition->getMessage();
message->setUsedByCondition();
addPollMessage(message, true);
}
}
errorMessage = error.str();
m_lastError = error.str();
return overallResult;
}
@@ -1067,9 +1115,17 @@ void MessageMap::clear()
m_pollMessages.pop();
}
// free message instances
for (map<string, vector<Message*> >::iterator it = m_messagesByName.begin(); it != m_messagesByName.end(); it++) {
if (it->first[0] != '-') // avoid double free: instances stored multiple times have a key starting with "-"
it->second.clear();
for (map<string, vector<Message*> >::iterator mit = m_messagesByName.begin(); mit != m_messagesByName.end(); mit++) {
if (mit->first[0] != '-') { // avoid double free: instances stored multiple times have a key starting with "-"
vector<Message*> messages = mit->second;
for (vector<Message*>::iterator it = messages.begin(); it != messages.end(); it++)
delete *it;
messages.clear();
}
}
// free condition instances
for (map<string, Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
delete it->second;
}
// clear messages by name
m_messageCount = 0;
+102 -27
View File
@@ -33,6 +33,8 @@
using namespace std;
class Condition;
class SimpleCondition;
class CombinedCondition;
class MessageMap;
/**
@@ -420,7 +422,7 @@ public:
/**
* Holds a reference to a @a Message as condition for another @a Message.
* An abstract condition based on the value of one or more @a Message instances.
*/
class Condition
{
@@ -428,16 +430,9 @@ public:
/**
* Construct a new instance.
* @param circuit the circuit name.
* @param name the message name.
* @param field the field name.
* @param valueRanges the valid value ranges (pairs of from/to inclusive).
*/
Condition(const string circuit, const string name, const string field, const vector<unsigned int> valueRanges)
: m_circuit(circuit), m_name(name), m_field(field), m_valueRanges(valueRanges),
m_message(NULL), m_lastCheckTime(0), m_isTrue(false) {
// cout << "condition " << circuit << " " << name << " " << field << ":" << static_cast<unsigned>(valueRanges.size()) << endl;
}
Condition()
: m_lastCheckTime(0), m_isTrue(false) { }
/**
* Destructor.
@@ -451,27 +446,79 @@ public:
* @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code.
*/
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end, Condition*& returnValue);
static result_t create(vector<string>::iterator& it, const vector<string>::iterator end, SimpleCondition*& returnValue);
/**
* Resolve the referred @a Message instance and field index.
* @param messages the @a MessageMap instance for resolving the referred @a Message.
* Combine this condition with another instance using a logical and.
* @param other the @a Condition to combine with.
*/
virtual CombinedCondition* combineAnd(Condition* other) = 0;
/**
* Resolve the referred @a Message instance(s) and field index(es).
* @param messages the @a MessageMap instance for resolving.
* @param errorMessage a @a ostringstream to which to add optional error messages.
* @return @a RESULT_OK on success, or an error code.
*/
result_t resolve(MessageMap* messages, ostringstream& errorMessage);
/**
* Get the resolved @a Message instance
* @return the resolved @a Message instance, or NULL.
*/
Message* getMessage() { return m_message; }
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage) = 0;
/**
* Check and return whether this condition is fulfilled.
* @return whether this condition is fulfilled.
*/
bool isTrue();
virtual bool isTrue() = 0;
protected:
/** the system time when the condition was last checked, 0 for never. */
time_t m_lastCheckTime;
/** whether the condition was @a true during the last check. */
bool m_isTrue;
};
/**
* A simple condition based on the value of one @a Message.
*/
class SimpleCondition : public Condition
{
public:
/**
* Construct a new instance.
* @param circuit the circuit name.
* @param name the message name.
* @param field the field name.
* @param valueRanges the valid value ranges (pairs of from/to inclusive).
*/
SimpleCondition(const string circuit, const string name, const string field, const vector<unsigned int> valueRanges)
: Condition(),
m_circuit(circuit), m_name(name), m_field(field), m_valueRanges(valueRanges),
m_message(NULL) { }
/**
* Destructor.
*/
virtual ~SimpleCondition() {}
// @copydoc
virtual CombinedCondition* combineAnd(Condition* other);
/**
* Resolve the referred @a Message instance(s) and field index(es).
* @param messages the @a MessageMap instance for resolving.
* @param errorMessage a @a ostringstream to which to add optional error messages.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage);
/**
* Check and return whether this condition is fulfilled.
* @return whether this condition is fulfilled.
*/
virtual bool isTrue();
private:
@@ -490,11 +537,40 @@ private:
/** the resolved @a Message instance, or NULL. */
Message* m_message;
/** the system time when the condition was last checked, 0 for never. */
time_t m_lastCheckTime;
};
/** whether the condition was @a true during the last check. */
bool m_isTrue;
/**
* A condition combining two or more @a SimpleCondition instances with a logical and.
*/
class CombinedCondition : public Condition
{
public:
/**
* Construct a new instance.
*/
CombinedCondition()
: Condition() { }
/**
* Destructor.
*/
virtual ~CombinedCondition() {}
// @copydoc
virtual CombinedCondition* combineAnd(Condition* other) { m_conditions.push_back(other); return this; }
// @copydoc
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage);
// @copydoc
virtual bool isTrue();
private:
/** the @a Condition instances used. */
vector<Condition*> m_conditions;
};
@@ -537,11 +613,10 @@ public:
/**
* Resolve all @a Condition instances.
* @param errorMessage a @a string reference to which to add an optional error message.
* @param verbose whether to verbosely add all problems to the error message.
* @return @a RESULT_OK on success, or an error code.
*/
result_t resolveConditions(string& errorMessage, bool verbose=false);
result_t resolveConditions(bool verbose=false);
/**
* Find the @a Message instance for the specified circuit and name.