khanat-opennel-code/code/nel/include/nel/ligo/primitive_utils.h
acemtp@users.sourceforge.net d5c601ffa5 initial version
2010-05-06 02:08:41 +02:00

371 lines
9.9 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef PRIMITIVE_UTIL_H
#define PRIMITIVE_UTIL_H
#include "primitive.h"
#include "nel/misc/i_xml.h"
#include "nel/misc/o_xml.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include <vector>
#include <string>
namespace NLLIGO
{
typedef std::vector<IPrimitive*> TPrimitiveSet;
/** Default predicate for primitive enumerator.
* This predicate test the class name of each primitive against a
* given class name.
*/
struct TPrimitiveClassPredicate : public std::unary_function<IPrimitive*, bool>
{
TPrimitiveClassPredicate(const std::string &className)
: ClassName(className)
{}
bool operator () (const IPrimitive *prim) const
{
std::string *s;
if (prim->getPropertyByName("class", s) && *s == ClassName)
return true;
return false;
}
/// The primitive class name to check
const std::string ClassName;
};
/** Predicate for primitive enumerator.
* This predicate test the name of each primitive against a
* given name.
*/
struct TPrimitiveNamePredicate
{
TPrimitiveNamePredicate(const std::string &name)
: Name(name)
{}
bool operator () (const IPrimitive *prim) const
{
std::string *s;
if (prim->getPropertyByName("name", s) && *s == Name)
return true;
return false;
}
/// The primitive name to check
const std::string Name;
};
/** Predicate for primitive enumerator.
* This predicate test the class name and name of the primitive.
*/
struct TPrimitiveClassAndNamePredicate
{
TPrimitiveClassAndNamePredicate(const std::string &className, const std::string &name)
: ClassName(className),
Name(name)
{}
bool operator () (const IPrimitive *prim) const
{
std::string *s;
if (prim->getPropertyByName("class", s) && *s == ClassName)
{
if (prim->getPropertyByName("name", s) && *s == Name)
return true;
}
return false;
}
/// The primitive class name to check
const std::string ClassName;
/// The primitive name to check
const std::string Name;
};
/** Predicate for primitive enumerator.
* This predicate test the string value of a given property
*/
struct TPrimitivePropertyPredicate
{
TPrimitivePropertyPredicate(const std::string &propName, const std::string &value)
: PropName(propName), PropValue(value)
{}
bool operator () (const IPrimitive *prim) const
{
std::string *s;
if (prim->getPropertyByName(PropName.c_str(), s) && *s == PropValue)
return true;
return false;
}
/// The property name
const std::string PropName;
/// The property value
const std::string PropValue;
};
/** The primitive enumerator class is used to iterate over primitive node that
* match a given predicate.
* The primitive are tested recursively starting at an arbitrary node in the
* primitive tree.
* Application code just need to call getNextMatch until it return NULL indicating
* there is no more node that match the predicate.
*/
template <class Pred = TPrimitiveClassPredicate>
class CPrimitiveEnumerator
{
public:
/** Construct a primitive enumerator.
* startPrim is the primitive where the enumeration start. Even if the startPrimitive
* is not at the root of the primitive tree, the enumerator will not
* try to parse the parent of startPrim.
* predicate is the functor predicate. Each node is tested against the bool operator()(IPrimitive *)
* method of the predicate. If the predicate return true, then the node is returned by getNextMatch.
*/
CPrimitiveEnumerator(IPrimitive *startPrim, Pred &predicate)
: _StartPrim(startPrim),
_Predicate(predicate),
_CurrentPrim(startPrim)
{
// mark the root node as non checked
_IndexStack.push_back(~0);
}
/** Each call to this method will return a primitive pointer that match
* the predicate functor.
* Return NULL when there is no more primitive matching the predicate.
*/
IPrimitive *getNextMatch()
{
while (!_IndexStack.empty())
{
if (_IndexStack.back() == ~0)
{
_IndexStack.back() = 0;
// we need to check the current node.
if (_Predicate(_CurrentPrim))
{
// this one match !
return _CurrentPrim;
}
}
if (_IndexStack.back() < _CurrentPrim->getNumChildren())
{
IPrimitive *child;
if (_CurrentPrim->getChild(child, _IndexStack.back()++))
{
// go down into this node
_IndexStack.push_back(~0);
_CurrentPrim = child;
}
}
else
{
// no more child to test, pop one level
_IndexStack.pop_back();
_CurrentPrim = _CurrentPrim->getParent();
}
}
// no more match
return NULL;
}
private:
/// The root primitive for enumeration
IPrimitive *_StartPrim;
/// The predicate functor
Pred _Predicate;
/// The current primitive
IPrimitive *_CurrentPrim;
/// for each recursion level, keep the index of the currently explored child.
std::vector<uint> _IndexStack;
};
/** Build a primitive set that match the predicate
* This class makes use of the CPrimitiveEnumerator class to iterate
* on each valid node and fill the result primitive set.
*/
template <class Pred>
class CPrimitiveSet
{
public:
void buildSet(IPrimitive *startPrimitive, Pred &predicate, TPrimitiveSet &result)
{
CPrimitiveEnumerator<Pred> enumerator(startPrimitive, predicate);
IPrimitive *p;
while ((p = enumerator.getNextMatch()) != NULL)
result.push_back(p);
}
};
/** Filter a primitive set against a predicate.
* Useful to refine a primitive set with another predicate.
*/
template <class Pred>
class CPrimitiveSetFilter
{
public:
void filterSet(const std::vector<IPrimitive*> &source, Pred &predicate, TPrimitiveSet &result)
{
std::vector<IPrimitive*>::const_iterator first(source.begin()), last(source.end());
for (; first != last; ++first)
{
if (predicate(*first))
result.push_back(*first);
}
}
};
/** Utility function that load an xml primitive file into a CPrimitives object.
* This function deal with file IO and XML parsing call.
* Return false if the loading fail for some reason, true otherwise.
*/
inline bool loadXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName, CLigoConfig &ligoConfig)
{
try
{
NLMISC::CIFile fileIn(fileName);
NLMISC::CIXml xmlIn;
xmlIn.init (fileIn);
// Read it
return primDoc.read (xmlIn.getRootNode (), NLMISC::CFile::getFilename(fileName).c_str(), ligoConfig);
}
catch(NLMISC::Exception e)
{
nlwarning("Error reading input file '%s': '%s'", fileName.c_str(), e.what());
return false;
}
}
/** Utility function that save a CPrimitives object into an xml file.
* This function deal with file IO and XML parsing call.
* Return false if the saving fail for some reason, true otherwise.
*/
inline bool saveXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName)
{
try
{
NLMISC::COFile fileOut(fileName);
// xmlDocPtr xmlDoc = xmlNewDoc((xmlChar*)("1.0"));;
NLMISC::COXml xmlOut;
xmlOut.init (&fileOut);
// NLMISC::CIXml xmlOut;
// xmlOut.init (fileOut);
// Read it
primDoc.write(xmlOut.getDocument(), fileName.c_str());
xmlOut.flush ();
fileOut.close();
return true;
// return xmlSaveFile(fileName.c_str(), xmlDoc) != -1;
}
catch(NLMISC::Exception e)
{
nlwarning("Error writing output file '%s': '%s'", fileName.c_str(), e.what());
return false;
}
}
/** Utility function to look for the first child of a primitive node that
* match the predicate.
* Return NULL if none of the child match the predicate.
* There is no way to get the next matching child using this function,
* you must use filterPrimitiveChilds to do this.
*/
template <class Pred>
IPrimitive *getPrimitiveChild(IPrimitive *parent, Pred &predicate)
{
for (uint i=0; i<parent->getNumChildren(); ++i)
{
IPrimitive *child;
if (parent->getChild(child, i) && predicate(child))
{
return child;
}
}
return NULL;
}
/** Utility function to look for the first parent of a primitive node that
* match the predicate.
* Return NULL if none of the parent match the predicate.
*/
template <class Pred>
IPrimitive *getPrimitiveParent(IPrimitive *prim, Pred &predicate)
{
IPrimitive *parent = prim->getParent();
while (parent)
{
if (predicate(parent))
return parent;
parent = parent->getParent();
}
return NULL;
}
/** Utility function that fill a primitive set with all the child nodes
* that match the predicate.
*/
template <class Pred>
void filterPrimitiveChilds(IPrimitive *parent, Pred &predicate, TPrimitiveSet &result)
{
for (uint i=0; i<parent->getNumChildren(); ++i)
{
IPrimitive *child;
if (parent->getChild(child, i) && predicate(child))
result.push_back(child);
}
}
/** Build a string that represent the path to a node
* Note that the reverse operation does not guaranty to
* return a unique node because there is no name
* uniqueness constraint in the primitive system.
*/
std::string buildPrimPath(const IPrimitive *prim);
/** Return a set of primitive that match a given path*/
void selectPrimByPath(IPrimitive *rootNode, const std::string &path, TPrimitiveSet &result);
} // namespace NLLIGO
#endif // #define PRIMITIVE_UTIL_H