OMG, what was all this about? OK... this cant possibly work this way. At least we need to trim after splitting the attributes. But this is not enough, we want the value, which implies to make the type flexible (since we cant return a const& to a substring extracted on-the-fly)
367 lines
9.1 KiB
C++
367 lines
9.1 KiB
C++
/*
|
|
UTIL.hpp - collection of small helper functions used "everywhere"
|
|
|
|
Copyright (C) Lumiera.org
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
|
#ifndef LIB_UTIL_H
|
|
#define LIB_UTIL_H
|
|
|
|
#include "include/limits.h"
|
|
#include "lib/hash-standard.hpp"
|
|
|
|
#include <set>
|
|
#include <string>
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
namespace util {
|
|
|
|
using std::string;
|
|
|
|
|
|
template <class NUM>
|
|
inline int
|
|
sgn (NUM n)
|
|
{
|
|
return (n==0)? 0 :((n<0)? -1:+1 );
|
|
}
|
|
|
|
template <class N1, class N2>
|
|
inline N1
|
|
min (N1 n1, N2 n2)
|
|
{
|
|
return n2 < n1? N1(n2) : n1;
|
|
}
|
|
|
|
template <class N1, class N2>
|
|
inline N1
|
|
max (N1 n1, N2 n2)
|
|
{
|
|
return n1 < n2? N1(n2) : n1;
|
|
}
|
|
|
|
/** cut a numeric value to be >=0 */
|
|
template <typename NUM>
|
|
inline NUM
|
|
noneg (NUM val)
|
|
{
|
|
return (0<val? val : 0);
|
|
}
|
|
|
|
/** force a numeric to be within bounds, inclusively */
|
|
template <typename NUM, typename NB>
|
|
inline NUM
|
|
limited (NB lowerBound, NUM val, NB upperBound)
|
|
{
|
|
return min ( max (val, lowerBound)
|
|
, upperBound);
|
|
}
|
|
|
|
/** positive integral number from textual representation
|
|
* @return always a number, 0 in case of unparseable text,
|
|
* limited to 0 <= num <= LUMIERA_MAX_ORDINAL_NUMBER */
|
|
inline uint
|
|
uNum (const char* pCStr)
|
|
{
|
|
if (!pCStr) return 0;
|
|
int parsedNumber(std::atoi (pCStr));
|
|
return limited (0, parsedNumber, LUMIERA_MAX_ORDINAL_NUMBER);
|
|
}
|
|
|
|
inline int
|
|
sNum (const char* pCStr)
|
|
{
|
|
if (!pCStr) return 0;
|
|
int parsedNumber(std::atoi (pCStr));
|
|
return limited (-LUMIERA_MAX_ORDINAL_NUMBER, parsedNumber, LUMIERA_MAX_ORDINAL_NUMBER);
|
|
}
|
|
|
|
inline uint
|
|
uNum (string const& spec)
|
|
{
|
|
return uNum (spec.c_str());
|
|
}
|
|
|
|
inline int
|
|
sNum (string const& spec)
|
|
{
|
|
return sNum (spec.c_str());
|
|
}
|
|
|
|
|
|
|
|
/* ======== generic empty check ========= */
|
|
|
|
/** a family of util functions providing a "no value whatsoever" test.
|
|
Works on strings and all STL containers, includes NULL test for pointers */
|
|
template <class CONT>
|
|
inline bool
|
|
isnil (const CONT& container)
|
|
{
|
|
return container.empty();
|
|
}
|
|
|
|
template <class CONT>
|
|
inline bool
|
|
isnil (const CONT* pContainer)
|
|
{
|
|
return !pContainer || pContainer->empty();
|
|
}
|
|
|
|
template <class CONT>
|
|
inline bool
|
|
isnil (CONT* pContainer)
|
|
{
|
|
return !pContainer || pContainer->empty();
|
|
}
|
|
|
|
inline bool
|
|
isnil (const char* pCStr)
|
|
{
|
|
return !pCStr || !(*pCStr);
|
|
}
|
|
|
|
|
|
|
|
/** check if string starts with a given prefix */
|
|
inline bool
|
|
startsWith (string const& str, string const& prefix)
|
|
{
|
|
return 0 == str.rfind(prefix, 0);
|
|
}
|
|
|
|
inline bool
|
|
startsWith (string const& str, const char* prefix)
|
|
{
|
|
return 0 == str.rfind(prefix, 0);
|
|
}
|
|
|
|
|
|
/** shortcut for containment test on a map */
|
|
template <typename MAP>
|
|
inline bool
|
|
contains (MAP& map, typename MAP::key_type const& key)
|
|
{
|
|
return map.find(key) != map.end();
|
|
}
|
|
|
|
/** shortcut for set value containment test */
|
|
template <typename T>
|
|
inline bool
|
|
contains (std::set<T>& set, T const& val)
|
|
{
|
|
return set.end() != set.find (val);
|
|
}
|
|
|
|
/** shortcut for string value containment test */
|
|
template <typename T>
|
|
inline bool
|
|
contains (std::string const& str, const T& val)
|
|
{
|
|
return str.find (val) != std::string::npos;
|
|
}
|
|
|
|
/** shortcut for brute-force containment test
|
|
* in any sequential container */
|
|
template <typename SEQ>
|
|
inline bool
|
|
contains (SEQ const& cont, typename SEQ::const_reference val)
|
|
{
|
|
typename SEQ::const_iterator begin = cont.begin();
|
|
typename SEQ::const_iterator end = cont.end();
|
|
|
|
return end != std::find(begin,end, val);
|
|
}
|
|
|
|
/** fetch value from a Map, or return a default if not found */
|
|
template <typename MAP>
|
|
inline typename MAP::mapped_type
|
|
getValue_or_default (MAP& map, typename MAP::key_type const& key
|
|
, typename MAP::mapped_type defaultVal)
|
|
{
|
|
typename MAP::const_iterator pos = map.find (key);
|
|
if (pos != map.end())
|
|
return pos->second;
|
|
else
|
|
return defaultVal;
|
|
}
|
|
|
|
/** expose a reference to a map entry, with fall-back to some default object
|
|
* @note exposing a const reference; especially the default needs to reside
|
|
* somewhere at a safe storage location.
|
|
* @see lib::NullValue
|
|
*/
|
|
template <typename MAP>
|
|
inline typename MAP::mapped_type const &
|
|
access_or_default (MAP& map, typename MAP::key_type const& key
|
|
, typename MAP::mapped_type const& refDefault)
|
|
{
|
|
typename MAP::const_iterator pos = map.find (key);
|
|
if (pos != map.end())
|
|
return pos->second;
|
|
else
|
|
return refDefault;
|
|
}
|
|
|
|
/** shortcut for removing all copies of an Element
|
|
* in any sequential collection */
|
|
template <typename SEQ>
|
|
inline typename SEQ::iterator
|
|
removeall (SEQ& coll, typename SEQ::value_type& val)
|
|
{
|
|
typename SEQ::iterator collEnd = coll.end();
|
|
return coll.erase (std::remove (coll.begin(), collEnd, val),
|
|
collEnd
|
|
);
|
|
}
|
|
|
|
|
|
/** remove all elements fulfilling a given predicate
|
|
* from a (sorted) set.
|
|
* @return true if anything has been removed. */
|
|
template<class SET, typename PRD>
|
|
bool remove_if (SET& set, PRD test)
|
|
{
|
|
typedef typename SET::iterator Itor;
|
|
bool found = false;
|
|
Itor end = set.end();
|
|
Itor begin = set.begin();
|
|
Itor pos = begin;
|
|
while (pos!=end)
|
|
{
|
|
if (!test (*pos)) ++pos;
|
|
else
|
|
{
|
|
found = true;
|
|
if (pos==begin)
|
|
{
|
|
set.erase(pos);
|
|
pos = begin = set.begin();
|
|
}
|
|
else
|
|
{
|
|
set.erase(pos--);
|
|
++pos;
|
|
}
|
|
end = set.end();
|
|
} }
|
|
return found;
|
|
}
|
|
|
|
|
|
/** shortcut to save some typing when having to define
|
|
* const and non-const variants of member functions
|
|
*/
|
|
template<class OBJ>
|
|
OBJ*
|
|
unConst (const OBJ* o)
|
|
{
|
|
return const_cast<OBJ*> (o);
|
|
}
|
|
|
|
template<class OBJ>
|
|
OBJ&
|
|
unConst (OBJ const& ro)
|
|
{
|
|
return const_cast<OBJ&> (ro);
|
|
}
|
|
|
|
|
|
/** compare plain object identity,
|
|
* bypassing any custom comparison operators.
|
|
*/
|
|
template<class A, class B>
|
|
inline bool
|
|
isSameObject (A const& a, B const& b)
|
|
{
|
|
return static_cast<const void*> (&a)
|
|
== static_cast<const void*> (&b);
|
|
}
|
|
|
|
|
|
|
|
|
|
/** produce an identifier based on the given string.
|
|
* remove non-standard-chars, reduce sequences of punctuation
|
|
* and whitespace to single underscores. The sanitised string
|
|
* will start with an alphanumeric character.
|
|
*
|
|
* @par Example Conversions
|
|
\verbatim
|
|
"Word" --> 'Word'
|
|
"a Sentence" --> 'a_Sentence'
|
|
"trailing Withespace \t \n" --> 'trailing_Withespace'
|
|
"with a lot \nof Whitespace" --> 'with_a_lot_of_Whitespace'
|
|
"with\"much (punctuation)[]!" --> 'withmuch_(punctuation)'
|
|
"§&Ω%€ leading garbage" --> 'leading_garbage'
|
|
"mixed Ω garbage" --> 'mixed_garbage'
|
|
"Bääääh!!" --> 'Bh'
|
|
\endverbatim
|
|
* @see sanitised-identifier-test.cpp
|
|
*/
|
|
string sanitise (string const& org);
|
|
|
|
|
|
/** remove leading and trailing whitespace
|
|
* @return a trimmed copy (default locale)
|
|
*/
|
|
string trim (string const& org);
|
|
|
|
|
|
|
|
|
|
/** convenience shortcut: conversion to c-String via string.
|
|
* usable for printf with objects providing to-string conversion.
|
|
*/
|
|
inline const char*
|
|
cStr (string const& org)
|
|
{
|
|
return org.c_str();
|
|
}
|
|
|
|
|
|
} // namespace util
|
|
|
|
|
|
|
|
/* === some common macro definitions === */
|
|
|
|
/** suppress "warning: unused variable" on vars, which are
|
|
* introduced into a scope because of some sideeffect, i.e. Locking
|
|
*/
|
|
#define SIDEEFFECT __attribute__ ((unused));
|
|
|
|
/** this macro wraps its parameter into a cstring literal */
|
|
#define STRINGIFY(TOKEN) __STRNGFY(TOKEN)
|
|
#define __STRNGFY(TOKEN) #TOKEN
|
|
|
|
/** shortcut for subclass test, intended for assertions only.
|
|
* @note it is considered bad style to use such in non-assertion code,
|
|
* and we probably will enforce this design rule in future. */
|
|
#define INSTANCEOF(CLASS, EXPR) (dynamic_cast<const CLASS*> (EXPR))
|
|
|
|
/** the inevitable MAX macro, sometimes still necessary in template code */
|
|
#ifndef MAX // this is present to make this definition play nice with GLib
|
|
#define MAX(A,B) ((A < B) ? (B) : (A))
|
|
#endif
|
|
|
|
#endif /*UTIL_HPP_*/
|