From 0952e7673d713b43c359d44057c7278306599631 Mon Sep 17 00:00:00 2001 From: marian Date: Mon, 20 Jul 2015 11:04:45 +0000 Subject: [PATCH] Added math slice vector. git-svn-id: http://yate.null.ro/svn/yate/trunk@6006 acf43c95-373e-0410-b603-e72c3f656dc1 --- Makefile.in | 4 +- engine/Makefile.in | 3 +- engine/Math.cpp | 328 +++++++++ yatemath.h | 1691 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2023 insertions(+), 3 deletions(-) create mode 100644 engine/Math.cpp create mode 100644 yatemath.h diff --git a/Makefile.in b/Makefile.in index f2d498ef..24b292b5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,7 +32,7 @@ SLIBS:= $(YLIB) libyate.so \ libyatemgcp.so.@PACKAGE_VERSION@ libyatemgcp.so \ libyatejabber.so.@PACKAGE_VERSION@ libyatejabber.so ILIBS:= yscript yasn yradio -INCS := yateclass.h yatemime.h yatengine.h yatephone.h yatecbase.h yatexml.h +INCS := yateclass.h yatemime.h yatengine.h yatephone.h yatecbase.h yatexml.h yatemath.h GENS := yateversn.h LIBS := MAN8 := yate.8 yate-config.8 @@ -165,7 +165,7 @@ apidocs: $(APIINDEX) $(APIINDEX): @srcdir@/docs/Doxyfile \ @srcdir@/yateclass.h @srcdir@/yatemime.h @srcdir@/yatengine.h \ - @srcdir@/yatephone.h @srcdir@/yatecbase.h + @srcdir@/yatephone.h @srcdir@/yatecbase.h @srcdir@/yatemath.h $(MAKE) apidocs-build .PHONY: strip sex love war diff --git a/engine/Makefile.in b/engine/Makefile.in index e480414b..d6453890 100644 --- a/engine/Makefile.in +++ b/engine/Makefile.in @@ -29,7 +29,8 @@ LIBS := CLSOBJS := TelEngine.o ObjList.o HashList.o Mutex.o Thread.o Socket.o Resolver.o \ String.o DataBlock.o NamedList.o \ URI.o Mime.o Array.o Iterator.o XML.o \ - Hasher.o YMD5.o YSHA1.o YSHA256.o Base64.o Cipher.o Compressor.o + Hasher.o YMD5.o YSHA1.o YSHA256.o Base64.o Cipher.o Compressor.o \ + Math.o ENGOBJS := Configuration.o Message.o Engine.o Plugin.o TELOBJS := DataFormat.o Channel.o CLIOBJS := Client.o ClientLogic.o diff --git a/engine/Math.cpp b/engine/Math.cpp new file mode 100644 index 00000000..f0a0467c --- /dev/null +++ b/engine/Math.cpp @@ -0,0 +1,328 @@ +/** + * Math.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2015 Null Team + * + * This software is distributed under multiple licenses; + * see the COPYING file in the main directory for licensing + * information for this specific distribution. + * + * This use of this software may be subject to additional restrictions. + * See the LEGAL file in the main directory for details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "yatemath.h" + +using namespace TelEngine; + +#ifdef DEBUG +#define YBITVECTOR_VALID(meth,offs,len) { \ + BitVector tmp(*this,offs,len); \ + if (!tmp.valid()) \ + Debug(DebugFail,"BitVector::%s contains non 0/1 value [%p]",meth,this); \ +} +#else +#ifdef _WINDOWS +#define YBITVECTOR_VALID do { break; } while +#else +#define YBITVECTOR_VALID(meth,offs,len) +#endif +#endif + + +static inline bool isBitSet(uint8_t val) +{ + return val != 0; +} + +// Unpack 8 bits to buffer, MSB first +// Advance the buffer +static inline void unpackMsb8(uint8_t*& d, uint8_t val) +{ + *d++ = (val >> 7) & 0x01; + *d++ = (val >> 6) & 0x01; + *d++ = (val >> 5) & 0x01; + *d++ = (val >> 4) & 0x01; + *d++ = (val >> 3) & 0x01; + *d++ = (val >> 2) & 0x01; + *d++ = (val >> 1) & 0x01; + *d++ = val & 0x01; +} + +// Copy string, advance dest and src, return src +static inline const char* copyInc(char*& dest, const char* src, unsigned int n) +{ + if (n) { + ::strncpy(dest,src,n); + dest += n; + } + return src + n; +} + + +// +// RefStorage +// +String& RefStorage::dumpSplit(String& buf, const String& str, unsigned int lineLen, + unsigned int offset, const char* linePrefix, const char* suffix) +{ + suffix = TelEngine::c_safe(suffix); + if (TelEngine::null(linePrefix)) + linePrefix = suffix; + unsigned int len = str.length(); + unsigned int linePrefLen = ::strlen(linePrefix); + // No lines ? + if (!(lineLen && len && linePrefLen && lineLen < len)) + return buf << str << suffix; + unsigned int firstLineLen = 0; + if (offset && offset < lineLen) { + firstLineLen = lineLen - offset; + if (firstLineLen > len) + firstLineLen = len; + len -= firstLineLen; + // Nothing to be added after first line ? + if (!len) + return buf << str << suffix; + } + unsigned int nFullLines = len / lineLen; + unsigned int lastLineLen = len % lineLen; + unsigned int suffixLen = ::strlen(suffix); + unsigned int nSep = nFullLines + (lastLineLen ? 1 : 0); + char* tmpBuf = new char[str.length() + nSep * linePrefLen + suffixLen + 1]; + char* dest = tmpBuf; + const char* src = str.c_str(); + src = copyInc(dest,src,firstLineLen); + for (; nFullLines; nFullLines--) { + copyInc(dest,linePrefix,linePrefLen); + src = copyInc(dest,src,lineLen); + } + if (lastLineLen) { + copyInc(dest,linePrefix,linePrefLen); + src = copyInc(dest,src,lastLineLen); + } + copyInc(dest,suffix,suffixLen); + *dest = 0; + buf << tmpBuf; + delete[] tmpBuf; + return buf; +} + + +// +// BitVector +// +BitVector::BitVector(const char* str, unsigned int maxLen) + : ByteVector(::strlen(TelEngine::c_safe(str)),0,maxLen) +{ + uint8_t* d = data(); + for (uint8_t* last = end(d,length()); d != last; ++d, ++str) + if (*str == '1') + *d = 1; +} + +// Check if this vector contains valid values (0 or 1) +bool BitVector::valid() const +{ + const uint8_t* d = data(); + for (const uint8_t* last = end(d,length()); d != last; ++d) + if (*d > 1) + return false; + return true; +} + +bool BitVector::get(FloatVector& dest) const +{ + YBITVECTOR_VALID("get()",0,length()); + if (!dest.resize(length())) + return false; + float* d = dest.data(); + const uint8_t* src = data(); + for (const uint8_t* last = end(src,length()); src != last; ++src, ++d) + *d = isBitSet(*src) ? 1.0F : 0.0F; + return true; +} + +bool BitVector::set(const FloatVector& input) +{ + if (!resize(input.length())) + return false; + const float* src = input.data(); + uint8_t* d = data(); + for (uint8_t* last = end(d,length()); d != last; ++d, ++src) + *d = *src ? 1 : 0; + return true; +} + +// Apply XOR on vector bits from value, MSB first +void BitVector::xorMsb(uint32_t value, unsigned int offs, uint8_t len) +{ + len = (uint8_t)availableClamp(32,offs,len); + uint8_t* d = data(offs,len); + if (!d) + return; + YBITVECTOR_VALID("xorMsb()",offs,len); + uint8_t shift = 24; + for (uint8_t full = len / 8; full; --full, shift -= 8) { + uint8_t v = (uint8_t)(value >> shift); + *d++ ^= (v >> 7) & 0x01; + *d++ ^= (v >> 6) & 0x01; + *d++ ^= (v >> 5) & 0x01; + *d++ ^= (v >> 4) & 0x01; + *d++ ^= (v >> 3) & 0x01; + *d++ ^= (v >> 2) & 0x01; + *d++ ^= (v >> 1) & 0x01; + *d++ ^= v & 0x01; + } + uint8_t rest = len % 8; + if (!rest) + return; + uint8_t v = (uint8_t)(value >> (shift + 8 - rest)); + uint8_t* stop = --d; + for (d = stop + rest; d != stop; --d, v >>= 1) + *d ^= v & 0x01; +} + +// Pack up to 64 bits, LSB first +uint64_t BitVector::pack(unsigned int offs, int len) const +{ + len = (int)availableClamp(64,offs,len); + const uint8_t* d = data(offs,len); + if (!d) + return 0; + YBITVECTOR_VALID("pack()",offs,len); + uint64_t res = 0; + for (int i = 0; i < len; ++i, ++d) + if (isBitSet(*d)) + res |= (uint64_t)1 << i; + return res; +} + +// Unpack up to 64 bits into this vector, LSB first +void BitVector::unpack(uint64_t value, unsigned int offs, uint8_t len) +{ + len = (uint8_t)availableClamp(64,offs,len); + YBITVECTOR_VALID("unpack()",offs,len); + uint8_t* d = data(offs,len); + for (uint8_t* last = end(d,len); d != last; ++d, value >>= 1) + *d = (uint8_t)(value & 0x01); +} + +// Unpack up to 32 bits into this vector (MSB to LSB). +// MSB from value is the first unpacked bit +void BitVector::unpackMsb(uint32_t value, unsigned int offs, uint8_t len) +{ + len = (uint8_t)availableClamp(32,offs,len); + uint8_t* d = data(offs,len); + if (!d) + return; + YBITVECTOR_VALID("unpackMsb()",offs,len); + uint8_t shift = 24; + for (uint8_t full = len / 8; full; --full, shift -= 8) + unpackMsb8(d,value >> shift); + uint8_t rest = len % 8; + if (!rest) + return; + uint8_t v = (uint8_t)(value >> (shift + 8 - rest)); + uint8_t* stop = --d; + for (d = stop + rest; d != stop; --d, v >>= 1) + *d = v & 0x01; +} + +// Pack bits into a ByteVector +bool BitVector::pack(ByteVector& dest) const +{ + if (!length()) + return 0; + unsigned int full = length() / 8; + unsigned int rest = length() % 8; + unsigned int n = full + (rest ? 1 : 0); + uint8_t* d = dest.data(0,n); + if (!d) { + YMATH_FAIL(false, + "BitVector::pack() not enough data in destination vector [%p]",this); + return false; + } + YBITVECTOR_VALID("pack()",0,length()); + dest.bzero(0,n); + const uint8_t* src = data(); + // Full bytes + for (const uint8_t* last = end(src,full * 8); src != last; ++d) { +#define SET_BIT(bit) if (isBitSet(*src++)) *d |= (1 << bit); + SET_BIT(7); + SET_BIT(6); + SET_BIT(5); + SET_BIT(4); + SET_BIT(3); + SET_BIT(2); + SET_BIT(1); + SET_BIT(0); +#undef SET_BIT + } + // Partial byte + if (rest) + for (uint8_t val = 0x80; rest; --rest, val >>= 1) + if (isBitSet(*src++)) + *d |= val; + return true; +} + +// Unpack a ByteVector into this BitVector +// MSB bit of the first element in source goes to first bit in this vector +bool BitVector::unpack(const ByteVector& src) +{ + const uint8_t* s = src.data(0,src.length()); + if (!s) + return true; + unsigned int len = src.length() * 8; + uint8_t* d = data(0,len); + if (d) { + YBITVECTOR_VALID("unpack()",0,length()); + for(uint8_t* last = end(d,len); d != last; ++s) + unpackMsb8(d,*s); + return true; + } + YMATH_FAIL(false,"BitVector::unpack() not enough space in vector [%p]",this); + return false; +} + +// Append bits to a string +String& BitVector::appendTo(String& buf, unsigned int offs, int len) const +{ + len = available(offs,len); + const uint8_t* d = data(offs,len); + if (!d) + return buf; + YBITVECTOR_VALID("appendTo()",offs,len); + String tmp('0',len); + char* s = (char*)tmp.c_str(); + for (const uint8_t* last = end(d,len); d != last; ++d, ++s) + if (isBitSet(*d)) + *s = '1'; + return buf.append(tmp); +} + + +// +// Math +// +// Append a Complex number to a String (using "%g%+gi" format) +String& Math::dumpComplex(String& dest, const Complex& val, const char* sep) +{ + String tmp; + return dest.append(tmp.printf("%g%+gi",val.re(),val.im()),sep); +} + +// Append float value to a String (using %g format) +String& Math::dumpFloat(String& dest, const float& val, const char* sep) +{ + String tmp; + return dest.append(tmp.printf("%g",val),sep); +} + +/* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/yatemath.h b/yatemath.h new file mode 100644 index 00000000..cd18ff7c --- /dev/null +++ b/yatemath.h @@ -0,0 +1,1691 @@ +/** + * yatemath.h + * This file is part of the YATE Project http://YATE.null.ro + * + * Math data types + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2014 Null Team + * + * This software is distributed under multiple licenses; + * see the COPYING file in the main directory for licensing + * information for this specific distribution. + * + * This use of this software may be subject to additional restrictions. + * See the LEGAL file in the main directory for details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef __YATEMATH_H +#define __YATEMATH_H + +#include +#include +#include + +namespace TelEngine { + +#ifdef DEBUG +#define YMATH_FAIL(cond,args...) { \ + if (!(cond)) \ + Debug(DebugFail,args); \ +} +#else +#ifdef _WINDOWS +#define YMATH_FAIL do { break; } while +#else +#define YMATH_FAIL(arg...) +#endif +#endif + +/** + * This class implements a complex number + * @short A Complex (float) number + */ +class YATE_API Complex +{ +public: + /** + * Constructor + */ + inline Complex() + : m_real(0), m_imag(0) + {} + + /** + * Constructor + * @param real The real part of the complex number + * @param imag The imaginary part of a complex number + */ + inline Complex(float real, float imag = 0) + : m_real(real), m_imag(imag) + {} + + /** + * Copy constructor + * @param c The source complex number + */ + inline Complex(const Complex& c) + : m_real(c.m_real), m_imag(c.m_imag) + {} + + /** + * Obtain the real part of the complex number + * @return The real part + */ + inline float re() const + { return m_real; } + + /** + * Set the real part of the complex number + * @param r The new real part value + */ + inline void re(float r) + { m_real = r; } + + /** + * Obtain the imaginary part of a complex number + * @return The imaginary part + */ + inline float im() const + { return m_imag; } + + /** + * Set the imaginary part of the complex number + * @param i The new imaginary part value + */ + inline void im(float i) + { m_imag = i; } + + /** + * Set data + * @param r The real part of the complex number + * @param i The imaginary part of a complex number + * @return A reference to this object + */ + inline Complex& set(float r = 0, float i = 0) { + m_real = r; + m_imag = i; + return *this; + } + + /** + * Equality operator + * @param c Complex number to compare with + * @return True if equal, false otherwise + */ + inline bool operator==(const Complex& c) const + { return m_real == c.m_real && m_imag == c.m_imag; } + + /** + * Inequality operator + * @param c Complex number to compare with + * @return True if not equal, false otherwise + */ + inline bool operator!=(const Complex& c) const + { return m_real != c.m_real || m_imag != c.m_imag; } + + /** + * Assignment operator + * @param c Complex number to assign + * @return A reference to this object + */ + inline Complex& operator=(const Complex& c) + { return set(c.m_real,c.m_imag); } + + /** + * Assignment operator. Set the real part, reset the imaginary one + * @param real New real part value + * @return A reference to this object + */ + inline Complex& operator=(float real) + { return set(real); } + + /** + * Addition operator + * @param c Complex number to add + * @return A reference to this object + */ + inline Complex& operator+=(const Complex& c) + { return set(m_real + c.m_real,m_imag + c.m_imag); } + + /** + * Addition operator. Add a value to the real part + * @param real Value to add to real part + * @return A reference to this object + */ + inline Complex& operator+=(float real) { + m_real += real; + return *this; + } + + /** + * Substraction operator + * @param c Complex number to substract from this one + * @return A reference to this object + */ + inline Complex& operator-=(const Complex& c) + { return set(m_real - c.m_real,m_imag - c.m_imag); } + + /** + * Substraction operator. Substract a value a value from the real part + * @param real Value to substract from real part + * @return A reference to this object + */ + inline Complex& operator-=(float real) { + m_real -= real; + return *this; + } + + /** + * Multiplication operator + * @param c Complex number to multiply with + * @return A reference to this object + */ + inline Complex& operator*=(const Complex& c) { + return set(m_real * c.m_real - m_imag * c.m_imag, + m_real * c.m_imag + m_imag * c.m_real); + } + + /** + * Multiplication operator. Multiply this number with a float number + * @param f Value to multiply with + * @return A reference to this object + */ + inline Complex& operator*=(float f) + { return set(m_real * f,m_imag * f); } + + /** + * Division operator + * @param c Complex number to devide with + * @return A reference to this object + */ + inline Complex& operator/=(const Complex& c) { + float tmp = c.norm2(); + return set((m_real * c.m_real + m_imag * c.m_imag) / tmp, + (-m_real * c.m_imag + m_imag * c.m_real) / tmp); + } + + /** + * Division operator + * @param f Float number to devide with + * @return A reference to this object + */ + inline Complex& operator/=(float f) + { return set(m_real / f,m_imag / f); } + + /** + * Compute the absolute value of this complex number + * @return The result + */ + inline float abs() const + { return ::sqrtf(norm2()); } + + /** + * Compute the modulus value of this complex number + * @return The result + */ + inline float mod() const + { return abs(); } + + /** + * Compute the the argument of this complex number + * @return Ther result + */ + inline float arg() const + { return ::atan(m_imag / m_real); } + + /** + * Computes the exponential of this complex number + * @return The result + */ + inline Complex exp() const { + float r = ::expf(m_real); + return Complex(r * ::cosf(m_imag),r * ::sinf(m_imag)); + } + + /** + * Compute the norm of this complex number + * @return The result + */ + inline float norm() const + { return abs(); } + + /** + * Compute the norm2 value of this complex number + * @return The result + */ + inline float norm2() const + { return m_real * m_real + m_imag * m_imag; } + +private: + float m_real; // The real part + float m_imag; // The imaginary part +}; + + +/** + * This class holds a ref counted storage + * @short A fixed ref counted storage + */ +class YATE_API RefStorage : public RefObject +{ + YCLASS(RefStorage,RefObject) + YNOCOPY(RefStorage); // No automatic copies please +public: + /** + * Constructor + * @param value Data to assign, may be NULL to fill with zeros + * @param len Length of data, may be zero (then value is ignored) + */ + inline RefStorage(const void* value, unsigned int len) + : m_data((void*)value,len) + {} + + /** + * Get the length of the stored data + * @return The length of the stored data, zero for NULL + */ + inline unsigned int length() const + { return m_data.length(); } + + /** + * Get a pointer to a byte range inside the stored data + * @param offs Byte offset inside the stored data + * @param len Number of bytes that must be valid starting at offset (must not be 0) + * @return A pointer to the data or NULL if the range is not available + */ + inline void* data(unsigned int offs, unsigned int len) const + { return len ? m_data.data(offs,len) : 0; } + + /** + * Copy data to this storage + * @param buf Buffer to copy + * @param len The number of bytes to copy + * @param offs The start index in this storage + * @return True on success, false if there is not enough space in our storage or + * the buffer pointer is NULL + */ + inline bool set(const void* buf, unsigned int len, unsigned int offs = 0) + { return copy(data(offs,len),buf,len); } + + /** + * Fill a buffer + * @param dest Destination buffer + * @param len The number of bytes to fill + * @param val Value to fill with + */ + static inline void fill(void* dest, unsigned int len, int val = 0) { + if (dest && len) + ::memset(dest,val,len); + } + + /** + * Copy data + * @param dest Destination buffer + * @param src Source buffer + * @param len The number of bytes to copy + * @return True on success, false if parameters are invalid + */ + static inline bool copy(void* dest, const void* src, unsigned int len) { + if (!(len && dest && src)) + return len == 0; + if (dest != src) + ::memcpy(dest,src,len); + return true; + } + + /** + * Compare data + * @param buf1 First buffer + * @param buf2 Second buffer + * @param len The number of bytes to compare + * @return True if equal + */ + static inline bool equals(const void* buf1, const void* buf2, unsigned int len) { + if (len && buf1 && buf2) + return (buf1 == buf2) || (::memcmp(buf1,buf2,len) == 0); + return true; + } + + /** + * Split a string and append lines to another one + * @param buf Destination string + * @param str Input string + * @param lineLen Line length, characters to copy + * @param offset Offset in first line (if incomplete). No data will be + * added on first line if offset is greater then line length + * @param linePrefix Prefix for new lines. + * Set it to empty string or 0 to use the suffix + * @param suffix End of line for the last line + * @return Destination string address + */ + static String& dumpSplit(String& buf, const String& str, unsigned int lineLen, + unsigned int offset = 0, const char* linePrefix = 0, + const char* suffix = "\r\n"); + +private: + RefStorage() {}; // No default constructor please + + DataBlock m_data; +}; + + +/** + * Base class for vector class(es). + * Its purpose is to offer a common interface when processing lists + * @short Base class for vector class(es) + */ +class MathVectorBase : public GenObject +{ + YCLASS(MathVectorBase,GenObject) +public: + /** + * Destructor. Does nothing, keeps the compiler satisfied + */ + virtual ~MathVectorBase() + {} + + /** + * Retrieve vector size in bytes + * @return Vector size in bytes + */ + virtual unsigned int vectorSize() const = 0; +}; + + +/** + * Template for vectors holding a fixed storage and a slice in it. + * This class works with objects not holding pointers: it uses memcpy to copy data + * @short A slice vector + */ +template class SliceVector : public MathVectorBase +{ +public: + /** + * Constructor + */ + inline SliceVector() + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) + {} + + /** + * Copy constructor. + * Builds a slice of another vector + * @param other Original vector + */ + inline SliceVector(const SliceVector& other) + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) + { initSlice(false,other); } + + /** + * Constructor. + * Build the vector storage + * @param len Length of data + * @param buf Optional init buffer ('len' elements will be copied from it to storage) + * @param maxLen Optional vector maximum length + * (it will be adjusted to be at least len) + */ + explicit inline SliceVector(unsigned int len, const Obj* buf = 0, + unsigned int maxLen = 0) + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) + { initStorage(len,buf,maxLen); } + + /** + * Constructor. + * Build a vector by concatenating two existing ones + * @param v1 The first vector + * @param v2 The second vector + */ + explicit inline SliceVector(const SliceVector& v1, const SliceVector& v2) + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) { + if (!initStorage(v1.length(),v1.data(),v1.length() + v2.length())) + return; + resizeMax(); + m_storage->set(v2.data(),v2.size(),v1.size()); + } + + /** + * Constructor. + * Build a vector by concatenating three existing ones + * @param v1 The first vector + * @param v2 The second vector + * @param v3 The third vector + */ + explicit inline SliceVector(const SliceVector& v1, const SliceVector& v2, + const SliceVector& v3) + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) { + unsigned int n = v1.length() + v2.length() + v3.length(); + if (!initStorage(v1.length(),v1.data(),n)) + return; + resizeMax(); + m_storage->set(v2.data(),v2.size(),v1.size()); + m_storage->set(v3.data(),v3.size(),v1.size() + v2.size()); + } + + /** + * Constructor. + * Builds a slice of another vector + * @param other Original vector + * @param offs Offset in the original vector + * @param len The number of elements (0 to use all available from offset) + */ + explicit inline SliceVector(const SliceVector& other, unsigned int offs, + unsigned int len = 0) + : m_storage(0), m_data(0), m_length(0), m_maxLen(0) + { initSlice(false,other,offs,len); } + + /** + * Destructor + */ + virtual ~SliceVector() + { setData(); } + + /** + * Get a pointer to data if 'len' elements are available from offset + * @param offs The offset + * @param len The number of elements to retrieve (must not be 0) + * @return A pointer to data at requested offset, + * NULL if there is not enough data available + */ + inline Obj* data(unsigned int offs, unsigned int len) { + if (len && length() && offs + len <= length()) + return m_data + offs; + return 0; + } + + /** + * Get a pointer to data if 'len' elements are available from offset + * @param offs The offset + * @param len The number of elements to retrieve (must not be 0) + * @return A pointer to data at requested offset, + * NULL if there is not enough data available + */ + inline const Obj* data(unsigned int offs, unsigned int len) const { + if (len && length() && offs + len <= length()) + return m_data + offs; + return 0; + } + + /** + * Get a pointer to data from offset to vector end + * @param offs The offset + * @return A pointer to data at requested offset, NULL if there is no data available + */ + inline Obj* data(unsigned int offs = 0) + { return data(offs,length()); } + + /** + * Get a pointer to data from offset to vector end + * @param offs The offset + * @return A pointer to data at requested offset, NULL if there is no data available + */ + inline const Obj* data(unsigned int offs = 0) const + { return data(offs,length()); } + + /** + * Get a pointer to data from offset to vector end + * @param offs The offset + * @param len The number of elements to retrieve (must not be 0) + * @param eod Pointer to be filled with end of data element + * (pointer to first element after requested number of elements) + * @return A pointer to data data from requested offset, + * NULL if there is not enough data available + */ + inline Obj* data(unsigned int offs, unsigned int len, Obj*& eod) { + Obj* d = data(offs,len); + eod = end(d,len); + return d; + } + + /** + * Get a pointer to data from offset to vector end + * @param offs The offset + * @param len The number of elements to retrieve (must not be 0) + * @param eod Pointer to be filled with end of data element + * (pointer to first element after requested number of elements) + * @return A pointer to data data from requested offset, + * NULL if there is not enough data available + */ + inline const Obj* data(unsigned int offs, unsigned int len, const Obj*& eod) const { + const Obj* d = data(offs,len); + eod = end(d,len); + return d; + } + + /** + * Get the length of the vector + * @return The length of the vector + */ + inline unsigned int length() const + { return m_length; } + + /** + * Get the maximum length of the vector + * @return The maximum length of the vector + * (0 if the vector don't have a storage buffer) + */ + inline unsigned int maxLen() const + { return m_maxLen; } + + /** + * Get the vector size in bytes + * @return Vector size in bytes + */ + inline unsigned int size() const + { return size(length()); } + + /** + * Retrieve the available number of elements from given offset + * (not more than required number) + * @param offs The offset + * @param len Required number of elements (-1: all available from offset) + * @return The available number of elements from given offset + * (may be less than required) + */ + inline unsigned int available(unsigned int offs, int len = -1) const { + if (len && offs < length()) { + unsigned int rest = length() - offs; + return (len < 0 || rest <= (unsigned int)len) ? rest : (unsigned int)len; + } + return 0; + } + + /** + * Retrieve the available number of elements from given offset. + * Clamp the available number of elements to requested value + * @param clamp Maximum number of elements to check + * @param offs The offset + * @param len Required number of elements (-1: all available from offset) + * @return The available number of elements from given offset + */ + inline unsigned int availableClamp(unsigned int clamp, unsigned int offs = 0, + int len = -1) const { + offs = available(offs,len); + return clamp <= offs ? clamp : offs; + } + + /** + * Retrieve vector size in bytes + * @return Vector size in bytes + */ + virtual unsigned int vectorSize() const + { return size(); } + + /** + * Change the vector length without changing the contents. + * If the vector length is increased the new elements' value are not reset + * @param len New vector length + * @return True on success, false if requested length is greater than max length + */ + inline bool resize(unsigned int len) { + if (len <= maxLen()) { + m_length = len; + return true; + } + return false; + } + + /** + * Change the vector length to maximum allowed without changing the contents + */ + inline void resizeMax() + { resize(maxLen()); } + + /** + * Steal other vector's data + * @param other Original vector + */ + inline void steal(SliceVector& other) { + m_storage = other.m_storage; + m_data = other.m_data; + m_length = other.m_length; + m_maxLen = other.m_maxLen; + other.m_storage = 0; + other.m_data = 0; + other.m_length = other.m_maxLen = 0; + } + + /** + * Change the vector storage (re-allocate) + * @param len New vector length (0 to clear vector data) + * @param maxLen Optional vector maximum length + * (it will be adjusted to be at least len) + */ + inline void resetStorage(unsigned int len, unsigned int maxLen = 0) { + setData(); + initStorage(len,0,maxLen); + } + + /** + * Set a slice containing another vector + * @param other Original vector + * @param offs Offset in the original vector + * @param len The number of elements (0 to use all available from offset) + * @return True on success, false on failure + */ + inline bool setSlice(const SliceVector& other, unsigned int offs = 0, + unsigned int len = 0) + { return initSlice(true,other,offs,len); } + + /** + * Retrieve vector head + * @param len The number of elements to retrieve + * @return A vector containing the first elements of this vector + */ + inline SliceVector head(unsigned int len) const + { return slice(0,len); } + + /** + * Retrieve vector head + * @param dest Destination vector + * @param len The number of elements to retrieve + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool head(SliceVector& dest, unsigned int len) const + { return slice(dest,0,len); } + + /** + * Retrieve vector tail (last elements) + * @param len The number of elements to retrieve + * @return A vector containing the last elements of this vector + */ + inline SliceVector tail(unsigned int len) const { + if (len < length()) + return SliceVector(*this,length() - len,len); + return SliceVector(); + } + + /** + * Retrieve vector tail (last elements) + * @param len The number of elements to retrieve + * @param dest Destination vector + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool tail(SliceVector& dest, unsigned int len) const { + if (len <= length()) + return dest.initSlice(true,*this,length() - len,len); + dest.setData(); + return false; + } + + /** + * Retrieve a vector slice + * @param offs Offset in our vector + * @param len The number of elements to retrieve + * @return A vector containing the requested slice + * (empty if offset/length are invalid) + */ + inline SliceVector slice(unsigned int offs, unsigned int len) const + { return SliceVector(*this,offs,len); } + + /** + * Set a slice of this vector to another one. + * The destination vector will be changed + * @param dest Destination vector + * @param offs Offset in our vector + * @param len The number of elements (0 to use all available from offset) + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool slice(SliceVector& dest, unsigned int offs, + unsigned int len = 0) const + { return dest.initSlice(true,*this,offs,len); } + + /** + * Copies elements from another vector to this one. + * NOTE: This method don't check for overlapping data + * @param src The source vector + * @param len The number of elements to copy + * @param offs The start index in our vector + * @param srcOffs The start index in the source vector + * @return True on success, false on failure (not enough data in source vector or + * not enough space in this vector) + */ + inline bool copy(const SliceVector& src, unsigned int len, + unsigned int offs = 0, unsigned int srcOffs = 0) + { return RefStorage::copy(data(offs,len),src.data(srcOffs,len),size(len)); } + + /** + * Fill the buffer with 0 + * @param offs The offset + * @param len The number of elements to retrieve (must not be 0) + */ + inline void bzero(unsigned int offs, unsigned int len) + { RefStorage::fill(data(offs,len),size(len)); } + + /** + * Fill the buffer with 0 + */ + inline void bzero() + { RefStorage::fill(data(),size()); } + + /** + * Fill the vector with a given value + * @param value The value to be set in this vector + */ + inline void fill(const Obj& value) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + *d = value; + } + + /** + * Apply an unary function to all elements in this vector + * @param func Function to apply + */ + inline void apply(void (*func)(Obj&)) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + (*func)(*d); + } + + /** + * Sum vector values + * @return The sum of the vector elements + */ + inline Obj sum() const { + Obj result(0); + const Obj* d = data(); + for (const Obj* last = end(d,length()); d != last; ++d) + result += *d; + return result; + } + + /** + * Apply a function to all vector elements and take the sum of the results + * @param func Function to apply + * @return The result + */ + inline Obj sumApply(Obj (*func)(const Obj&)) const { + Obj result(0); + const Obj* d = data(); + for (const Obj* last = end(d,length()); d != last; ++d) + result += (*func)(*d); + return result; + } + + /** + * Apply a function to all vector elements and take the sum of the results + * @param func Function to apply + * @return The result + */ + inline float sumApplyF(float (*func)(const Obj&)) const { + float result = 0; + const Obj* d = data(); + for (const Obj* last = end(d,length()); d != last; ++d) + result += (*func)(*d); + return result; + } + + /** + * Sum this vector with another one + * @param other Vector to sum with this one + * @return True on sucess, false on failure (vectors don't have the same length) + */ + inline bool sum(const SliceVector& other) { + if (length() != other.length()) + return false; + const Obj* od = other.m_data; + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d, ++od) + *d += *od; + return true; + } + + /** + * Add a value to each element of the vector + * @param value Value to add + */ + inline void sum(const Obj& value) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + *d += value; + } + + /** + * Substract another vector from this one + * @param other Vector to substract + * @return True on sucess, false on failure (vectors don't have the same length) + */ + inline bool sub(const SliceVector& other) { + if (length() != other.length()) + return false; + const Obj* od = other.m_data; + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d, ++od) + *d -= *od; + return true; + } + + /** + * Substract a value from each element of the vector + * @param value Value to substract + */ + inline void sub(const Obj& value) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + *d -= value; + } + + /** + * Multiply this vector with another one + * @param other Vector to multiply with + * @return True on sucess, false on failure (vectors don't have the same length) + */ + inline bool mul(const SliceVector& other) { + if (length() != other.length()) + return false; + const Obj* od = other.m_data; + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d, ++od) + *d *= *od; + return true; + } + + /** + * Multiply this vector with a value + * @param value Value to multiply with + */ + inline void mul(const Obj& value) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + *d *= value; + } + + /** + * Multiply this vector with a value + * @param value Value to multiply with + */ + inline void mul(float value) { + Obj* d = data(); + for (Obj* last = end(d,length()); d != last; ++d) + *d *= value; + } + + /** + * Indexing operator with unsigned int + * @param index Index of element to retrieve + * @return The element at requested index + */ + inline Obj& operator[](unsigned int index) { + YMATH_FAIL(index < m_length, + "SliceVector::operator[] index out of bounds [%p]",this); + return m_data[index]; + } + + /** + * Indexing operator with unsigned int + * @param index Index of element to retrieve + * @return The element at requested index + */ + inline const Obj& operator[](unsigned int index) const { + YMATH_FAIL(index < m_length, + "SliceVector::operator[] index out of bounds [%p]",this); + return m_data[index]; + } + + /** + * Indexing operator with signed int + * @param index Index of element to retrieve + * @return The element at requested index + */ + inline Obj& operator[](signed int index) { + YMATH_FAIL((unsigned int)index < m_length, + "SliceVector::operator[] index out of bounds [%p]",this); + return m_data[index]; + } + + /** + * Indexing operator with signed int + * @param index Index of element to retrieve + * @return The element at requested index + */ + inline const Obj& operator[](signed int index) const { + YMATH_FAIL((unsigned int)index < m_length, + "SliceVector::operator[] index out of bounds [%p]",this); + return m_data[index]; + } + + /** + * Equality operator + * @param other Original vector + * @return True if the vectors are equal, false otherwise + */ + inline bool operator==(const SliceVector& other) const + { return equals(other); } + + /** + * Inequality operator + * @param other Original vector + * @return True if the vectors are not equal, false otherwise + */ + inline bool operator!=(const SliceVector& other) const + { return !equals(other); } + + /** + * Asignment operator. Builds a slice of another vector + * @param other Original vector + * @return A reference to this vector + */ + inline SliceVector& operator=(const SliceVector& other) { + setSlice(other); + return *this; + } + + /** + * Sum this vector with another one + * @param other Vector to sum with this one + * @return A reference to this vector + */ + inline SliceVector& operator+=(const SliceVector& other) { + YMATH_FAIL(length() == other.length(), + "SliceVector(+=): invalid lengths [%p]",this); + sum(other); + return *this; + } + + /** + * Add a value to each element of the vector + * @param value Value to add + * @return A reference to this vector + */ + inline SliceVector& operator+=(const Obj& value) { + sum(value); + return *this; + } + + /** + * Substract another vector from this one + * @param other Vector to substract + * @return A reference to this vector + */ + inline SliceVector& operator-=(const SliceVector& other) { + YMATH_FAIL(length() == other.length(), + "SliceVector(-=): invalid lengths [%p]",this); + sub(other); + return *this; + } + + /** + * Substract a value from each element of the vector + * @param value Value to substract + * @return A reference to this vector + */ + inline SliceVector& operator-=(const Obj& value) { + sub(value); + return *this; + } + + /** + * Multiply this vector with another one + * @param other Vector to multiply with + * @return A reference to this vector + */ + inline SliceVector& operator*=(const SliceVector& other) { + YMATH_FAIL(length() == other.length(), + "SliceVector(*=): invalid lengths [%p]",this); + mul(other); + return *this; + } + + /** + * Multiply this vector with a value + * @param value Value to multiply with + * @return A reference to this vector + */ + inline SliceVector& operator*=(const Obj& value) { + mul(value); + return *this; + } + + /** + * Multiply this vector with a value + * @param value Value to multiply with + * @return A reference to this vector + */ + inline SliceVector& operator*=(float value) { + mul(value); + return *this; + } + + /** + * Compare this vector to another one (compare storage) + * @param other Vector to compare with + * @return True if they are equal + */ + inline bool equals(const SliceVector& other) const { + return length() == other.length() && + RefStorage::equals(data(),other.data(),size()); + } + + /** + * Dump data to a string (append) + * @param buf Destination string + * @param func Pointer to function who appends the object to a String + * (0 to dump all available from offset) + * @param sep Vector elements separator + * @return Destination string address + */ + String& dump(String& buf, String& (*func)(String& s, const Obj& o, const char* sep), + const char* sep = ",") const { + const Obj* d = data(); + if (!(d && func)) + return buf; + String localBuf; + for (const Obj* last = end(d,length()); d != last; ++d) + (*func)(localBuf,*d,sep); + return buf.append(localBuf); + } + + /** + * Dump this vector to string, split it and append lines to a buffer. + * Line prefix length is not included when line length is calculated. + * Separator length is included in line length + * @param buf Destination string + * @param lineLen Line length in bytes + * @param func Pointer to function who append the object to a String + * @param offset Offset in first line (if incomplete). No data will be + * added on first line if offset is greater then line length + * @param linePrefix Prefix for new lines. Empty string to use the suffix + * @param suffix String to always add to final result (even if no data dumped) + * @param sep Vector elements separator + * @return Destination string address + */ + String& dump(String& buf, unsigned int lineLen, + String& (*func)(String& s, const Obj& o, const char* sep), + unsigned int offset = 0, const char* linePrefix = 0, + const char* suffix = "\r\n", const char* sep = ",") const { + const Obj* d = data(); + if (!(d && func)) + return buf.append(suffix); + if (TelEngine::null(linePrefix)) + linePrefix = suffix; + if (!lineLen || TelEngine::null(linePrefix)) + return dump(buf,func,sep) << suffix; + String localBuf; + for (const Obj* last = end(d,length()); d != last;) { + String tmp; + (*func)(tmp,*d,0); + if (++d != last) + tmp << sep; + offset += tmp.length(); + if (offset > lineLen) { + localBuf << linePrefix; + offset = tmp.length(); + } + localBuf << tmp; + } + return buf << localBuf << suffix; + } + + /** + * Hexify data + * @param buf Destination string + * @param sep Optional separator + * @return Destination string address + */ + inline String& hexify(String& buf, char sep = 0) const + { return buf.hexify((void*)data(),size(),sep); } + + /** + * Hexify data, split it and append lines to a string + * @param buf Destination string + * @param lineLen Line length, characters to copy + * @param offset Offset in first line (if incomplete). No data will be + * added on first line if offset is greater then line length + * @param linePrefix Prefix for new lines. + * Set it to empty string or 0 to use the suffix + * @param suffix End of line for the last line + * @return Destination string address + */ + inline String& dumpHex(String& buf, unsigned int lineLen, + unsigned int offset = 0, const char* linePrefix = 0, + const char* suffix = "\r\n") const { + String h; + return RefStorage::dumpSplit(buf,hexify(h),lineLen,offset,linePrefix,suffix); + } + + /** + * Reset storage from a hexadecimal string representation. + * Clears the vector at start, i.e. the vector will be empty on failure. + * The vector may be empty on success also. + * Each octet must be represented in the input string with 2 hexadecimal characters. + * If a separator is specified, the octets in input string must be separated using + * exactly 1 separator. Only 1 leading or 1 trailing separators are allowed. + * @param str Input character string + * @param len Length of input string + * @param sep Separator character used between octets. + * [-128..127]: expected separator (0: no separator is expected). + * Detect the separator if other value is given + * @return 0 on success, negative if unhexify fails, + * positive if the result is not a multiple of Obj size + */ + int unHexify(const char* str, unsigned int len, int sep = 255) { + setData(); + DataBlock db; + bool ok = (sep < -128 || sep > 127) ? db.unHexify(str,len) : + db.unHexify(str,len,(char)sep); + if (ok && (db.length() % objSize() == 0)) { + initStorage(db.length() / objSize(),(const Obj*)db.data(0,db.length())); + return 0; + } + return ok ? 1 : -1; + } + + /** + * Unhexify data + * @param str Input string + * @param sep Separator character used between octets + * @return See unHexify(const char*,unsigned int,char) + */ + inline int unHexify(const String& str, int sep = 255) + { return unHexify(str.c_str(),str.length(),sep); } + + /** + * Retrieve the object size + * @return Obj size in bytes + */ + static inline unsigned int objSize() + { return sizeof(Obj); } + + /** + * Retrieve the length in bytes of a buffer containing 'count' objects + * @param len Buffer length + * @return Buffer length in bytes + */ + static inline unsigned int size(unsigned int len) + { return len * objSize(); } + +protected: + // Return end-of-data pointer from start and given length + inline Obj* end(Obj* start, unsigned int len) + { return start ? (start + len) : 0; } + inline const Obj* end(const Obj* start, unsigned int len) const + { return start ? (start + len) : 0; } + // Set data. Reset storage if we don't have a valid data pointer + // Return true if we have valid data + inline bool setData(Obj* data = 0, unsigned int len = 0, unsigned int maxLen = 0) { + m_data = data; + if (m_data) { + m_length = len; + m_maxLen = maxLen; + } + else { + m_length = m_maxLen = 0; + TelEngine::destruct(m_storage); + } + return m_data != 0; + } + // Build storage, update data. This method assumes our data is cleared + // If data is given 'len' elements will be copied from it to storage + inline bool initStorage(unsigned int len, const Obj* data = 0, + unsigned int maxLen = 0) { + if (maxLen < len) + maxLen = len; + if (!maxLen) + return false; + if (!data || maxLen == len) + m_storage = new RefStorage(data,size(maxLen)); + else { + m_storage = new RefStorage(0,size(maxLen)); + m_storage->set(data,size(len)); + } + return setData((Obj*)m_storage->data(0,1),len,maxLen); + } + // Build storage from slice and update data. + // Clear data if requested + inline bool initSlice(bool del, const SliceVector& other, unsigned int offs = 0, + unsigned int len = 0) { + if (!len) + len = other.length(); + Obj* d = (Obj*)other.data(offs,len); + if (!d) { + if (del) + setData(); + return len == 0; + } + if (m_storage == other.m_storage) + return setData(d,len,len); + RefStorage* tmp = other.m_storage; + if (tmp->ref()) { + TelEngine::destruct(m_storage); + m_storage = tmp; + return setData(d,len,len); + } + Debug(DebugFail,"SliceVector storage ref() failed"); + return del ? setData() : false; + } + + RefStorage* m_storage; // Vector storage + Obj* m_data; // Pointer to data + unsigned int m_length; // Data length + unsigned int m_maxLen; // Max storage +}; + +typedef SliceVector ComplexVector; +typedef SliceVector FloatVector; +typedef SliceVector ByteVector; + +/** + * This vector holds bit values using 1 byte. It implements methods operating on bits. + * NOTE: The array indexing operator allows setting invalid values (not 1 or 0). + * The pack/unpack methods are safe (they will handle non 0 values as bit 1). + * The comparison operators may fail for vectors containing values other than 0 or 1. + * @short A slice vector holding bits + */ +class YATE_API BitVector : public ByteVector +{ +public: + /** + * Constructor + */ + inline BitVector() + {} + + /** + * Copy constructor. + * Builds a slice of another vector + * @param other Original vector + */ + inline BitVector(const BitVector& other) + : ByteVector(other) + {} + + /** + * Constructor. + * Build the vector storage + * @param len Length of data + * @param maxLen Optional vector maximum length + * (it will be adjusted to be at least len) + */ + explicit inline BitVector(unsigned int len, unsigned int maxLen = 0) + : ByteVector(len,0,maxLen) + {} + + /** + * Constructor. + * Builds a slice of another vector + * @param other Original vector + * @param offs Offset in the original vector + * @param len The number of elements (0 to use all available from offset) + */ + explicit inline BitVector(const BitVector& other, unsigned int offs, + unsigned int len = 0) + : ByteVector(other,offs,len) + {} + + /** + * Constructor. Build from string bits + * @param str String bits ('1' -> 1, else -> 0) + * @param maxLen Optional vector maximum length + */ + explicit BitVector(const char* str, unsigned int maxLen = 0); + + /** + * Check if this vector contains valid values (0 or 1) + * @return True on success, false if the vector contains values other than 0 or 1 + */ + bool valid() const; + + /** + * Set float bit values from this vector (0 -> 0.0F, non 0 -> 1.0F). + * The destination vector will be resized to this vector's length + * @param dest The destination vector + * @return True on success, false if destination resize failed + */ + bool get(FloatVector& dest) const; + + /** + * Initializes this vector from float values (0.0F -> 0, non 0 -> 1). + * The vector will be resized to input length + * @param input The input vector + * @return True on success, false if resize failed + */ + bool set(const FloatVector& input); + + /** + * Apply XOR on vector elements using a given value's bits, MSB first. + * Given v31,v30,...,v0 the value's bits in MSB order the result will be + * data()[offs] ^= v31, data()[offs+1] ^= v30 ... + * @param value Value to use + * @param offs Start position in this BitVector + * @param len The number of bits to use + */ + void xorMsb(uint32_t value, unsigned int offs = 0, uint8_t len = 32); + + /** + * Apply XOR on vector elements using a given value's bits, MSB first. + * Given v15,v14,...,v0 the value's bits in MSB order the result will be + * data()[offs] ^= v15, data()[offs+1] ^= v14 ... + * @param value Value to use + * @param offs Start position in this BitVector + * @param len The number of bits to use + */ + inline void xorMsb16(uint16_t value, unsigned int offs = 0, uint8_t len = 16) + { return xorMsb((uint32_t)value << 16,offs,len <= 16 ? len : 16); } + + /** + * Pack up to 64 bits, LSB-first (i.e. first bit goes to LSB in destination) + * @param offs The start offset + * @param len The number of elements to be packed (-1 to pack all available). + * No more than 64 bits will be packed + * @return The packed 64-bit value + */ + uint64_t pack(unsigned int offs = 0, int len = -1) const; + + /** + * Unpack up to 64 bits into this vector, LSB first + * @param value Value to unpack + * @param offs Optional start offset + * @param len The number of bits to unpack + */ + void unpack(uint64_t value, unsigned int offs = 0, uint8_t len = 64); + + /** + * Unpack up to 32 bits into this vector (MSB to LSB). + * MSB from value is the first unpacked bit + * @param value The value to be unpacked + * @param offs Optional start offset + * @param len The number of bits to unpack + */ + void unpackMsb(uint32_t value, unsigned int offs = 0, uint8_t len = 32); + + /** + * Unpack up to 16 bits into this vector (MSB to LSB). + * MSB from value is the first unpacked bit + * @param value The value to be unpacked + * @param offs Optional start offset + * @param len The number of bits to unpack + */ + inline void unpackMsb16(uint16_t value, unsigned int offs = 0, uint8_t len = 16) + { unpackMsb((uint32_t)value << 16,offs,len <= 16 ? len : 16); } + + /** + * Pack bits into a ByteVector (LSB source to MSB in destination). + * MSB of first byte in destination will have the same value of the + * first bit in this vector. + * Remaining elements in destination are left untouched + * @param dest Destination vector + * @return True on success, false on failure (not enough space in destination vector) + */ + bool pack(ByteVector& dest) const; + + /** + * Unpack a ByteVector into this BitVector. + * MSB of the first element in source goes to first bit in this vector. + * Remaining bits are left untouched + * @param src Source byte vector + * @return True on success, false if there is not enough space to unpack + */ + bool unpack(const ByteVector& src); + + /** + * Append bits to string + * @param buf Destination string + * @param offs Optional starting index + * @param len The number of elements to be added (negative to add all) + * @return Destination string address + */ + String& appendTo(String& buf, unsigned int offs = 0, int len = -1) const; + + /** + * Build a String from vector bits and return it + * @param offs Optional starting index + * @param len The number of elements to be added (negative to add all) + * @return A newly created String containing vector bits + */ + inline String toString(unsigned int offs, int len = -1) const { + String tmp; + return appendTo(tmp,offs,len); + } + + /** + * Set a slice containing another vector + * @param other Original vector + * @param offs Offset in the original vector + * @param len The number of elements (0 to use all available from offset) + * @return True on success, false on failure + */ + inline bool setSlice(const BitVector& other, unsigned int offs = 0, + unsigned int len = 0) + { return initSlice(true,other,offs,len); } + + /** + * Retrieve vector head + * @param len The number of elements to retrieve + * @return A vector containing the first elements of this vector + */ + inline BitVector head(unsigned int len) const + { return slice(0,len); } + + /** + * Retrieve vector head + * @param dest Destination vector + * @param len The number of elements to retrieve + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool head(BitVector& dest, unsigned int len) const + { return slice(dest,0,len); } + + /** + * Retrieve vector tail (last elements) + * @param len The number of elements to retrieve + * @return A vector containing the last elements of this vector + */ + inline BitVector tail(unsigned int len) const { + if (len < length()) + return BitVector(*this,length() - len,len); + return BitVector(); + } + + /** + * Retrieve vector tail (last elements) + * @param len The number of elements to retrieve + * @param dest Destination vector + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool tail(BitVector& dest, unsigned int len) const { + if (len <= length()) + return dest.initSlice(true,*this,length() - len,len); + dest.setData(); + return false; + } + + /** + * Retrieve a vector slice + * @param offs Offset in our vector + * @param len The number of elements to retrieve + * @return A vector containing the requested slice + * (empty if offset/length are invalid) + */ + inline BitVector slice(unsigned int offs, unsigned int len) const + { return BitVector(*this,offs,len); } + + /** + * Set a slice of this vector to another one. + * The destination vector will be changed + * @param dest Destination vector + * @param offs Offset in our vector + * @param len The number of elements (0 to use all available from offset) + * @return True on success, false on failure (not enough data in our vector) + */ + inline bool slice(BitVector& dest, unsigned int offs, unsigned int len = 0) const + { return dest.initSlice(true,*this,offs,len); } +}; + + +/** + * This class global Math utility methods + * @short Math utilities + */ +class YATE_API Math +{ +public: + /** + * Dump a Complex number to a String + * @param buf Destination string + * @param val Value to dump + * @param sep Optional separator + * @return Destination string address + */ + static String& dumpComplex(String& buf, const Complex& val, const char* sep = 0); + + /** + * Dump a float number to a String + * @param buf Destination string + * @param val Value to dump + * @param sep Optional separator + * @return Destination string address + */ + static String& dumpFloat(String& buf, const float& val, const char* sep = 0); +}; + + +/** + * Addition operator + * @param c1 First number + * @param c2 Second number + * @return The result + */ +inline Complex operator+(const Complex& c1, const Complex& c2) +{ + Complex tmp(c1); + return (tmp += c2); +} + +/** + * Addition operator + * @param c A Complex number + * @param f A float value + * @return The result + */ +inline Complex operator+(const Complex& c, float f) +{ + Complex tmp(c); + return (tmp += f); +} + +/** + * Addition operator + * @param f The float value + * @param c The Complex number + * @return The result + */ +inline Complex operator+(float f, const Complex& c) +{ + return operator+(c,f); +} + +/** + * Substraction operator + * @param c1 First number + * @param c2 Second number + * @return The result + */ +inline Complex operator-(const Complex& c1, const Complex& c2) +{ + Complex tmp(c1); + return (tmp -= c2); +} + +/** + * Substraction operator + * @param c A Complex number + * @param f A float value + * @return The result + */ +inline Complex operator-(const Complex& c, float f) +{ + Complex tmp(c); + return (tmp -= f); +} + +/** + * Multiplication operator + * @param c1 First number + * @param c2 Second number + * @return The result + */ +inline Complex operator*(const Complex& c1, const Complex& c2) +{ + Complex tmp(c1); + return (tmp *= c2); +} + +/** + * Multiplication operator + * @param c A Complex number + * @param f A float value + * @return The result + */ +inline Complex operator*(const Complex& c, float f) +{ + Complex tmp(c); + return (tmp *= f); +} + +/** + * Multiplication operator + * @param f A float value + * @param c A Complex number + * @return The result + */ +inline Complex operator*(float f, const Complex& c) +{ + return operator*(c,f); +} + +/** + * Division operator + * @param c1 First number + * @param c2 Second number + * @return The result + */ +inline Complex operator/(const Complex& c1, const Complex& c2) +{ + Complex tmp(c1); + return (tmp /= c2); +} + +/** + * Division operator + * @param c A Complex number + * @param f A float value + * @return The result + */ +inline Complex operator/(const Complex& c, float f) +{ + Complex tmp(c); + return (tmp /= f); +} + +/** + * Append operator: append a Complex number to a String + * @param str Destination string + * @param c Complex number to append + * @return Destination string reference + */ +inline String& operator<<(String& str, const Complex& c) +{ + return Math::dumpComplex(str,c); +} + +/** + * Append operator: append a BitVector to a String + * @param str Destination string + * @param b Vector to append + * @return Destination string reference + */ +inline String& operator<<(String& str, const BitVector& b) +{ + return b.appendTo(str); +} + +}; // namespace TelEngine + +#endif /* __YATEMATH_H */ + +/* vi: set ts=8 sw=4 sts=4 noet: */