X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fprops.cxx;h=3d63758e143707fe38b100728e8ac6f7534f2e99;hb=284a9e061280535de01b0e3f36a9b85ef8178e61;hp=6730ef132876cf120b86d57d02e569d3724a9069;hpb=a25e859fa773c9463e4bec042b8d0b39041c29ad;p=simgear.git diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index 6730ef13..3d63758e 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -16,12 +16,15 @@ #include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -91,7 +94,7 @@ public: template inline Range -parse_name (const Range &path) +parse_name (const SGPropertyNode *node, const Range &path) { typename Range::iterator i = path.begin(); typename Range::iterator max = path.end(); @@ -115,15 +118,24 @@ parse_name (const Range &path) } else if (*i == '[' || *i == '/') { break; } else { - throw string("name may contain only ._- and alphanumeric characters"); + string err = "'"; + err.push_back(*i); + err.append("' found in propertyname after '"+node->getNameString()+"'"); + err.append("\nname may contain only ._- and alphanumeric characters"); + throw err; } i++; } } else { - if (path.begin() == i) - throw string("name must begin with alpha or '_'"); + if (path.begin() == i) { + string err = "'"; + err.push_back(*i); + err.append("' found in propertyname after '"+node->getNameString()+"'"); + err.append("\nname must begin with alpha or '_'"); + throw err; + } } return Range(path.begin(), i); } @@ -265,7 +277,7 @@ find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create, // Empty name at this point is empty, not root. if (token.empty()) return find_node_aux(current, ++itr, create, last_index); - Range name = parse_name(token); + Range name = parse_name(current, token); if (equals(name, ".")) return find_node_aux(current, ++itr, create, last_index); if (equals(name, "..")) { @@ -1024,17 +1036,22 @@ SGPropertyNode::getDisplayName (bool simplify) const } -const char * +string SGPropertyNode::getPath (bool simplify) const { - // Calculate the complete path only once. - if (_parent != 0 && _path.empty()) { - _path = _parent->getPath(simplify); - _path += '/'; - _path += getDisplayName(simplify); + typedef std::vector PList; + PList pathList; + for (const SGPropertyNode* node = this; node->_parent; node = node->_parent) + pathList.push_back(node); + string result; + for (PList::reverse_iterator itr = pathList.rbegin(), + rend = pathList.rend(); + itr != rend; + ++itr) { + result += '/'; + result += (*itr)->getDisplayName(simplify); } - - return _path.c_str(); + return result; } props::Type @@ -2379,6 +2396,146 @@ std::istream& readFrom(std::istream& stream, SGVec4d& result) } return stream; } + +namespace +{ +bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs) +{ + props::Type ltype = lhs.getType(); + props::Type rtype = rhs.getType(); + if (ltype != rtype) + return false; + switch (ltype) { + case props::NONE: + return true; + case props::ALIAS: + return false; // XXX Should we look in aliases? + case props::BOOL: + return lhs.getValue() == rhs.getValue(); + case props::INT: + return lhs.getValue() == rhs.getValue(); + case props::LONG: + return lhs.getValue() == rhs.getValue(); + case props::FLOAT: + return lhs.getValue() == rhs.getValue(); + case props::DOUBLE: + return lhs.getValue() == rhs.getValue(); + case props::STRING: + case props::UNSPECIFIED: + return !strcmp(lhs.getStringValue(), rhs.getStringValue()); + case props::VEC3D: + return lhs.getValue() == rhs.getValue(); + case props::VEC4D: + return lhs.getValue() == rhs.getValue(); + default: + return false; + } +} +} +} + +bool SGPropertyNode::compare(const SGPropertyNode& lhs, + const SGPropertyNode& rhs) +{ + if (&lhs == &rhs) + return true; + int lhsChildren = lhs.nChildren(); + int rhsChildren = rhs.nChildren(); + if (lhsChildren != rhsChildren) + return false; + if (lhsChildren == 0) + return compareNodeValue(lhs, rhs); + for (size_t i = 0; i < lhs._children.size(); ++i) { + const SGPropertyNode* lchild = lhs._children[i]; + const SGPropertyNode* rchild = rhs._children[i]; + // I'm guessing that the nodes will usually be in the same + // order. + if (lchild->getIndex() != rchild->getIndex() + || lchild->getNameString() != rchild->getNameString()) { + rchild = 0; + for (PropertyList::const_iterator itr = rhs._children.begin(), + end = rhs._children.end(); + itr != end; + ++itr) + if (lchild->getIndex() == (*itr)->getIndex() + && lchild->getNameString() == (*itr)->getNameString()) { + rchild = *itr; + break; + } + if (!rchild) + return false; + } + if (!compare(*lchild, *rchild)) + return false; + } + return true; +} + +struct PropertyPlaceLess { + typedef bool result_type; + bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const + { + int comp = lhs->getNameString().compare(rhs->getNameString()); + if (comp == 0) + return lhs->getIndex() < rhs->getIndex(); + else + return comp < 0; + } +}; + +size_t hash_value(const SGPropertyNode& node) +{ + using namespace boost; + + if (node.nChildren() == 0) { + switch (node.getType()) { + case props::NONE: + return 0; + + case props::BOOL: + return hash_value(node.getValue()); + case props::INT: + return hash_value(node.getValue()); + case props::LONG: + return hash_value(node.getValue()); + case props::FLOAT: + return hash_value(node.getValue()); + case props::DOUBLE: + return hash_value(node.getValue()); + case props::STRING: + case props::UNSPECIFIED: + { + const char *val = node.getStringValue(); + return hash_range(val, val + strlen(val)); + } + case props::VEC3D: + { + const SGVec3d val = node.getValue(); + return hash_range(&val[0], &val[3]); + } + case props::VEC4D: + { + const SGVec4d val = node.getValue(); + return hash_range(&val[0], &val[4]); + } + case props::ALIAS: // XXX Should we look in aliases? + default: + return 0; + } + } else { + size_t seed = 0; + PropertyList children(node._children.begin(), node._children.end()); + sort(children.begin(), children.end(), PropertyPlaceLess()); + for (PropertyList::const_iterator itr = children.begin(), + end = children.end(); + itr != end; + ++itr) { + hash_combine(seed, (*itr)->_name); + hash_combine(seed, (*itr)->_index); + hash_combine(seed, hash_value(**itr)); + } + return seed; + } } // end of props.cxx