Commit 61d5cc0f authored by Peter's avatar Peter
Browse files

Merge branch 'master' into applecl

parents e2999354 afae4bc8
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
#ifndef __FAST_A_TO_F_H_INCLUDED__
#define __FAST_A_TO_F_H_INCLUDED__
#include <stdlib.h>
#include <math.h>
namespace irr
{
namespace core
{
const float fast_atof_table[] = {
0.f,
0.1f,
0.01f,
0.001f,
0.0001f,
0.00001f,
0.000001f,
0.0000001f,
0.00000001f,
0.000000001f,
0.0000000001f,
0.00000000001f,
0.000000000001f,
0.0000000000001f,
0.00000000000001f,
0.000000000000001f
};
//! Provides a fast function for converting a string into a float,
//! about 6 times faster than atof in win32.
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
inline char* fast_atof_move(char* c, float& out)
{
bool inv = false;
char *t;
float f;
if (*c=='-')
{
c++;
inv = true;
}
f = (float)strtol(c, &t, 10);
c = t;
if (*c == '.')
{
c++;
float pl = (float)strtol(c, &t, 10);
pl *= fast_atof_table[t-c];
f += pl;
c = t;
if (*c == 'e')
{
++c;
float exp = (float)strtol(c, &t, 10);
f *= (float)pow(10.0f, exp);
c = t;
}
}
if (inv)
f *= -1.0f;
out = f;
return c;
}
//! Provides a fast function for converting a string into a float,
//! about 6 times faster than atof in win32.
// If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
inline const char* fast_atof_move_const(const char* c, float& out)
{
bool inv = false;
char *t;
float f;
if (*c=='-')
{
c++;
inv = true;
}
f = (float)strtol(c, &t, 10);
c = t;
if (*c == '.')
{
c++;
float pl = (float)strtol(c, &t, 10);
pl *= fast_atof_table[t-c];
f += pl;
c = t;
if (*c == 'e')
{
++c;
f32 exp = (f32)strtol(c, &t, 10);
f *= (f32)powf(10.0f, exp);
c = t;
}
}
if (inv)
f *= -1.0f;
out = f;
return c;
}
inline float fast_atof(const char* c)
{
float ret;
fast_atof_move_const(c, ret);
return ret;
}
} // end namespace core
}// end namespace irr
#endif
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_HEAPSORT_H_INCLUDED__
#define __IRR_HEAPSORT_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace core
{
//! Sinks an element into the heap.
template<class T>
inline void heapsink(T*array, s32 element, s32 max)
{
while ((element<<1) < max) // there is a left child
{
s32 j = (element<<1);
if (j+1 < max && array[j] < array[j+1])
j = j+1; // take right child
if (array[element] < array[j])
{
T t = array[j]; // swap elements
array[j] = array[element];
array[element] = t;
element = j;
}
else
return;
}
}
//! Sorts an array with size 'size' using heapsort.
template<class T>
inline void heapsort(T* array_, s32 size)
{
// for heapsink we pretent this is not c++, where
// arrays start with index 0. So we decrease the array pointer,
// the maximum always +2 and the element always +1
T* virtualArray = array_ - 1;
s32 virtualSize = size + 2;
s32 i;
// build heap
for (i=((size-1)/2); i>=0; --i)
heapsink(virtualArray, i+1, virtualSize-1);
// sort array
for (i=size-1; i>=0; --i)
{
T t = array_[0];
array_[0] = array_[i];
array_[i] = t;
heapsink(virtualArray, 1, i + 1);
}
}
} // end namespace core
} // end namespace irr
#endif
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
#ifndef __IRR_ARRAY_H_INCLUDED__
#define __IRR_ARRAY_H_INCLUDED__
#include "irrTypes.h"
#include "heapsort.h"
namespace irr
{
namespace core
{
//! Self reallocating template array (like stl vector) with additional features.
/** Some features are: Heap sorting, binary search methods, easier debugging.
*/
template <class T>
class array
{
public:
array()
: data(0), used(0), allocated(0),
free_when_destroyed(true), is_sorted(true)
{
}
//! Constructs a array and allocates an initial chunk of memory.
//! \param start_count: Amount of elements to allocate.
array(u32 start_count)
: data(0), used(0), allocated(0),
free_when_destroyed(true), is_sorted(true)
{
reallocate(start_count);
}
//! Copy constructor
array(const array<T>& other)
: data(0)
{
*this = other;
}
//! Destructor. Frees allocated memory, if set_free_when_destroyed
//! was not set to false by the user before.
~array()
{
if (free_when_destroyed)
delete [] data;
}
//! Reallocates the array, make it bigger or smaller.
//! \param new_size: New size of array.
void reallocate(u32 new_size)
{
T* old_data = data;
data = new T[new_size];
allocated = new_size;
s32 end = used < new_size ? used : new_size;
for (s32 i=0; i<end; ++i)
data[i] = old_data[i];
if (allocated < used)
used = allocated;
delete [] old_data;
}
//! Adds an element at back of array. If the array is to small to
//! add this new element, the array is made bigger.
//! \param element: Element to add at the back of the array.
void push_back(const T& element)
{
if (used + 1 > allocated)
{
// reallocate(used * 2 +1);
// this doesn't work if the element is in the same array. So
// we'll copy the element first to be sure we'll get no data
// corruption
T e;
e = element; // copy element
reallocate(used * 2 +1); // increase data block
data[used++] = e; // push_back
is_sorted = false;
return;
}
data[used++] = element;
is_sorted = false;
}
//! Adds an element at the front of the array. If the array is to small to
//! add this new element, the array is made bigger. Please note that this
//! is slow, because the whole array needs to be copied for this.
//! \param element: Element to add at the back of the array.
void push_front(const T& element)
{
if (used + 1 > allocated)
reallocate(used * 2 +1);
for (int i=(int)used; i>0; --i)
data[i] = data[i-1];
data[0] = element;
is_sorted = false;
++used;
}
//! Insert item into array at specified position. Please use this
//! only if you know what you are doing (possible performance loss).
//! The preferred method of adding elements should be push_back().
//! \param element: Element to be inserted
//! \param index: Where position to insert the new element.
void insert(const T& element, u32 index=0)
{
_IRR_DEBUG_BREAK_IF(index>used) // access violation
if (used + 1 > allocated)
reallocate(used * 2 +1);
for (u32 i=used++; i>index; i--)
data[i] = data[i-1];
data[index] = element;
is_sorted = false;
}
//! Clears the array and deletes all allocated memory.
void clear()
{
delete [] data;
data = 0;
used = 0;
allocated = 0;
is_sorted = true;
}
//! Sets pointer to new array, using this as new workspace.
//! \param newPointer: Pointer to new array of elements.
//! \param size: Size of the new array.
void set_pointer(T* newPointer, u32 size)
{
delete [] data;
data = newPointer;
allocated = size;
used = size;
is_sorted = false;
}
//! Sets if the array should delete the memory it used.
//! \param f: If true, the array frees the allocated memory in its
//! destructor, otherwise not. The default is true.
void set_free_when_destroyed(bool f)
{
free_when_destroyed = f;
}
//! Sets the size of the array.
//! \param usedNow: Amount of elements now used.
void set_used(u32 usedNow)
{
if (allocated < usedNow)
reallocate(usedNow);
used = usedNow;
}
//! Assignement operator
void operator=(const array<T>& other)
{
if (data)
delete [] data;
//if (allocated < other.allocated)
if (other.allocated == 0)
data = 0;
else
data = new T[other.allocated];
used = other.used;
free_when_destroyed = other.free_when_destroyed;
is_sorted = other.is_sorted;
allocated = other.allocated;
for (u32 i=0; i<other.used; ++i)
data[i] = other.data[i];
}
//! Direct access operator
T& operator [](u32 index)
{
_IRR_DEBUG_BREAK_IF(index>=used) // access violation
return data[index];
}
//! Direct access operator
const T& operator [](u32 index) const
{
_IRR_DEBUG_BREAK_IF(index>=used) // access violation
return data[index];
}
//! Gets last frame
const T& getLast() const
{
_IRR_DEBUG_BREAK_IF(!used) // access violation
return data[used-1];
}
//! Gets last frame
T& getLast()
{
_IRR_DEBUG_BREAK_IF(!used) // access violation
return data[used-1];
}
//! Returns a pointer to the array.
//! \return Pointer to the array.
T* pointer()
{
return data;
}
//! Returns a const pointer to the array.
//! \return Pointer to the array.
const T* const_pointer() const
{
return data;
}
//! Returns size of used array.
//! \return Size of elements in the array.
u32 size() const
{
return used;
}
//! Returns amount memory allocated.
//! \return Returns amount of memory allocated. The amount of bytes
//! allocated would be allocated_size() * sizeof(ElementsUsed);
u32 allocated_size() const
{
return allocated;
}
//! Returns true if array is empty
//! \return True if the array is empty, false if not.
bool empty() const
{
return used == 0;
}
//! Sorts the array using heapsort. There is no additional memory waste and
//! the algorithm performs (O) n log n in worst case.
void sort()
{
if (is_sorted || used<2)
return;
heapsort(data, used);
is_sorted = true;
}
//! Performs a binary search for an element, returns -1 if not found.
//! The array will be sorted before the binary search if it is not
//! already sorted.
//! \param element: Element to search for.
//! \return Returns position of the searched element if it was found,
//! otherwise -1 is returned.
s32 binary_search(const T& element)
{
return binary_search(element, 0, used-1);
}
//! Performs a binary search for an element, returns -1 if not found.
//! The array will be sorted before the binary search if it is not
//! already sorted.
//! \param element: Element to search for.
//! \param left: First left index
//! \param right: Last right index.
//! \return Returns position of the searched element if it was found,
//! otherwise -1 is returned.
s32 binary_search(const T& element, s32 left, s32 right)
{
if (!used)
return -1;
sort();
s32 m;
do
{
m = (left+right)>>1;
if (element < data[m])
right = m - 1;
else
left = m + 1;
} while((element < data[m] || data[m] < element) && left<=right);
// this last line equals to:
// " while((element != array[m]) && left<=right);"
// but we only want to use the '<' operator.
// the same in next line, it is "(element == array[m])"
if (!(element < data[m]) && !(data[m] < element))
return m;
return -1;
}
//! Finds an element in linear time, which is very slow. Use
//! binary_search for faster finding. Only works if =operator is implemented.
//! \param element: Element to search for.
//! \return Returns position of the searched element if it was found,
//! otherwise -1 is returned.
s32 linear_search(T& element)
{
for (u32 i=0; i<used; ++i)
if (!(element < data[i]) && !(data[i] < element))
return (s32)i;
return -1;
}
//! Finds an element in linear time, which is very slow. Use
//! binary_search for faster finding. Only works if =operator is implemented.
//! \param element: Element to search for.
//! \return Returns position of the searched element if it was found,
//! otherwise -1 is returned.
s32 linear_reverse_search(T& element)
{
for (s32 i=used-1; i>=0; --i)
if (data[i] == element)
return (s32)i;
return -1;
}
//! Erases an element from the array. May be slow, because all elements
//! following after the erased element have to be copied.
//! \param index: Index of element to be erased.
void erase(u32 index)
{
_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
for (u32 i=index+1; i<used; ++i)
data[i-1] = data[i];
--used;
}
//! Erases some elements from the array. may be slow, because all elements
//! following after the erased element have to be copied.
//! \param index: Index of the first element to be erased.
//! \param count: Amount of elements to be erased.
void erase(u32 index, s32 count)
{
_IRR_DEBUG_BREAK_IF(index>=used || index<0 || count<1 || index+count>used) // access violation
for (u32 i=index+count; i<used; ++i)
data[i-count] = data[i];
used-= count;
}
//! Sets if the array is sorted
void set_sorted(bool _is_sorted)
{
is_sorted = _is_sorted;
}
private:
T* data;
u32 allocated;
u32 used;
bool free_when_destroyed;
bool is_sorted;
};
} // end namespace core
} // end namespace irr
#endif
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
// For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
#ifndef __IRR_STRING_H_INCLUDED__
#define __IRR_STRING_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace core
{
//! Very simple string class with some useful features.
/** string<c8> and string<wchar_t> work both with unicode AND ascii,
so you can assign unicode to string<c8> and ascii to string<wchar_t>
(and the other way round) if your ever would want to.
Note that the conversation between both is not done using an encoding.
Known bugs:
Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the
methods make_upper, make_lower and equals_ignore_case.
*/
template <class T>
class string
{
public:
//! Default constructor
string()
: allocated(1), used(1), array(0)
{
array = new T[1];
array[0] = 0x0;
}
//! Constructor
string(const string<T>& other)
: allocated(0), used(0), array(0)
{
*this = other;
}
//! Constructs a string from an int
string(int number)
: allocated(0), used(0), array(0)
{
// store if negative and make positive
bool negative = false;
if (number < 0)
{
number *= -1;
negative = true;
}
// temporary buffer for 16 numbers
c8 tmpbuf[16];
tmpbuf[15] = 0;
s32 idx = 15;
// special case '0'
if (!number)
{
tmpbuf[14] = '0';
*this = &tmpbuf[14];
return;
}
// add numbers
while(number && idx)
{
idx--;
tmpbuf[idx] = (c8)('0' + (number % 10));
number = number / 10;
}
// add sign
if (negative)
{
idx--;
tmpbuf[idx] = '-';
}
*this = &tmpbuf[idx];
}
//! Constructor for copying a string from a pointer with a given lenght
template <class B>
string(const B* c, s32 lenght)
: allocated(0), used(0), array(0)
{
if (!c)
return;
allocated = used = lenght+1;
array = new T[used];
for (s32 l = 0; l<lenght; ++l)
array[l] = (T)c[l];
array[lenght] = 0;
}
//! Constructor for unicode and ascii strings
template <class B>
string(const B* c)
: allocated(0), used(0), array(0)
{
*this = c;
}
//! destructor
~string()
{
delete [] array;
}
//! Assignment operator
string<T>& operator=(const string<T>& other)
{
if (this == &other)
return *this;
delete [] array;
allocated = used = other.size()+1;
array = new T[used];
const T* p = other.c_str();
for (s32 i=0; i<used; ++i, ++p)
array[i] = *p;
return *this;
}
//! Assignment operator for strings, ascii and unicode
template <class B>
string<T>& operator=(const B* c)
{
if (!c)
{
if (!array)
{
array = new T[1];
allocated = 1;
used = 1;
}
array[0] = 0x0;
return *this;
}
if ((void*)c == (void*)array)
return *this;
s32 len = 0;
const B* p = c;
while(*p)
{
++len;
++p;
}
// we'll take the old string for a while, because the new string could be
// a part of the current string.
T* oldArray = array;
allocated = used = len+1;
array = new T[used];
for (s32 l = 0; l<len+1; ++l)
array[l] = (T)c[l];
delete [] oldArray;
return *this;
}
//! Add operator for other strings
string<T> operator+(const string<T>& other)
{
string<T> str(*this);
str.append(other);
return str;
}
//! Add operator for strings, ascii and unicode
template <class B>
string<T> operator+(const B* c)
{
string<T> str(*this);
str.append(c);
return str;
}
//! Direct access operator
T& operator [](const s32 index) const
{
_IRR_DEBUG_BREAK_IF(index>=used) // bad index
return array[index];
}
//! Comparison operator
bool operator ==(const T* str) const
{
int i;
for(i=0; array[i] && str[i]; ++i)
if (array[i] != str[i])
return false;
return !array[i] && !str[i];
}
//! Comparison operator
bool operator ==(const string<T>& other) const
{
for(s32 i=0; array[i] && other.array[i]; ++i)
if (array[i] != other.array[i])
return false;
return used == other.used;
}
//! Is smaller operator
bool operator <(const string<T>& other) const
{
for(s32 i=0; array[i] && other.array[i]; ++i)
if (array[i] != other.array[i])
return (array[i] < other.array[i]);
return used < other.used;
}
//! Equals not operator
bool operator !=(const string<T>& other) const
{
return !(*this == other);
}
//! Returns length of string
/** \return Returns length of the string in characters. */
s32 size() const
{
return used-1;
}
//! Returns character string
/** \return Returns pointer to C-style zero terminated string. */
const T* c_str() const
{
return array;
}
//! Makes the string lower case.
void make_lower()
{
const T A = (T)'A';
const T Z = (T)'Z';
const T diff = (T)'a' - A;
for (s32 i=0; i<used; ++i)
{
if (array[i]>=A && array[i]<=Z)
array[i] += diff;
}
}
//! Makes the string upper case.
void make_upper()
{
const T a = (T)'a';
const T z = (T)'z';
const T diff = (T)'A' - a;
for (s32 i=0; i<used; ++i)
{
if (array[i]>=a && array[i]<=z)
array[i] += diff;
}
}
//! Compares the string ignoring case.
/** \param other: Other string to compare.
\return Returns true if the string are equal ignoring case. */
bool equals_ignore_case(const string<T>& other) const
{
for(s32 i=0; array[i] && other[i]; ++i)
if (toLower(array[i]) != toLower(other[i]))
return false;
return used == other.used;
}
//! compares the first n characters of the strings
bool equalsn(const string<T>& other, int len)
{
int i;
for(i=0; array[i] && other[i] && i < len; ++i)
if (array[i] != other[i])
return false;
// if one (or both) of the strings was smaller then they
// are only equal if they have the same lenght
return (i == len) || (used == other.used);
}
//! compares the first n characters of the strings
bool equalsn(const T* str, int len)
{
int i;
for(i=0; array[i] && str[i] && i < len; ++i)
if (array[i] != str[i])
return false;
// if one (or both) of the strings was smaller then they
// are only equal if they have the same lenght
return (i == len) || (array[i] == 0 && str[i] == 0);
}
//! Appends a character to this string
/** \param character: Character to append. */
void append(T character)
{
if (used + 1 > allocated)
reallocate((s32)used + 1);
used += 1;
array[used-2] = character;
array[used-1] = 0;
}
//! Appends a string to this string
/** \param other: String to append. */
void append(const string<T>& other)
{
--used;
s32 len = other.size();
if (used + len + 1 > allocated)
reallocate((s32)used + (s32)len + 1);
for (s32 l=0; l<len+1; ++l)
array[l+used] = other[l];
used = used + len + 1;
}
//! Appends a string of the length l to this string.
/** \param other: other String to append to this string.
\param length: How much characters of the other string to add to this one. */
void append(const string<T>& other, s32 length)
{
s32 len = other.size();
if (len < length)
{
append(other);
return;
}
len = length;
--used;
if (used + len > allocated)
reallocate((s32)used + (s32)len);
for (s32 l=0; l<len; ++l)
array[l+used] = other[l];
used = used + len;
}
//! Reserves some memory.
/** \param count: Amount of characters to reserve. */
void reserve(s32 count)
{
if (count < allocated)
return;
reallocate(count);
}
//! finds first occurrence of character in string
/** \param c: Character to search for.
\return Returns position where the character has been found,
or -1 if not found. */
s32 findFirst(T c) const
{
for (s32 i=0; i<used; ++i)
if (array[i] == c)
return i;
return -1;
}
//! finds first occurrence of a character of a list in string
/** \param c: List of strings to find. For example if the method
should find the first occurance of 'a' or 'b', this parameter should be "ab".
\param count: Amount of characters in the list. Ususally,
this should be strlen(ofParameter1)
\return Returns position where one of the character has been found,
or -1 if not found. */
s32 findFirstChar(T* c, int count) const
{
for (s32 i=0; i<used; ++i)
for (int j=0; j<count; ++j)
if (array[i] == c[j])
return i;
return -1;
}
//! Finds first position of a character not in a given list.
/** \param c: List of characters not to find. For example if the method
should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
\param count: Amount of characters in the list. Ususally,
this should be strlen(ofParameter1)
\return Returns position where the character has been found,
or -1 if not found. */
template <class B>
s32 findFirstCharNotInList(B* c, int count) const
{
for (int i=0; i<used; ++i)
{
int j;
for (j=0; j<count; ++j)
if (array[i] == c[j])
break;
if (j==count)
return i;
}
return -1;
}
//! Finds last position of a character not in a given list.
/** \param c: List of characters not to find. For example if the method
should find the first occurance of a character not 'a' or 'b', this parameter should be "ab".
\param count: Amount of characters in the list. Ususally,
this should be strlen(ofParameter1)
\return Returns position where the character has been found,
or -1 if not found. */
template <class B>
s32 findLastCharNotInList(B* c, int count) const
{
for (int i=used-2; i>=0; --i)
{
int j;
for (j=0; j<count; ++j)
if (array[i] == c[j])
break;
if (j==count)
return i;
}
return -1;
}
//! finds next occurrence of character in string
/** \param c: Character to search for.
\param startPos: Position in string to start searching.
\return Returns position where the character has been found,
or -1 if not found. */
s32 findNext(T c, s32 startPos) const
{
for (s32 i=startPos; i<used; ++i)
if (array[i] == c)
return i;
return -1;
}
//! finds last occurrence of character in string
//! \param c: Character to search for.
//! \return Returns position where the character has been found,
//! or -1 if not found.
s32 findLast(T c) const
{
for (s32 i=used-1; i>=0; --i)
if (array[i] == c)
return i;
return -1;
}
//! Returns a substring
//! \param begin: Start of substring.
//! \param length: Length of substring.
string<T> subString(s32 begin, s32 length)
{
if (length <= 0)
return string<T>("");
string<T> o;
o.reserve(length+1);
for (s32 i=0; i<length; ++i)
o.array[i] = array[i+begin];
o.array[length] = 0;
o.used = o.allocated;
return o;
}
void operator += (T c)
{
append(c);
}
void operator += (const string<T>& other)
{
append(other);
}
void operator += (int i)
{
append(string<T>(i));
}
//! replaces all characters of a special type with another one
void replace(T toReplace, T replaceWith)
{
for (s32 i=0; i<used; ++i)
if (array[i] == toReplace)
array[i] = replaceWith;
}
//! trims the string.
/** Removes whitespace from begin and end of the string. */
void trim()
{
const char whitespace[] = " \t\n";
const int whitespacecount = 3;
// find start and end of real string without whitespace
int begin = findFirstCharNotInList(whitespace, whitespacecount);
if (begin == -1)
return;
int end = findLastCharNotInList(whitespace, whitespacecount);
if (end == -1)
return;
*this = subString(begin, (end +1) - begin);
}
//! Erases a character from the string. May be slow, because all elements
//! following after the erased element have to be copied.
//! \param index: Index of element to be erased.
void erase(int index)
{
_IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation
for (int i=index+1; i<used; ++i)
array[i-1] = array[i];
--used;
}
private:
//! Returns a character converted to lower case
T toLower(const T& t) const
{
if (t>=(T)'A' && t<=(T)'Z')
return t + ((T)'a' - (T)'A');
else
return t;
}
//! Reallocate the array, make it bigger or smaler
void reallocate(s32 new_size)
{
T* old_array = array;
array = new T[new_size];
allocated = new_size;
s32 amount = used < new_size ? used : new_size;
for (s32 i=0; i<amount; ++i)
array[i] = old_array[i];
if (allocated < used)
used = allocated;
delete [] old_array;
}
//--- member variables
T* array;
s32 allocated;
s32 used;
};
//! Typedef for character strings
typedef string<irr::c8> stringc;
//! Typedef for wide character strings
typedef string<wchar_t> stringw;
} // end namespace core
} // end namespace irr
#endif
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_TYPES_H_INCLUDED__
#define __IRR_TYPES_H_INCLUDED__
namespace irr
{
//! 8 bit unsigned variable.
/** This is a typedef for unsigned char, it ensures portability of the engine. */
typedef unsigned char u8;
//! 8 bit signed variable.
/** This is a typedef for signed char, it ensures portability of the engine. */
typedef signed char s8;
//! 8 bit character variable.
/** This is a typedef for char, it ensures portability of the engine. */
typedef char c8;
//! 16 bit unsigned variable.
/** This is a typedef for unsigned short, it ensures portability of the engine. */
typedef unsigned short u16;
//! 16 bit signed variable.
/** This is a typedef for signed short, it ensures portability of the engine. */
typedef signed short s16;
//! 32 bit unsigned variable.
/** This is a typedef for unsigned int, it ensures portability of the engine. */
typedef unsigned int u32;
//! 32 bit signed variable.
/** This is a typedef for signed int, it ensures portability of the engine. */
typedef signed int s32;
// 64 bit signed variable.
// This is a typedef for __int64, it ensures portability of the engine.
// This type is currently not used by the engine and not supported by compilers
// other than Microsoft Compilers, so it is outcommented.
//typedef __int64 s64;
//! 32 bit floating point variable.
/** This is a typedef for float, it ensures portability of the engine. */
typedef float f32;
//! 64 bit floating point variable.
/** This is a typedef for double, it ensures portability of the engine. */
typedef double f64;
} // end namespace
// define the wchar_t type if not already built in.
#ifdef _MSC_VER
#ifndef _WCHAR_T_DEFINED
//! A 16 bit wide character type.
/**
Defines the wchar_t-type.
In VS6, its not possible to tell
the standard compiler to treat wchar_t as a built-in type, and
sometimes we just don't want to include the huge stdlib.h or wchar.h,
so we'll use this.
*/
typedef unsigned short wchar_t;
#define _WCHAR_T_DEFINED
#endif // wchar is not defined
#endif // microsoft compiler
//! define a break macro for debugging only in Win32 mode.
#if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG)
#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) if (_CONDITION_) {_asm int 3}
#else
#define _IRR_DEBUG_BREAK_IF( _CONDITION_ )
#endif
//! Defines a small statement to work around a microsoft compiler bug.
/** The microsft compiler 7.0 - 7.1 has a bug:
When you call unmanaged code that returns a bool type value of false from managed code,
the return value may appear as true. See
http://support.microsoft.com/default.aspx?kbid=823071 for details.
Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400)
#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX __asm mov eax,100
#else
#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
#endif // _IRR_MANAGED_MARSHALLING_BUGFIX
#endif // __IRR_TYPES_H_INCLUDED__
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
#ifndef __IRR_XML_H_INCLUDED__
#define __IRR_XML_H_INCLUDED__
#include <stdio.h>
/** \mainpage irrXML 1.2 API documentation
<div align="center"><img src="logobig.png" ></div>
\section intro Introduction
Welcome to the irrXML API documentation.
Here you'll find any information you'll need to develop applications with
irrXML. If you look for a tutorial on how to start, take a look at the \ref irrxmlexample,
at the homepage of irrXML at <A HREF="http://xml.irrlicht3d.org" >xml.irrlicht3d.org</A>
or into the SDK in the directory \example.
irrXML is intended to be a high speed and easy-to-use XML Parser for C++, and
this documentation is an important part of it. If you have any questions or
suggestions, just send a email to the author of the engine, Nikolaus Gebhardt
(niko (at) irrlicht3d.org). For more informations about this parser, see \ref history.
\section features Features
irrXML provides forward-only, read-only
access to a stream of non validated XML data. It was fully implemented by
Nikolaus Gebhardt. Its current features are:
- It it fast as lighting and has very low memory usage. It was
developed with the intention of being used in 3D games, as it already has been.
- irrXML is very small: It only consists of 60 KB of code and can be added easily
to your existing project.
- Of course, it is platform independent and works with lots of compilers.
- It is able to parse ASCII, UTF-8, UTF-16 and UTF-32 text files, both in
little and big endian format.
- Independent of the input file format, the parser can return all strings in ASCII, UTF-8,
UTF-16 and UTF-32 format.
- With its optional file access abstraction it has the advantage that it can read not
only from files but from any type of data (memory, network, ...). For example when
used with the Irrlicht Engine, it directly reads from compressed .zip files.
- Just like the Irrlicht Engine for which it was originally created, it is extremely easy
to use.
- It has no external dependencies, it does not even need the STL.
Although irrXML has some strenghts, it currently also has the following limitations:
- The input xml file is not validated and assumed to be correct.
\section irrxmlexample Example
The following code demonstrates the basic usage of irrXML. A simple xml
file like this is parsed:
\code
<?xml version="1.0"?>
<config>
<!-- This is a config file for the mesh viewer -->
<model file="dwarf.dea" />
<messageText caption="Irrlicht Engine Mesh Viewer">
Welcome to the Mesh Viewer of the &quot;Irrlicht Engine&quot;.
</messageText>
</config>
\endcode
The code for parsing this file would look like this:
\code
#include <irrXML.h>
using namespace irr; // irrXML is located in the namespace irr::io
using namespace io;
#include <string> // we use STL strings to store data in this example
void main()
{
// create the reader using one of the factory functions
IrrXMLReader* xml = createIrrXMLReader("config.xml");
// strings for storing the data we want to get out of the file
std::string modelFile;
std::string messageText;
std::string caption;
// parse the file until end reached
while(xml && xml->read())
{
switch(xml->getNodeType())
{
case EXN_TEXT:
// in this xml file, the only text which occurs is the messageText
messageText = xml->getNodeData();
break;
case EXN_ELEMENT:
{
if (!strcmp("model", xml->getNodeName()))
modelFile = xml->getAttributeValue("file");
else
if (!strcmp("messageText", xml->getNodeName()))
caption = xml->getAttributeValue("caption");
}
break;
}
}
// delete the xml parser after usage
delete xml;
}
\endcode
\section howto How to use
Simply add the source files in the /src directory of irrXML to your project. Done.
\section license License
The irrXML license is based on the zlib license. Basicly, this means you can do with
irrXML whatever you want:
Copyright (C) 2002-2005 Nikolaus Gebhardt
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
\section history History
As lots of references in this documentation and the source show, this xml
parser has originally been a part of the
<A HREF="http://irrlicht.sourceforge.net" >Irrlicht Engine</A>. But because
the parser has become very useful with the latest release, people asked for a
separate version of it, to be able to use it in non Irrlicht projects. With
irrXML 1.0, this has now been done.
*/
namespace irr
{
namespace io
{
//! Enumeration of all supported source text file formats
enum ETEXT_FORMAT
{
//! ASCII, file without byte order mark, or not a text file
ETF_ASCII,
//! UTF-8 format
ETF_UTF8,
//! UTF-16 format, big endian
ETF_UTF16_BE,
//! UTF-16 format, little endian
ETF_UTF16_LE,
//! UTF-32 format, big endian
ETF_UTF32_BE,
//! UTF-32 format, little endian
ETF_UTF32_LE,
};
//! Enumeration for all xml nodes which are parsed by IrrXMLReader
enum EXML_NODE
{
//! No xml node. This is usually the node if you did not read anything yet.
EXN_NONE,
//! A xml element, like <foo>
EXN_ELEMENT,
//! End of an xml element, like </foo>
EXN_ELEMENT_END,
//! Text within a xml element: <foo> this is the text. </foo>
EXN_TEXT,
//! An xml comment like &lt;!-- I am a comment --&gt; or a DTD definition.
EXN_COMMENT,
//! An xml cdata section like &lt;![CDATA[ this is some CDATA ]]&gt;
EXN_CDATA,
//! Unknown element.
EXN_UNKNOWN
};
//! Callback class for file read abstraction.
/** With this, it is possible to make the xml parser read in other things
than just files. The Irrlicht engine is using this for example to
read xml from compressed .zip files. To make the parser read in
any other data, derive a class from this interface, implement the
two methods to read your data and give a pointer to an instance of
your implementation when calling createIrrXMLReader(),
createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */
class IFileReadCallBack
{
public:
//! virtual destructor
virtual ~IFileReadCallBack() {};
//! Reads an amount of bytes from the file.
/** \param buffer: Pointer to buffer where to read bytes will be written to.
\param sizeToRead: Amount of bytes to read from the file.
\return Returns how much bytes were read. */
virtual int read(void* buffer, int sizeToRead) = 0;
//! Returns size of file in bytes
virtual int getSize() = 0;
};
//! Empty class to be used as parent class for IrrXMLReader.
/** If you need another class as base class for the xml reader, you can do this by creating
the reader using for example new CXMLReaderImpl<char, YourBaseClass>(yourcallback);
The Irrlicht Engine for example needs IUnknown as base class for every object to
let it automaticly reference countend, hence it replaces IXMLBase with IUnknown.
See irrXML.cpp on how this can be done in detail. */
class IXMLBase
{
};
//! Interface providing easy read access to a XML file.
/** You can create an instance of this reader using one of the factory functions
createIrrXMLReader(), createIrrXMLReaderUTF16() and createIrrXMLReaderUTF32().
If using the parser from the Irrlicht Engine, please use IFileSystem::createXMLReader()
instead.
For a detailed intro how to use the parser, see \ref irrxmlexample and \ref features.
The typical usage of this parser looks like this:
\code
#include <irrXML.h>
using namespace irr; // irrXML is located in the namespace irr::io
using namespace io;
void main()
{
// create the reader using one of the factory functions
IrrXMLReader* xml = createIrrXMLReader("config.xml");
if (xml == 0)
return; // file could not be opened
// parse the file until end reached
while(xml->read())
{
// based on xml->getNodeType(), do something.
}
// delete the xml parser after usage
delete xml;
}
\endcode
See \ref irrxmlexample for a more detailed example.
*/
template<class char_type, class super_class>
class IIrrXMLReader : public super_class
{
public:
//! Destructor
virtual ~IIrrXMLReader() {};
//! Reads forward to the next xml node.
/** \return Returns false, if there was no further node. */
virtual bool read() = 0;
//! Returns the type of the current XML node.
virtual EXML_NODE getNodeType() const = 0;
//! Returns attribute count of the current XML node.
/** This is usually
non null if the current node is EXN_ELEMENT, and the element has attributes.
\return Returns amount of attributes of this xml node. */
virtual int getAttributeCount() const = 0;
//! Returns name of an attribute.
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
\return Name of the attribute, 0 if an attribute with this index does not exist. */
virtual const char_type* getAttributeName(int idx) const = 0;
//! Returns the value of an attribute.
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
\return Value of the attribute, 0 if an attribute with this index does not exist. */
virtual const char_type* getAttributeValue(int idx) const = 0;
//! Returns the value of an attribute.
/** \param name: Name of the attribute.
\return Value of the attribute, 0 if an attribute with this name does not exist. */
virtual const char_type* getAttributeValue(const char_type* name) const = 0;
//! Returns the value of an attribute in a safe way.
/** Like getAttributeValue(), but does not
return 0 if the attribute does not exist. An empty string ("") is returned then.
\param name: Name of the attribute.
\return Value of the attribute, and "" if an attribute with this name does not exist */
virtual const char_type* getAttributeValueSafe(const char_type* name) const = 0;
//! Returns the value of an attribute as integer.
/** \param name Name of the attribute.
\return Value of the attribute as integer, and 0 if an attribute with this name does not exist or
the value could not be interpreted as integer. */
virtual int getAttributeValueAsInt(const char_type* name) const = 0;
//! Returns the value of an attribute as integer.
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
\return Value of the attribute as integer, and 0 if an attribute with this index does not exist or
the value could not be interpreted as integer. */
virtual int getAttributeValueAsInt(int idx) const = 0;
//! Returns the value of an attribute as float.
/** \param name: Name of the attribute.
\return Value of the attribute as float, and 0 if an attribute with this name does not exist or
the value could not be interpreted as float. */
virtual float getAttributeValueAsFloat(const char_type* name) const = 0;
//! Returns the value of an attribute as float.
/** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1.
\return Value of the attribute as float, and 0 if an attribute with this index does not exist or
the value could not be interpreted as float. */
virtual float getAttributeValueAsFloat(int idx) const = 0;
//! Returns the name of the current node.
/** Only non null, if the node type is EXN_ELEMENT.
\return Name of the current node or 0 if the node has no name. */
virtual const char_type* getNodeName() const = 0;
//! Returns data of the current node.
/** Only non null if the node has some
data and it is of type EXN_TEXT or EXN_UNKNOWN. */
virtual const char_type* getNodeData() const = 0;
//! Returns if an element is an empty element, like <foo />
virtual bool isEmptyElement() const = 0;
//! Returns format of the source xml file.
/** It is not necessary to use
this method because the parser will convert the input file format
to the format wanted by the user when creating the parser. This
method is useful to get/display additional informations. */
virtual ETEXT_FORMAT getSourceFormat() const = 0;
//! Returns format of the strings returned by the parser.
/** This will be UTF8 for example when you created a parser with
IrrXMLReaderUTF8() and UTF32 when it has been created using
IrrXMLReaderUTF32. It should not be necessary to call this
method and only exists for informational purposes. */
virtual ETEXT_FORMAT getParserFormat() const = 0;
};
//! defines the utf-16 type.
/** Not using wchar_t for this because
wchar_t has 16 bit on windows and 32 bit on other operating systems. */
typedef unsigned short char16;
//! defines the utf-32 type.
/** Not using wchar_t for this because
wchar_t has 16 bit on windows and 32 bit on other operating systems. */
typedef unsigned long char32;
//! A UTF-8 or ASCII character xml parser.
/** This means that all character data will be returned in 8 bit ASCII or UTF-8 by this parser.
The file to read can be in any format, it will be converted to UTF-8 if it is not
in this format.
Create an instance of this with createIrrXMLReader();
See IIrrXMLReader for description on how to use it. */
typedef IIrrXMLReader<char, IXMLBase> IrrXMLReader;
//! A UTF-16 xml parser.
/** This means that all character data will be returned in UTF-16 by this parser.
The file to read can be in any format, it will be converted to UTF-16 if it is not
in this format.
Create an instance of this with createIrrXMLReaderUTF16();
See IIrrXMLReader for description on how to use it. */
typedef IIrrXMLReader<char16, IXMLBase> IrrXMLReaderUTF16;
//! A UTF-32 xml parser.
/** This means that all character data will be returned in UTF-32 by this parser.
The file to read can be in any format, it will be converted to UTF-32 if it is not
in this format.
Create an instance of this with createIrrXMLReaderUTF32();
See IIrrXMLReader for description on how to use it. */
typedef IIrrXMLReader<char32, IXMLBase> IrrXMLReaderUTF32;
//! Creates an instance of an UFT-8 or ASCII character xml parser.
/** This means that all character data will be returned in 8 bit ASCII or UTF-8.
The file to read can be in any format, it will be converted to UTF-8 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReaderUTF8() instead.
\param filename: Name of file to be opened.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReader* createIrrXMLReader(const char* filename);
//! Creates an instance of an UFT-8 or ASCII character xml parser.
/** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can
be in any format, it will be converted to UTF-8 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReaderUTF8() instead.
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReader* createIrrXMLReader(FILE* file);
//! Creates an instance of an UFT-8 or ASCII character xml parser.
/** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can
be in any format, it will be converted to UTF-8 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReaderUTF8() instead.
\param callback: Callback for file read abstraction. Implement your own
callback to make the xml parser read in other things than just files. See
IFileReadCallBack for more information about this.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback);
//! Creates an instance of an UFT-16 xml parser.
/** This means that
all character data will be returned in UTF-16. The file to read can
be in any format, it will be converted to UTF-16 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param filename: Name of file to be opened.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename);
//! Creates an instance of an UFT-16 xml parser.
/** This means that all character data will be returned in UTF-16. The file to read can
be in any format, it will be converted to UTF-16 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file);
//! Creates an instance of an UFT-16 xml parser.
/** This means that all character data will be returned in UTF-16. The file to read can
be in any format, it will be converted to UTF-16 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param callback: Callback for file read abstraction. Implement your own
callback to make the xml parser read in other things than just files. See
IFileReadCallBack for more information about this.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback);
//! Creates an instance of an UFT-32 xml parser.
/** This means that all character data will be returned in UTF-32. The file to read can
be in any format, it will be converted to UTF-32 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param filename: Name of file to be opened.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename);
//! Creates an instance of an UFT-32 xml parser.
/** This means that all character data will be returned in UTF-32. The file to read can
be in any format, it will be converted to UTF-32 if it is not in this format.
if you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param file: Pointer to opened file, must have been opened in binary mode, e.g.
using fopen("foo.bar", "wb"); The file will not be closed after it has been read.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file);
//! Creates an instance of an UFT-32 xml parser.
/** This means that
all character data will be returned in UTF-32. The file to read can
be in any format, it will be converted to UTF-32 if it is not in this format.
If you are using the Irrlicht Engine, it is better not to use this function but
IFileSystem::createXMLReader() instead.
\param callback: Callback for file read abstraction. Implement your own
callback to make the xml parser read in other things than just files. See
IFileReadCallBack for more information about this.
\return Returns a pointer to the created xml parser. This pointer should be
deleted using 'delete' after no longer needed. Returns 0 if an error occured
and the file could not be opened. */
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback);
/*! \file irrxml.h
\brief Header file of the irrXML, the Irrlicht XML parser.
This file includes everything needed for using irrXML,
the XML parser of the Irrlicht Engine. To use irrXML,
you only need to include this file in your project:
\code
#include <irrXML.h>
\endcode
It is also common to use the two namespaces in which irrXML is included,
directly after #including irrXML.h:
\code
#include <irrXML.h>
using namespace irr;
using namespace io;
\endcode
*/
} // end namespace io
} // end namespace irr
#endif // __IRR_XML_H_INCLUDED__
==========================================================================
irrXML 1.2
==========================================================================
Welcome to irrXML
Content of this file:
1. Directory structure overview
2. How to use
3. Requirements
5. License
6. Contact
==========================================================================
1. Directory structure overview
==========================================================================
You will find some directories after decompressing the archive in which
came the SDK. These are:
\doc Documentation of irrXML.
\example A short example showing how to use the parser with solution
and make files.
\src The source code of irrXML.
==========================================================================
2. How to use
==========================================================================
For Linux/Unix users: Simply go into the directory /example and run
'make'. This will create a sample project using irrXML.
Windows users: Just add the source files to your project. That's all.
For more information see the documentation in the \doc directory.
Alternatively, you could compile irrXML as .lib, after this you would
only need to use the irrXML.h header file, nothing more.
==========================================================================
3. Requirements
==========================================================================
You can use one of the following compilers/IDEs to develop applications
with irrXML. However, other compilers/IDEs make work as well,
we simply didn't test them.
* gcc 3.2
* gcc 3.3
* Visual Studio 6.0
* Visual Studio.NET (7.0)
* Visual Studio.NET 2003 (7.1)
* Visual Studio.NET 2005 (8.0)
* DevC++ 4.9 & gcc (project files included)
==========================================================================
5. License
==========================================================================
The license of irrXML is based on the zlib/libpng license.
Even though this license does not require you to mention that you are
using the Irrlicht Engine in your product, an acknowledgement
would be highly appreciated.
The irrXML License
===========================
Copyright (C) 2002-2005 Nikolaus Gebhardt
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
==========================================================================
6. Contact
==========================================================================
If you have problems, questions or suggestions, please visit the
official homepage of irrXML:
http://xml.irrlicht3d.org
You will find forums, patches, documentation, and other stuff
which will help you out.
If want to contact the author of the engine, please send an email to
Nikolaus Gebhardt:
irrlicht@users.sourceforge.net
\ No newline at end of file
// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine" and the "irrXML" project.
// For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h
#include "irrXML.h"
#include "irrString.h"
#include "irrArray.h"
#include "fast_atof.h"
#include "CXMLReaderImpl.h"
namespace irr
{
namespace io
{
//! Implementation of the file read callback for ordinary files
class CFileReadCallBack : public IFileReadCallBack
{
public:
//! construct from filename
CFileReadCallBack(const char* filename)
: File(0), Size(0), Close(true)
{
// open file
File = fopen(filename, "rb");
if (File)
getFileSize();
}
//! construct from FILE pointer
CFileReadCallBack(FILE* file)
: File(file), Size(0), Close(false)
{
if (File)
getFileSize();
}
//! destructor
virtual ~CFileReadCallBack()
{
if (Close && File)
fclose(File);
}
//! Reads an amount of bytes from the file.
virtual int read(void* buffer, int sizeToRead)
{
if (!File)
return 0;
return (int)fread(buffer, 1, sizeToRead, File);
}
//! Returns size of file in bytes
virtual int getSize()
{
return Size;
}
private:
//! retrieves the file size of the open file
void getFileSize()
{
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
}
FILE* File;
int Size;
bool Close;
}; // end class CFileReadCallBack
// FACTORY FUNCTIONS:
//! Creates an instance of an UFT-8 or ASCII character xml parser.
IrrXMLReader* createIrrXMLReader(const char* filename)
{
return new CXMLReaderImpl<char, IXMLBase>(new CFileReadCallBack(filename));
}
//! Creates an instance of an UFT-8 or ASCII character xml parser.
IrrXMLReader* createIrrXMLReader(FILE* file)
{
return new CXMLReaderImpl<char, IXMLBase>(new CFileReadCallBack(file));
}
//! Creates an instance of an UFT-8 or ASCII character xml parser.
IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback)
{
return new CXMLReaderImpl<char, IXMLBase>(callback, false);
}
//! Creates an instance of an UTF-16 xml parser.
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename)
{
return new CXMLReaderImpl<char16, IXMLBase>(new CFileReadCallBack(filename));
}
//! Creates an instance of an UTF-16 xml parser.
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file)
{
return new CXMLReaderImpl<char16, IXMLBase>(new CFileReadCallBack(file));
}
//! Creates an instance of an UTF-16 xml parser.
IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback)
{
return new CXMLReaderImpl<char16, IXMLBase>(callback, false);
}
//! Creates an instance of an UTF-32 xml parser.
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename)
{
return new CXMLReaderImpl<char32, IXMLBase>(new CFileReadCallBack(filename));
}
//! Creates an instance of an UTF-32 xml parser.
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file)
{
return new CXMLReaderImpl<char32, IXMLBase>(new CFileReadCallBack(file));
}
//! Creates an instance of an UTF-32 xml parser.
IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback)
{
return new CXMLReaderImpl<char32, IXMLBase>(callback, false);
}
} // end namespace io
} // end namespace irr
......@@ -38,6 +38,9 @@
#include <set>
#include <string>
#include <vector>
#ifdef LEPTON_USE_JIT
#include "asmjit.h"
#endif
namespace Lepton {
......@@ -87,6 +90,13 @@ private:
mutable std::vector<double> workspace;
mutable std::vector<double> argValues;
std::map<std::string, double> dummyVariables;
void* jitCode;
#ifdef LEPTON_USE_JIT
void generateJitCode();
void generateSingleArgCall(asmjit::X86Compiler& c, asmjit::X86XmmVar& dest, asmjit::X86XmmVar& arg, double (*function)(double));
std::vector<double> constants;
asmjit::JitRuntime runtime;
#endif
};
} // namespace Lepton
......
......@@ -64,7 +64,7 @@ public:
*/
enum Id {CONSTANT, VARIABLE, CUSTOM, ADD, SUBTRACT, MULTIPLY, DIVIDE, POWER, NEGATE, SQRT, EXP, LOG,
SIN, COS, SEC, CSC, TAN, COT, ASIN, ACOS, ATAN, SINH, COSH, TANH, ERF, ERFC, STEP, DELTA, SQUARE, CUBE, RECIPROCAL,
ADD_CONSTANT, MULTIPLY_CONSTANT, POWER_CONSTANT, MIN, MAX, ABS};
ADD_CONSTANT, MULTIPLY_CONSTANT, POWER_CONSTANT, MIN, MAX, ABS, FLOOR, CEIL};
/**
* Get the name of this Operation.
*/
......@@ -153,6 +153,8 @@ public:
class Min;
class Max;
class Abs;
class Floor;
class Ceil;
};
class LEPTON_EXPORT Operation::Constant : public Operation {
......@@ -1090,6 +1092,51 @@ public:
ExpressionTreeNode differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs, const std::string& variable) const;
};
class LEPTON_EXPORT Operation::Floor : public Operation {
public:
Floor() {
}
std::string getName() const {
return "floor";
}
Id getId() const {
return FLOOR;
}
int getNumArguments() const {
return 1;
}
Operation* clone() const {
return new Floor();
}
double evaluate(double* args, const std::map<std::string, double>& variables) const {
return std::floor(args[0]);
}
ExpressionTreeNode differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs, const std::string& variable) const;
};
class LEPTON_EXPORT Operation::Ceil : public Operation {
public:
Ceil() {
}
std::string getName() const {
return "ceil";
}
Id getId() const {
return CEIL;
}
int getNumArguments() const {
return 1;
}
Operation* clone() const {
return new Ceil();
}
double evaluate(double* args, const std::map<std::string, double>& variables) const {
return std::ceil(args[0]);
}
ExpressionTreeNode differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs, const std::string& variable) const;
};
} // namespace Lepton
#endif /*LEPTON_OPERATION_H_*/
......@@ -25,14 +25,14 @@
#ifdef _MSC_VER
// We don't want to hear about how sprintf is "unsafe".
#pragma warning(disable:4996)
// Keep MS VC++ quiet about lack of dll export of private members.
#pragma warning(disable:4251)
#if defined(LEPTON_BUILDING_SHARED_LIBRARY)
#define LEPTON_EXPORT __declspec(dllexport)
// Keep MS VC++ quiet about lack of dll export of private members.
#pragma warning(disable:4251)
#elif defined(LEPTON_BUILDING_STATIC_LIBRARY) || defined(LEPTON_USE_STATIC_LIBRARIES)
#define LEPTON_EXPORT
#define LEPTON_EXPORT
#else
#define LEPTON_EXPORT __declspec(dllimport) // i.e., a client of a shared library
#define LEPTON_EXPORT __declspec(dllimport) // i.e., a client of a shared library
#endif
#else
#define LEPTON_EXPORT // Linux, Mac
......
/* -------------------------------------------------------------------------- *
* Lepton *
* -------------------------------------------------------------------------- *
* This is part of the Lepton expression parser originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h"
#include "lepton/Operation.h"
#include "lepton/ParsedExpression.h"
#include <utility>
using namespace Lepton;
using namespace std;
CompiledExpression::CompiledExpression() {
}
CompiledExpression::CompiledExpression(const ParsedExpression& expression) {
ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
vector<pair<ExpressionTreeNode, int> > temps;
compileExpression(expr.getRootNode(), temps);
}
CompiledExpression::~CompiledExpression() {
for (int i = 0; i < (int) operation.size(); i++)
if (operation[i] != NULL)
delete operation[i];
}
CompiledExpression::CompiledExpression(const CompiledExpression& expression) {
*this = expression;
}
CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
arguments = expression.arguments;
target = expression.target;
variableIndices = expression.variableIndices;
variableNames = expression.variableNames;
workspace.resize(expression.workspace.size());
argValues.resize(expression.argValues.size());
operation.resize(expression.operation.size());
for (int i = 0; i < (int) operation.size(); i++)
operation[i] = expression.operation[i]->clone();
return *this;
}
void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
if (findTempIndex(node, temps) != -1)
return; // We have already processed a node identical to this one.
// Process the child nodes.
vector<int> args;
for (int i = 0; i < node.getChildren().size(); i++) {
compileExpression(node.getChildren()[i], temps);
args.push_back(findTempIndex(node.getChildren()[i], temps));
}
// Process this node.
if (node.getOperation().getId() == Operation::VARIABLE) {
variableIndices[node.getOperation().getName()] = (int) workspace.size();
variableNames.insert(node.getOperation().getName());
}
else {
int stepIndex = (int) arguments.size();
arguments.push_back(vector<int>());
target.push_back((int) workspace.size());
operation.push_back(node.getOperation().clone());
if (args.size() == 0)
arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
else {
// If the arguments are sequential, we can just pass a pointer to the first one.
bool sequential = true;
for (int i = 1; i < args.size(); i++)
if (args[i] != args[i-1]+1)
sequential = false;
if (sequential)
arguments[stepIndex].push_back(args[0]);
else {
arguments[stepIndex] = args;
if (args.size() > argValues.size())
argValues.resize(args.size(), 0.0);
}
}
}
temps.push_back(make_pair(node, workspace.size()));
workspace.push_back(0.0);
}
int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
for (int i = 0; i < (int) temps.size(); i++)
if (temps[i].first == node)
return i;
return -1;
}
const set<string>& CompiledExpression::getVariables() const {
return variableNames;
}
double& CompiledExpression::getVariableReference(const string& name) {
map<string, int>::iterator index = variableIndices.find(name);
if (index == variableIndices.end())
throw Exception("getVariableReference: Unknown variable '"+name+"'");
return workspace[index->second];
}
double CompiledExpression::evaluate() const {
// Loop over the operations and evaluate each one.
for (int step = 0; step < operation.size(); step++) {
const vector<int>& args = arguments[step];
if (args.size() == 1)
workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
else {
for (int i = 0; i < args.size(); i++)
argValues[i] = workspace[args[i]];
workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
}
}
return workspace[workspace.size()-1];
}
/* -------------------------------------------------------------------------- *
* Lepton *
* -------------------------------------------------------------------------- *
* This is part of the Lepton expression parser originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h"
#include "lepton/Operation.h"
#include "lepton/ParsedExpression.h"
#include <utility>
using namespace Lepton;
using namespace std;
#ifdef LEPTON_USE_JIT
using namespace asmjit;
#endif
CompiledExpression::CompiledExpression() : jitCode(NULL) {
}
CompiledExpression::CompiledExpression(const ParsedExpression& expression) : jitCode(NULL) {
ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
vector<pair<ExpressionTreeNode, int> > temps;
compileExpression(expr.getRootNode(), temps);
int maxArguments = 1;
for (int i = 0; i < (int) operation.size(); i++)
if (operation[i]->getNumArguments() > maxArguments)
maxArguments = operation[i]->getNumArguments();
argValues.resize(maxArguments);
#ifdef LEPTON_USE_JIT
generateJitCode();
#endif
}
CompiledExpression::~CompiledExpression() {
for (int i = 0; i < (int) operation.size(); i++)
if (operation[i] != NULL)
delete operation[i];
}
CompiledExpression::CompiledExpression(const CompiledExpression& expression) : jitCode(NULL) {
*this = expression;
}
CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
arguments = expression.arguments;
target = expression.target;
variableIndices = expression.variableIndices;
variableNames = expression.variableNames;
workspace.resize(expression.workspace.size());
argValues.resize(expression.argValues.size());
operation.resize(expression.operation.size());
for (int i = 0; i < (int) operation.size(); i++)
operation[i] = expression.operation[i]->clone();
#ifdef LEPTON_USE_JIT
generateJitCode();
#endif
return *this;
}
void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
if (findTempIndex(node, temps) != -1)
return; // We have already processed a node identical to this one.
// Process the child nodes.
vector<int> args;
for (int i = 0; i < node.getChildren().size(); i++) {
compileExpression(node.getChildren()[i], temps);
args.push_back(findTempIndex(node.getChildren()[i], temps));
}
// Process this node.
if (node.getOperation().getId() == Operation::VARIABLE) {
variableIndices[node.getOperation().getName()] = (int) workspace.size();
variableNames.insert(node.getOperation().getName());
}
else {
int stepIndex = (int) arguments.size();
arguments.push_back(vector<int>());
target.push_back((int) workspace.size());
operation.push_back(node.getOperation().clone());
if (args.size() == 0)
arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
else {
// If the arguments are sequential, we can just pass a pointer to the first one.
bool sequential = true;
for (int i = 1; i < args.size(); i++)
if (args[i] != args[i-1]+1)
sequential = false;
if (sequential)
arguments[stepIndex].push_back(args[0]);
else
arguments[stepIndex] = args;
}
}
temps.push_back(make_pair(node, (int) workspace.size()));
workspace.push_back(0.0);
}
int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
for (int i = 0; i < (int) temps.size(); i++)
if (temps[i].first == node)
return i;
return -1;
}
const set<string>& CompiledExpression::getVariables() const {
return variableNames;
}
double& CompiledExpression::getVariableReference(const string& name) {
map<string, int>::iterator index = variableIndices.find(name);
if (index == variableIndices.end())
throw Exception("getVariableReference: Unknown variable '"+name+"'");
return workspace[index->second];
}
double CompiledExpression::evaluate() const {
#ifdef LEPTON_USE_JIT
return ((double (*)()) jitCode)();
#else
// Loop over the operations and evaluate each one.
for (int step = 0; step < operation.size(); step++) {
const vector<int>& args = arguments[step];
if (args.size() == 1)
workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
else {
for (int i = 0; i < args.size(); i++)
argValues[i] = workspace[args[i]];
workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
}
}
return workspace[workspace.size()-1];
#endif
}
#ifdef LEPTON_USE_JIT
static double evaluateOperation(Operation* op, double* args) {
map<string, double>* dummyVariables = NULL;
return op->evaluate(args, *dummyVariables);
}
void CompiledExpression::generateJitCode() {
X86Compiler c(&runtime);
c.addFunc(kFuncConvHost, FuncBuilder0<double>());
vector<X86XmmVar> workspaceVar(workspace.size());
for (int i = 0; i < (int) workspaceVar.size(); i++)
workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
X86GpVar workspacePointer(c);
X86GpVar argsPointer(c);
c.mov(workspacePointer, imm_ptr(&workspace[0]));
c.mov(argsPointer, imm_ptr(&argValues[0]));
// Load the arguments into variables.
for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
map<string, int>::iterator index = variableIndices.find(*iter);
c.movsd(workspaceVar[index->second], x86::ptr(workspacePointer, 8*index->second, 0));
}
// Make a list of all constants that will be needed for evaluation.
vector<int> operationConstantIndex(operation.size(), -1);
for (int step = 0; step < (int) operation.size(); step++) {
// Find the constant value (if any) used by this operation.
Operation& op = *operation[step];
double value;
if (op.getId() == Operation::CONSTANT)
value = dynamic_cast<Operation::Constant&>(op).getValue();
else if (op.getId() == Operation::ADD_CONSTANT)
value = dynamic_cast<Operation::AddConstant&>(op).getValue();
else if (op.getId() == Operation::MULTIPLY_CONSTANT)
value = dynamic_cast<Operation::MultiplyConstant&>(op).getValue();
else if (op.getId() == Operation::RECIPROCAL)
value = 1.0;
else if (op.getId() == Operation::STEP)
value = 1.0;
else if (op.getId() == Operation::DELTA)
value = 1.0;
else
continue;
// See if we already have a variable for this constant.
for (int i = 0; i < (int) constants.size(); i++)
if (value == constants[i]) {
operationConstantIndex[step] = i;
break;
}
if (operationConstantIndex[step] == -1) {
operationConstantIndex[step] = constants.size();
constants.push_back(value);
}
}
// Load constants into variables.
vector<X86XmmVar> constantVar(constants.size());
if (constants.size() > 0) {
X86GpVar constantsPointer(c);
c.mov(constantsPointer, imm_ptr(&constants[0]));
for (int i = 0; i < (int) constants.size(); i++) {
constantVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
c.movsd(constantVar[i], x86::ptr(constantsPointer, 8*i, 0));
}
}
// Evaluate the operations.
for (int step = 0; step < (int) operation.size(); step++) {
Operation& op = *operation[step];
vector<int> args = arguments[step];
if (args.size() == 1) {
// One or more sequential arguments. Fill out the list.
for (int i = 1; i < op.getNumArguments(); i++)
args.push_back(args[0]+i);
}
// Generate instructions to execute this operation.
switch (op.getId()) {
case Operation::CONSTANT:
c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::ADD:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.addsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::SUBTRACT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.subsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::MULTIPLY:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::DIVIDE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.divsd(workspaceVar[target[step]], workspaceVar[args[1]]);
break;
case Operation::NEGATE:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.subsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::SQRT:
c.sqrtsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::EXP:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], exp);
break;
case Operation::LOG:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], log);
break;
case Operation::SIN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sin);
break;
case Operation::COS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cos);
break;
case Operation::TAN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tan);
break;
case Operation::ASIN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asin);
break;
case Operation::ACOS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acos);
break;
case Operation::ATAN:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atan);
break;
case Operation::SINH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sinh);
break;
case Operation::COSH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cosh);
break;
case Operation::TANH:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tanh);
break;
case Operation::STEP:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(18)); // Comparison mode is _CMP_LE_OQ = 18
c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::DELTA:
c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::SQUARE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::CUBE:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::RECIPROCAL:
c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
c.divsd(workspaceVar[target[step]], workspaceVar[args[0]]);
break;
case Operation::ADD_CONSTANT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.addsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::MULTIPLY_CONSTANT:
c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
c.mulsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
break;
case Operation::ABS:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], fabs);
break;
case Operation::FLOOR:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], floor);
break;
case Operation::CEIL:
generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], ceil);
break;
default:
// Just invoke evaluateOperation().
for (int i = 0; i < (int) args.size(); i++)
c.movsd(x86::ptr(argsPointer, 8*i, 0), workspaceVar[args[i]]);
X86GpVar fn(c, kVarTypeIntPtr);
c.mov(fn, imm_ptr((void*) evaluateOperation));
X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder2<double, Operation*, double*>());
call->setArg(0, imm_ptr(&op));
call->setArg(1, imm_ptr(&argValues[0]));
call->setRet(0, workspaceVar[target[step]]);
}
}
c.ret(workspaceVar[workspace.size()-1]);
c.endFunc();
jitCode = c.make();
}
void CompiledExpression::generateSingleArgCall(X86Compiler& c, X86XmmVar& dest, X86XmmVar& arg, double (*function)(double)) {
X86GpVar fn(c, kVarTypeIntPtr);
c.mov(fn, imm_ptr((void*) function));
X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<double, double>());
call->setArg(0, arg);
call->setRet(0, dest);
}
#endif
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009 Stanford University and the Authors. *
* Portions copyright (c) 2009-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -38,25 +38,25 @@ using namespace std;
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const vector<ExpressionTreeNode>& children) : operation(operation), children(children) {
if (operation->getNumArguments() != children.size())
throw Exception("Parse error: wrong number of arguments to function: "+operation->getName());
throw Exception("wrong number of arguments to function: "+operation->getName());
}
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child1, const ExpressionTreeNode& child2) : operation(operation) {
children.push_back(child1);
children.push_back(child2);
if (operation->getNumArguments() != children.size())
throw Exception("Parse error: wrong number of arguments to function: "+operation->getName());
throw Exception("wrong number of arguments to function: "+operation->getName());
}
ExpressionTreeNode::ExpressionTreeNode(Operation* operation, const ExpressionTreeNode& child) : operation(operation) {
children.push_back(child);
if (operation->getNumArguments() != children.size())
throw Exception("Parse error: wrong number of arguments to function: "+operation->getName());
throw Exception("wrong number of arguments to function: "+operation->getName());
}
ExpressionTreeNode::ExpressionTreeNode(Operation* operation) : operation(operation) {
if (operation->getNumArguments() != children.size())
throw Exception("Parse error: wrong number of arguments to function: "+operation->getName());
throw Exception("wrong number of arguments to function: "+operation->getName());
}
ExpressionTreeNode::ExpressionTreeNode(const ExpressionTreeNode& node) : operation(&node.getOperation() == NULL ? NULL : node.getOperation().clone()), children(node.getChildren()) {
......
......@@ -317,3 +317,11 @@ ExpressionTreeNode Operation::Abs::differentiate(const std::vector<ExpressionTre
ExpressionTreeNode(new Operation::AddConstant(-1),
ExpressionTreeNode(new Operation::MultiplyConstant(2), step)));
}
ExpressionTreeNode Operation::Floor::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs, const std::string& variable) const {
return ExpressionTreeNode(new Operation::Constant(0.0));
}
ExpressionTreeNode Operation::Ceil::differentiate(const std::vector<ExpressionTreeNode>& children, const std::vector<ExpressionTreeNode>& childDerivs, const std::string& variable) const {
return ExpressionTreeNode(new Operation::Constant(0.0));
}
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2013 Stanford University and the Authors. *
* Portions copyright (c) 2009-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -150,51 +150,56 @@ ParsedExpression Parser::parse(const string& expression) {
}
ParsedExpression Parser::parse(const string& expression, const map<string, CustomFunction*>& customFunctions) {
// First split the expression into subexpressions.
try {
// First split the expression into subexpressions.
string primaryExpression = expression;
vector<string> subexpressions;
while (true) {
string::size_type pos = primaryExpression.find_last_of(';');
if (pos == string::npos)
break;
string sub = trim(primaryExpression.substr(pos+1));
if (sub.size() > 0)
subexpressions.push_back(sub);
primaryExpression = primaryExpression.substr(0, pos);
}
string primaryExpression = expression;
vector<string> subexpressions;
while (true) {
string::size_type pos = primaryExpression.find_last_of(';');
if (pos == string::npos)
break;
string sub = trim(primaryExpression.substr(pos+1));
if (sub.size() > 0)
subexpressions.push_back(sub);
primaryExpression = primaryExpression.substr(0, pos);
}
// Parse the subexpressions.
map<string, ExpressionTreeNode> subexpDefs;
for (int i = 0; i < (int) subexpressions.size(); i++) {
string::size_type equalsPos = subexpressions[i].find('=');
if (equalsPos == string::npos)
throw Exception("subexpression does not specify a name");
string name = trim(subexpressions[i].substr(0, equalsPos));
if (name.size() == 0)
throw Exception("subexpression does not specify a name");
vector<ParseToken> tokens = tokenize(subexpressions[i].substr(equalsPos+1));
int pos = 0;
subexpDefs[name] = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
if (pos != tokens.size())
throw Exception("unexpected text at end of subexpression: "+tokens[pos].getText());
}
// Parse the subexpressions.
// Now parse the primary expression.
map<string, ExpressionTreeNode> subexpDefs;
for (int i = 0; i < (int) subexpressions.size(); i++) {
string::size_type equalsPos = subexpressions[i].find('=');
if (equalsPos == string::npos)
throw Exception("Parse error: subexpression does not specify a name");
string name = trim(subexpressions[i].substr(0, equalsPos));
if (name.size() == 0)
throw Exception("Parse error: subexpression does not specify a name");
vector<ParseToken> tokens = tokenize(subexpressions[i].substr(equalsPos+1));
vector<ParseToken> tokens = tokenize(primaryExpression);
int pos = 0;
subexpDefs[name] = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
ExpressionTreeNode result = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
if (pos != tokens.size())
throw Exception("Parse error: unexpected text at end of subexpression: "+tokens[pos].getText());
throw Exception("unexpected text at end of expression: "+tokens[pos].getText());
return ParsedExpression(result);
}
catch (Exception& ex) {
throw Exception("Parse error in expression \""+expression+"\": "+ex.what());
}
// Now parse the primary expression.
vector<ParseToken> tokens = tokenize(primaryExpression);
int pos = 0;
ExpressionTreeNode result = parsePrecedence(tokens, pos, customFunctions, subexpDefs, 0);
if (pos != tokens.size())
throw Exception("Parse error: unexpected text at end of expression: "+tokens[pos].getText());
return ParsedExpression(result);
}
ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int& pos, const map<string, CustomFunction*>& customFunctions,
const map<string, ExpressionTreeNode>& subexpressionDefs, int precedence) {
if (pos == tokens.size())
throw Exception("Parse error: unexpected end of expression");
throw Exception("unexpected end of expression");
// Parse the next value (number, variable, function, parenthesized expression)
......@@ -220,7 +225,7 @@ ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int
pos++;
result = parsePrecedence(tokens, pos, customFunctions, subexpressionDefs, 0);
if (pos == tokens.size() || tokens[pos].getType() != ParseToken::RightParen)
throw Exception("Parse error: unbalanced parentheses");
throw Exception("unbalanced parentheses");
pos++;
}
else if (token.getType() == ParseToken::Function) {
......@@ -234,7 +239,7 @@ ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int
pos++;
} while (moreArgs);
if (pos == tokens.size() || tokens[pos].getType() != ParseToken::RightParen)
throw Exception("Parse error: unbalanced parentheses");
throw Exception("unbalanced parentheses");
pos++;
Operation* op = getFunctionOperation(token.getText(), customFunctions);
try {
......@@ -251,7 +256,7 @@ ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int
result = ExpressionTreeNode(new Operation::Negate(), toNegate);
}
else
throw Exception("Parse error: unexpected token: "+token.getText());
throw Exception("unexpected token: "+token.getText());
// Now deal with the next binary operator.
......@@ -288,7 +293,7 @@ Operation* Parser::getOperatorOperation(const std::string& name) {
case Operation::POWER:
return new Operation::Power();
default:
throw Exception("Parse error: unknown operator");
throw Exception("unknown operator");
}
}
......@@ -321,6 +326,8 @@ Operation* Parser::getFunctionOperation(const std::string& name, const map<strin
opMap["min"] = Operation::MIN;
opMap["max"] = Operation::MAX;
opMap["abs"] = Operation::ABS;
opMap["floor"] = Operation::FLOOR;
opMap["ceil"] = Operation::CEIL;
}
string trimmed = name.substr(0, name.size()-1);
......@@ -334,7 +341,7 @@ Operation* Parser::getFunctionOperation(const std::string& name, const map<strin
map<string, Operation::Id>::const_iterator iter = opMap.find(trimmed);
if (iter == opMap.end())
throw Exception("Parse error: unknown function: "+trimmed);
throw Exception("unknown function: "+trimmed);
switch (iter->second) {
case Operation::SQRT:
return new Operation::Sqrt();
......@@ -386,7 +393,11 @@ Operation* Parser::getFunctionOperation(const std::string& name, const map<strin
return new Operation::Max();
case Operation::ABS:
return new Operation::Abs();
case Operation::FLOOR:
return new Operation::Floor();
case Operation::CEIL:
return new Operation::Ceil();
default:
throw Exception("Parse error: unknown function");
throw Exception("unknown function");
}
}
......@@ -83,7 +83,7 @@ typedef StringStringVectorMap::const_iterator StringStringVectorMapCI;
class ValidateOpenMM {
public:
ValidateOpenMM( void );
ValidateOpenMM();
~ValidateOpenMM();
// force names
......@@ -166,7 +166,7 @@ public:
* @return log
*
*/
FILE* getLog( ) const;
FILE* getLog() const;
/**
*
......
......@@ -41,7 +41,7 @@ typedef MapIntInt::const_iterator MapIntIntCI;
class ForceValidationResult {
public:
ForceValidationResult( const Context& context1, const Context& context2, StringUIntMap& forceNamesMap );
ForceValidationResult(const Context& context1, const Context& context2, StringUIntMap& forceNamesMap);
~ForceValidationResult();
/**
......@@ -51,7 +51,7 @@ public:
*
* @throws OpenMMException if energyIndex is not 0 or 1
*/
double getPotentialEnergy( int energyIndex ) const;
double getPotentialEnergy(int energyIndex) const;
/**
* Get array of forces at specified platform index (0 || 1)
......@@ -60,7 +60,7 @@ public:
*
* @throws OpenMMException if forceIndex is not 0 or 1
*/
std::vector<double> getForceNorms( int forceIndex ) const;
std::vector<double> getForceNorms(int forceIndex) const;
/**
* Get array of forces at platform index (0 || 1)
......@@ -69,7 +69,7 @@ public:
*
* @throws OpenMMException if forceIndex is not 0 or 1
*/
std::vector<Vec3> getForces( int forceIndex ) const;
std::vector<Vec3> getForces(int forceIndex) const;
/**
* Get maximum delta in force norm
......@@ -78,7 +78,7 @@ public:
*
* @return max delta in norm of forces
*/
double getMaxDeltaForceNorm( int* maxIndex = NULL ) const;
double getMaxDeltaForceNorm(int* maxIndex = NULL) const;
/**
* Get maximum relative delta in force norm
......@@ -87,7 +87,7 @@ public:
*
* @return max relative delta in norm of forces
*/
double getMaxRelativeDeltaForceNorm( int* maxIndex = NULL ) const;
double getMaxRelativeDeltaForceNorm(int* maxIndex = NULL) const;
/**
* Get maximum dot product between forces
......@@ -96,7 +96,7 @@ public:
*
* @return max dot product between forces
*/
double getMaxDotProduct( int* maxIndex = NULL ) const;
double getMaxDotProduct(int* maxIndex = NULL) const;
/**
* Get name of force associated w/ computed results
......@@ -104,7 +104,7 @@ public:
* @return force name(s); if more than one force active in computation,
* then names are concatenated and separated by '::' (e.g., 'NB_FORCE::GBSA_OBC_FORCE')
*/
std::string getForceName( void ) const;
std::string getForceName() const;
/**
* Get platform name
......@@ -115,7 +115,7 @@ public:
*
* @throws OpenMMException if index is not 0 or 1
*/
std::string getPlatformName( int index ) const;
std::string getPlatformName(int index) const;
/**
* Register index of two entries that differ by a specified tolerance
......@@ -123,46 +123,46 @@ public:
* @param index inconsistent index
*
*/
void registerInconsistentForceIndex( int index, int value = 1 );
void registerInconsistentForceIndex(int index, int value = 1);
/**
* Clear list of entries that differ by a specified tolerance
*
*/
void clearInconsistentForceIndexList( void );
void clearInconsistentForceIndexList();
/**
* Get list of entries that differ by a specified tolerance
*
*/
void getInconsistentForceIndexList( std::vector<int>& inconsistentIndices ) const;
void getInconsistentForceIndexList(std::vector<int>& inconsistentIndices) const;
/**
* Get number of entries in inconsistent index list
*
*/
int getNumberOfInconsistentForceEntries( void ) const;
int getNumberOfInconsistentForceEntries() const;
/**
* Return true if nans were detected
*
* @return true if nans were detected
*/
int nansDetected( void ) const;
int nansDetected() const;
/**
* Determine if force norms are valid
*
* @param tolerance tolerance
*/
void compareForceNorms( double tolerance );
void compareForceNorms(double tolerance);
/**
* Determine if forces are valid
*
* @param tolerance tolerance
*/
void compareForces( double tolerance );
void compareForces(double tolerance);
private:
......@@ -193,13 +193,13 @@ private:
* Calculate norms of vectors
*
*/
void _calculateNorms( void );
void _calculateNorms();
/**
* Calculate norms of specified vector
*
*/
void _calculateNormOfForceVector( int forceIndex );
void _calculateNormOfForceVector(int forceIndex);
// stat indices
......@@ -216,7 +216,7 @@ private:
* Find vector stats
*
*/
void _findStatsForDouble( const std::vector<double>& array, std::vector<double>& statVector ) const;
void _findStatsForDouble(const std::vector<double>& array, std::vector<double>& statVector) const;
};
// Class used to compare forces/potential energies on two platforms
......@@ -224,7 +224,7 @@ private:
class ValidateOpenMMForces : public ValidateOpenMM {
public:
OPENMM_VALIDATE_EXPORT ValidateOpenMMForces( void );
OPENMM_VALIDATE_EXPORT ValidateOpenMMForces();
OPENMM_VALIDATE_EXPORT ~ValidateOpenMMForces();
/**
......@@ -236,7 +236,7 @@ public:
*
* @return number of inconsistent entries
*/
int OPENMM_VALIDATE_EXPORT compareWithReferencePlatform(Context& context, std::string* summaryString = NULL );
int OPENMM_VALIDATE_EXPORT compareWithReferencePlatform(Context& context, std::string* summaryString = NULL);
/**
* Validate force/energy by comparing the results between the forces/energies computed on two different platforms
......@@ -250,7 +250,7 @@ public:
* on the two input platforms
*/
ForceValidationResult* compareForce(Context& context, std::vector<int>& compareForces,
Platform& platform1, Platform& platform2 ) const;
Platform& platform1, Platform& platform2) const;
/**
* Compare individual forces by comparing calculations across two platforms (platform associated w/ input context and
......@@ -261,42 +261,42 @@ public:
* @param forceValidationResults output vector of ForceValidationResult ptrs (user is responsible for deleting
* individual ForceValidationResult objects)
*/
void compareOpenMMForces(Context& context, Platform& comparisonPlatform, std::vector<ForceValidationResult*>& forceValidationResults ) const;
void compareOpenMMForces(Context& context, Platform& comparisonPlatform, std::vector<ForceValidationResult*>& forceValidationResults) const;
/**
* Determine if results are consistent
*
* @param forceValidationResults vector of ForceValidationResult ptrs to check if forces are consistent
*/
void checkForInconsistentForceEntries( std::vector<ForceValidationResult*>& forceValidationResults ) const;
void checkForInconsistentForceEntries(std::vector<ForceValidationResult*>& forceValidationResults) const;
/**
* Get total number of force entries that are inconsistent
*
* @param forceValidationResults vector of ForceValidationResult ptrs to check if forces are consistent
*/
int getTotalNumberOfInconsistentForceEntries( std::vector<ForceValidationResult*>& forceValidationResults ) const;
int getTotalNumberOfInconsistentForceEntries(std::vector<ForceValidationResult*>& forceValidationResults) const;
/**
* Get summary string of results
*
* @param forceValidationResults vector of ForceValidationResult ptrs
*/
std::string getSummary( std::vector<ForceValidationResult*>& forceValidationResults ) const;
std::string getSummary(std::vector<ForceValidationResult*>& forceValidationResults) const;
/**
* Set force tolerance
*
* @param tolerance force tolerance
*/
void setForceTolerance( double tolerance );
void setForceTolerance(double tolerance);
/**
* Get force tolerance
*
* @return force tolerance
*/
double getForceTolerance( void ) const;
double getForceTolerance() const;
/*
* Get force tolerance for specified force
......@@ -307,7 +307,7 @@ public:
*
* */
double getForceTolerance( const std::string& forceName ) const;
double getForceTolerance(const std::string& forceName) const;
/*
* Get max errors to print in summary string
......@@ -316,7 +316,7 @@ public:
*
* */
int getMaxErrorsToPrint( void ) const;
int getMaxErrorsToPrint() const;
/*
* Set max errors to print in summary string
......@@ -325,7 +325,7 @@ public:
*
* */
void setMaxErrorsToPrint( int maxErrorsToPrint );
void setMaxErrorsToPrint(int maxErrorsToPrint);
/*
* Return true if force is not to be validated (Andersen thermostat, CM motion remover, ...)
......@@ -335,13 +335,13 @@ public:
* @return true if force is not currently validated
**/
int isExcludedForce( std::string forceName ) const;
int isExcludedForce(std::string forceName) const;
private:
// initialize class entries
void _initialize( void );
void _initialize();
/*
* Format output line
......@@ -354,9 +354,9 @@ private:
*
* */
std::string _getLine( const std::string& tab,
const std::string& description,
const std::string& value ) const;
std::string _getLine(const std::string& tab,
const std::string& description,
const std::string& value) const;
std::vector<ForceValidationResult*> _forceValidationResults;
......
......@@ -54,7 +54,7 @@ const std::string ValidateOpenMM::CUSTOM_EXTERNAL_FORCE = "CustomExter
const std::string ValidateOpenMM::CUSTOM_NONBONDED_FORCE = "CustomNonBonded";
ValidateOpenMM::ValidateOpenMM( void ) {
ValidateOpenMM::ValidateOpenMM() {
_log = NULL;
......@@ -82,7 +82,7 @@ int ValidateOpenMM::isNanOrInfinity( double number ){
return (number != number || number == std::numeric_limits<double>::infinity() || number == -std::numeric_limits<double>::infinity()) ? 1 : 0;
}
FILE* ValidateOpenMM::getLog( void ) const {
FILE* ValidateOpenMM::getLog() const {
return _log;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment