#ifndef SHARELIB_H
#define SHARELIB_H
/**
* @file sharelib.h
* @brief Share library interface
* @author Kamil Dudka, xdudka00@gmail.com
* @date 2007-05-15
* @ingroup core
* @ingroup stl
*/
#ifdef _WIN32
// Export symbols to .dll while using MS C++ compiler
# define SHARE_EXPORT __declspec(dllexport)
#else
// There is no need to declare export on Linux
# define SHARE_EXPORT
#endif
#include <new> // Import std::bad_alloc exception
#include <memory> // Import std::allocator
#include <iterator> // Import std::random_access_iterator_tag
#include <functional>
#include <stddef.h> // Import base set of system types (like size_t, ptrdiff_t, ...)
/**
* @namespace Share
* @brief Library namespace
*/
namespace Share {
/**
* @brief Compile-time assertion.
*/
template <bool> struct ERROR_CTAssert_failed__Unexpected_sizeof_char;
/**
* @brief template specialization.
*/
template <> struct ERROR_CTAssert_failed__Unexpected_sizeof_char<true> { };
/**
* @brief General exception carrying text message inside
* @ingroup core
*/
class ShareException: public std::bad_alloc {
public:
/**
* Create exception object
* @param message Text message describing exception
*/
SHARE_EXPORT ShareException (const char *message);
/**
* Overloaded destructor from std::bad_alloc
*/
SHARE_EXPORT ~ShareException () throw ();
/**
* Copy constructor needed to pass exception by value
*/
SHARE_EXPORT ShareException (const ShareException &);
/**
* @return Return text message describing exception
*/
SHARE_EXPORT const char* message() const;
private:
void operator= (const ShareException &);
char *message_;
};
/**
* Non-instantiable class.
* @brief Class handling low-level pointer relocation
* @attention Implementation expects @b sizeof(char) @b == @b 1 !
* @ingroup core
*/
class Relocator {
public:
typedef void* absolute_pointer; ///< @brief Absolute pointer type
typedef const void* absolute_const_pointer; ///< @brief Absolute const pointer type
typedef size_t relative_pointer; ///< @brief Relative pointer type
typedef const size_t relative_const_pointer; ///< @brief Relative const pointer type
/**
* Convert absolute address to relative.
* @param abs Absolute address to convert.
* @param base Base address for relocation.
* @return Return relative address.
*/
static relative_pointer absToRel (absolute_pointer abs, absolute_pointer base) {
ERROR_CTAssert_failed__Unexpected_sizeof_char<sizeof(char)==1>();
return
(abs) ?
static_cast<char *> (abs) - static_cast<char *> (base) :
0;
}
/**
* Overloaded method for const pointers.
* @copydoc Relocator::absToRel(absolute_pointer,absolute_pointer)
*/
static relative_const_pointer absToRel (absolute_const_pointer abs, absolute_pointer base) {
return absToRel (const_cast<absolute_pointer>(abs), base);
}
/**
* Convert relative address to absolute.
* @param rel Relative address to convert.
* @param base Base address for relocation.
* @return Return absolute address.
*/
static absolute_pointer relToAbs (relative_pointer rel, absolute_pointer base) {
ERROR_CTAssert_failed__Unexpected_sizeof_char<sizeof(char)==1>();
return
(rel) ?
static_cast<char *> (base) + rel :
0;
}
private:
/**
* Private constructor to avoid class instantiation.
*/
Relocator ();
};
/**
* Struct defines type for reference and const reference.
* This helps to avoid referencing void type in templates.
* @brief Reference generic template
* @ingroup core
*/
template <class T> struct TReference {
typedef T& reference; ///< @brief Reference type derived from template parameter
typedef const T& const_reference; ///< @brief Const reference type derived from template parameter
};
/**
* @brief template specialization.
*/
template <> struct TReference<void> {
typedef void reference; ///< @brief Avoid referencing @c void
typedef void const_reference; ///< @brief Avoid referencing @c void
};
/**
* @brief template specialization.
*/
template <> struct TReference<const void> {
typedef void reference; ///< @brief Avoid referencing @c void
typedef void const_reference; ///< @brief Avoid referencing @c void
};
/**
* Struct defines type for @c void and @c const @c void.
* This helps to carry constness of pointer trough generic template.
* @brief Void pointer generic template
* @ingroup core
*/
template <class T> struct TVoidPointer {
typedef void* void_pointer; ///< @brief @c void pointer type derived from template parameter
typedef const void* const_void_pointer; ///< @brief @c const @c void pointer type derived from template parameter
};
/**
* @brief template specialization
*/
template <class T> struct TVoidPointer<const T> {
typedef const void* void_pointer; ///< @copydoc TVoidPointer::void_pointer
typedef const void* const_void_pointer; ///< @copydoc TVoidPointer::const_void_pointer
};
class SharedSegment; // Platform-independent shared segment representation
class SegmentHeader; // Object placed at begin of each shared segment
/**
* High-level interface to shared segment manipulation.
* Design pattern @b signleton
* @brief @b Gateway to shared segment
* @ingroup core
*/
class ShareManager {
public:
typedef Relocator::relative_pointer relative_pointer; ///< @copydoc Relocator::relative_pointer
typedef Relocator::relative_const_pointer relative_const_pointer; ///< @copydoc Relocator::relative_const_pointer
/**
* Method to access to singleton object.
* @return Return pointer to singleton object.
* @callergraph
*/
SHARE_EXPORT static ShareManager* instance();
/**
* Destroy singleton object.
* This method should be called automatically on application exit using std::atexit() function.
*/
SHARE_EXPORT static void destroySelf();
/**
* Create and attach new segment.
* @param name Name of new segment. Method throws ShareException if name is already used.
* @param size How much memory will be allocated for data. Note that real size can be larger.
* @brief @b Create @b and @b attach segment
* @throw ShareException Generic exception thrown if creation process fails.
*/
SHARE_EXPORT void createSegment (const char *name, size_t size) throw (ShareException);
/**
* Method throws ShareException if segment does not exist.
* @param name Name of shared segment to attach to.
* @brief Attach an already existing shared segment.
* @throw ShareException Generic exception thrown if attaching fails.
* @note Do not call this method after createSegment method call.
*/
SHARE_EXPORT void attachSegment (const char *name) throw (ShareException);
/**
* All relative and absolute pointers to segment will be invalid after detach.
* @brief Detach from shared segment.
*/
SHARE_EXPORT void detachSegment () throw ();
/**
* Segment will be realy destroyed after references count fades to zero.
* This means that calling prcess has to detach shared segment after this call to destroy it.
* @brief Mark shared segment to be destroyed
* @attention On Win32 platform is segment destoroyed automatically by OS, when there are no more references to segment.
*/
SHARE_EXPORT void unlinkSegment () throw ();
/**
* @brief Name of attached shared segment
* @return Return name of shared segment.
*/
SHARE_EXPORT const char* name ();
/**
* Convert absolute address to relative.
* @param abs Absolute address to convert.
* @return Return relative address.
*/
relative_pointer absToRel (void *abs) {
return Relocator::absToRel (abs, atAddr_);
}
/**
* @copydoc ShareManager::absToRel(void*)
*/
relative_const_pointer absToRel (const void *abs) {
return Relocator::absToRel (abs, atAddr_);
}
/**
* @copydoc ShareManager::absToRel(void*)
*/
template <class T> relative_pointer absToRel (T *abs) {
typedef typename TVoidPointer<T>::void_pointer void_pointer;
return absToRel(static_cast<void_pointer> (abs));
}
/**
* Convert relative address to absolute.
* @param rel Relative address to convert.
* @return Return absolute address.
*/
void* relToAbs (relative_pointer rel) {
return Relocator::relToAbs (rel, atAddr_);
}
/**
* Allocate piece of memory from shared segment or local heap.
* @param size Requested size to allocate.
* @return Return local pointer to allocated memory.
* @throw ShareException Library-specific exception derived from std::bad_alloc
*/
SHARE_EXPORT void* alloc (size_t size) throw (ShareException);
/**
* @copydoc alloc(size_t)
* @param count Objects count to allocate.
* @note Used for STL allocator.
*/
void* alloc (size_t size, size_t count) throw (ShareException) {
return this-> alloc (size * count);
}
/**
* Free memory allocated by method alloc().
* @param addr Address returned by alloc(). If this is different addres,
* all attached application will crash terribly.
*/
SHARE_EXPORT void free (void *addr) throw ();
/**
* @copydoc free(void*)
* @note Used for STL allocator.
*/
void free (void *addr, size_t) throw () {
this-> free (addr);
}
/**
* @return Return size of avalilable memory in shared segment
*/
SHARE_EXPORT size_t available ();
protected:
/**
* @ingroup sharectl
* @brief Initialize ShareManager for debuging
* @param segment Pointer to initialized segment object
*/
SHARE_EXPORT void initDebugMode (SharedSegment *segment);
/**
* @ingroup sharectl
* @brief Destroy current shared segment immediately
*/
SHARE_EXPORT void destroySegment ();
/**
* @brief Bridge from sharectl to sharelib
*/
friend class SharedSegmentWrapper;
private:
static ShareManager *instance_; ///< Pointer to singleton object
SharedSegment *segment_; ///< Platform independent segment representation
SegmentHeader *atAddr_; ///< attached addres of shared memory segment
private:
ShareManager ();
~ShareManager ();
ShareManager (const ShareManager&); ///< avoid object copying
ShareManager& operator= (const ShareManager&); ///< avoid object copying
};
/**
* It overload operators @b new and @b delete for derived class.
* @brief Shareable object @b base @b class
* @ingroup core
*/
class SharedObject {
public:
/**
* Overloaded operator new
* @throw ShareException Library-specific exception derived from std::bad_alloc
*/
static void* operator new (size_t size) throw (ShareException)
{
return alloc(size);
}
/**
* Overloaded operator new[]
* @throw ShareException Library-specific exception derived from std::bad_alloc
*/
static void* operator new[] (size_t size) throw (ShareException)
{
return alloc(size);
}
/**
* Overloaded opeartor delete
*/
static void operator delete (void *addr, size_t) throw ()
{
free (addr);
}
/**
* Overloaded operator delete[]
*/
static void operator delete[] (void *addr, size_t) throw()
{
free (addr);
}
/**
* Allocate block of memory inside shared segment.
* @param size Desired size of block to allocate.
* @return Return local address of allocated block on success.
* @throw ShareException Library-specific exception derived from std::bad_alloc
*/
static void* alloc (size_t size) throw (ShareException)
{
return ShareManager::instance()-> alloc (size);
}
/**
* @copydoc alloc(size_t)
* @param count Objects count to allocate.
* @note Used for STL allocator.
*/
static void* alloc (size_t size, size_t count) throw (ShareException) {
return alloc (size * count);
}
/**
* Free block of memory previously allocated by alloc() method.
* @param addr Address of block returned by alloc() method.
* @attention All attached application may crash if this method is called with invalid address as parameter
*/
static void free (void *addr) throw ()
{
ShareManager::instance()-> free (addr);
}
protected:
SharedObject () { } ///< This is base class only and could not be instantiated direct
~SharedObject () { } ///< This is base class only and could not be deleted direct
};
/**
* @brief @b Relocable @b pointer type.
* @note Used for STL allocator.
* @ingroup core
*/
template <class T> class RelocPtr: public SharedObject {
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef typename TVoidPointer<T>::void_pointer void_pointer; ///< @copydoc TVoidPointer::void_pointer
typedef typename TVoidPointer<T>::const_void_pointer const_void_pointer; ///< @copydoc TVoidPointer::const_void_pointer
typedef typename TReference<T>::reference reference; ///< @copydoc TReference::reference
typedef typename TReference<T>::const_reference const_reference; ///< @copydoc TReference::const_reference
typedef typename Relocator::relative_pointer relative_pointer; ///< @copydoc Relocator::relative_pointer
typedef typename Relocator::relative_const_pointer relative_const_pointer; ///< @copydoc Relocator::relative_const_pointer
/**
* @brief STL iterator category
*/
typedef std::random_access_iterator_tag iterator_category;
/**
* Construct null pointer
*/
RelocPtr ():
rel_ (0)
{
}
/**
* Initialize object using ShareManager singleton to obtain relative address.
* @param abs Absolute pointer to save to object.
*/
RelocPtr (void_pointer abs):
rel_ (ShareManager::instance()-> absToRel (abs))
{
}
/**
* Initialize object using given base address.
* @param abs Absolute pointer to save to object.
* @param base Base address for relocation.
*/
RelocPtr (void_pointer abs, void *base):
rel_ (Relocator::absToRel (abs, base))
{
}
/**
* Copy constructor
*/
RelocPtr (const RelocPtr &src):
SharedObject(),
rel_ (src.rel_)
{
}
/**
* Assignment
*/
RelocPtr& operator= (const RelocPtr &src) {
rel_= src.rel_;
return *this;
}
/**
* Assignment from absolute pointer
*/
RelocPtr& operator= (void_pointer abs) {
rel_= ShareManager::instance()-> absToRel (abs);
return *this;
}
/**
* Implicit conversion for accessing members
* @return Return absolute pointer using ShareManager singleton to obtain absolute address.
*/
pointer operator-> () const {
return static_cast <T *> (ShareManager::instance()-> relToAbs (rel_));
}
/**
* @brief Implicit conversion to native pointer.
* @return Return absolute pointer using ShareManager singleton to obtain absolute address.
* @callgraph
*/
operator pointer () const {
return operator-> ();
}
/**
* Indexer
* @param i index
*/
reference operator[] (size_type i) {
RelocPtr<T> tmp (*this);
tmp+= i;
return *(tmp.operator->());
}
/**
* @brief @b Export pointer to number
*/
relative_pointer toRel () const {
return rel_;
}
/**
* @brief @b Import pointer from number
*/
static RelocPtr<T> fromRel (relative_pointer rel) {
RelocPtr<T> tmp;
tmp.rel_= rel;
return tmp;
}
/**
* Pre-increment
*/
RelocPtr& operator++ () {
rel_+= sizeof(T);
return *this;
}
/**
* Pre-decrement
*/
RelocPtr& operator-- () {
rel_-= sizeof(T);
return *this;
}
/**
* Overloaded operator +=
*/
RelocPtr& operator+= (difference_type count) {
rel_+= count * sizeof(T);
return *this;
}
/**
* Overloaded operator -=
*/
RelocPtr& operator-= (difference_type count) {
rel_-= count * sizeof(T);
return *this;
}
private:
relative_pointer rel_; ///< Internal pointer representation
};
/**
* @brief RelocPtr post-increment
*/
template <class T> RelocPtr<T> operator++ (RelocPtr<T> &ptr, int)
{
RelocPtr<T> tmp(ptr);
++ptr;
return tmp;
}
/**
* @brief RelocPtr post-decrement
*/
template <class T> RelocPtr<T> operator-- (RelocPtr<T> &ptr, int)
{
RelocPtr<T> tmp(ptr);
--ptr;
return tmp;
}
/**
* @brief RelocPtr pointer difference
*/
template <class T> ptrdiff_t operator- (RelocPtr<T> &a, RelocPtr<T> &b)
{
return (a.toRel()-b.toRel())/sizeof(T);
}
/**
* @brief RelocPtr pointer arithmetic - go next N
*/
template <class T> RelocPtr<T> operator+ (RelocPtr<T> ptr, ptrdiff_t diff)
{
ptr+= diff;
return ptr;
}
/**
* @brief RelocPtr pointer arithemtic - go back N
*/
template <class T> RelocPtr<T> operator- (RelocPtr<T> ptr, ptrdiff_t diff)
{
ptr-= diff;
return ptr;
}
/**
* Equivalent to std::allocator using ShareManager to define storage.
* @brief STL @b allocator
* @bug This allocator is known not to work with usual implementations of STL.
* @ingroup core
*/
template <class T> class Allocator {
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef RelocPtr<T> pointer; ///< @brief Using relocable pointer type
typedef RelocPtr<const T> const_pointer; ///< @brief Using relocable pointer type
typedef T& reference;
typedef const T& const_reference;
/**
* @note Not used for now
*/
Allocator() throw() { }
/**
* @note Not used for now
*/
~Allocator() throw() { }
/**
* Copy constructor
*/
template <class U> Allocator (const Allocator<U>&) throw() { }
/**
* Another type of allocator can be derived from existing one using this template.
* @brief STL allocator type adapter template
*/
template <class U>
struct rebind {
typedef Allocator<U> other;
};
/**
* @param obj Reference to object
* @return Return pointer to object
*/
pointer address (reference obj) const {
return &obj;
}
/**
* @param obj Reference to const object
* @return Return pointer to const object
*/
const_pointer address (const_reference obj) const {
return &obj;
}
/**
* Allocate array of object
* @param count Count of object to allocate
* @return Return pointer to allocated array
*/
pointer allocate (size_type count) {
return pointer (static_cast<T*>(ShareManager::instance()-> alloc (sizeof(T), count)));
}
/**
* Deallocate array of object
* @param addr Pointer to array to deallocate
* @param count Count of object to deallocate
* @note Parameter @c count is not used by default implementation
*/
void deallocate (pointer addr, size_type count) {
ShareManager::instance()-> free (addr, count);
}
void construct (pointer p, const T& val) {
::new(p) T(val);
}
void destroy (pointer p) {
p->~T();
}
size_type max_size () const throw() {
return
(ShareManager::instance()-> available())
/sizeof(T);
}
};
template <class T1, class T2> bool operator== (const Allocator<T1>&, const Allocator<T2>&) throw() { return true; }
template <class T1, class T2> bool operator!= (const Allocator<T1>&, const Allocator<T2>&) throw() { return false; }
// Patch for Microsoft C++ compiler
#ifdef _WIN32
template <> void Allocator<char>::destroy(Allocator<char>::pointer) { }
#endif // _WIN32
/**
* Light-weight implementation of STL std::vector
* @brief STL vector
* @ingroup stl
* @param TItem Type of object stored in container.
* @param TAllocator Type of allocator for container. Default is @b std::allocator. For sharing use Share::Allocator instead.
*/
template <
class TItem,
class TAllocator = std::allocator<TItem>
>
class Vector {
/**
* Base capacity of vector to allocate. Given as exponent of 2^n.
*/
static const size_t allocBase2Exp = 4;
/**
* Allocation down factor. Given as exponent of 2^n.
*/
static const size_t allocDownFactor2Exp = 2;
typedef typename TAllocator::size_type size_type;
typedef typename TAllocator::difference_type difference_type;
typedef typename TAllocator::pointer pointer;
typedef typename TAllocator::const_pointer const_pointer;
typedef typename TAllocator::reference reference;
typedef typename TAllocator::const_reference const_reference;
public:
typedef pointer iterator; ///< STL vector iterator equivalent
typedef const_pointer const_iterator; ///< STL vector const_iterator equivalent
/**
* Construct empty vector
*/
Vector():
size_ (0),
capacity_ (0),
data_ (0)
{
lowLevelResize(0);
}
Vector (size_type size):
size_ (0),
capacity_ (0),
data_ (0)
{
lowLevelResize(size);
size_ = size;
}
/**
* Copy constructor
*/
Vector (const Vector &other):
size_ (0),
capacity_ (0),
data_ (0)
{
operator= (other);
}
/**
* assignment
*/
Vector& operator= (const Vector &other) {
size_type newSize = other.size();
lowLevelResize(newSize);
size_ = newSize;
TItem *s1 = begin();
const TItem *s2 = other.begin();
const TItem *s2end = other.end();
for (; s2!=s2end; s1++, s2++)
alloc_.construct (s1, *s2);
return *this;
}
~Vector() {
TItem *pEnd = end();
for (TItem *i=begin(); i!=pEnd; i++)
alloc_.destroy (i);
alloc_.deallocate (data_, capacity_);
}
/**
* Indexer
* @param index index
* @return Return reference to indexed object.
*/
reference operator[] (size_type index) {
return data_[index];
}
/**
* @copydoc operator[](size_type)
*/
const_reference operator[] (size_type index) const {
return data_[index];
}
/**
* equivalence
*/
bool operator== (const Vector &other) const {
const TItem *s1 = begin();
const TItem *s2 = other.begin();
for (; s1!=end() && s2!=other.end(); s1++, s2++)
if (*s1 != *s2)
return false;
return
s1 == end() &&
s2 == other.end();
}
/**
* non-equivalence
*/
bool operator!= (const Vector &other) const {
return !operator== (other);
}
/**
* @return Return iterator pointing to begin of vector.
*/
iterator begin() {
return data_;
}
/**
* @return Return iterator pointing behind the last element of vector.
*/
iterator end() {
return data_ + static_cast<difference_type> (size_);
}
/**
* @copydoc begin()
*/
const_iterator begin() const {
return static_cast<const_iterator>(data_);
}
/**
* @copydoc end()
*/
const_iterator end() const {
return static_cast<const_iterator>(data_ + static_cast<difference_type>(size_));
}
/**
* Remove all items from vector.
*/
void clear() {
for (TItem *i=begin(); i!=end(); i++)
alloc_.destroy (i);
lowLevelResize(0);
size_ = 0;
}
/**
* @return Return true if vector is empty.
*/
bool empty() const {
return size_==0;
}
/**
* Append item to end of vector.
* @param item Item to append.
* @note Vector capacity will be increased if needed.
*/
void push_back (const_reference item) {
lowLevelResize (size_ + 1, true);
alloc_.construct (this + static_cast<difference_type>(size_), item);
size_ ++;
}
/**
* Remove last element of vector
* @attention This method could not be called if vector is empty.
*/
void pop_back() {
lowLevelResize(size_ - 1, true);
size_ --;
}
/**
* @return Return size of vector
*/
size_type size() const {
return size_;
}
/**
* Resize vector to desired size.
* @param newSize Desired size of vector
* @param val Value to assign to new object if newSize is greater then current size.
*/
void resize (size_type newSize, const_reference val= TItem()) {
lowLevelResize(newSize, true);
for (; size_ < newSize; size_++)
data_[size_] = val;
size_ = newSize;
}
private:
TAllocator alloc_;
size_type size_;
size_type capacity_;
iterator data_;
void lowLevelCopy (TItem *dest, const TItem *src, size_type count) {
for (size_type i=0; i<count; i++, dest++, src++)
*dest = *src;
}
void lowLevelResize (size_type newSize, bool bCopyContent=false) {
static const size_type allocBaseSize = 1 << allocBase2Exp;
if (newSize < allocBaseSize)
newSize = allocBaseSize;
if (
newSize <= capacity_ &&
newSize >= (capacity_ >> allocDownFactor2Exp)
)
return;
for (capacity_= allocBaseSize; capacity_<newSize; capacity_<<=1);
TItem *newBlock = alloc_.allocate (capacity_);
if (data_) {
if (bCopyContent)
lowLevelCopy (newBlock, static_cast<const_iterator>(data_), size_);
alloc_.deallocate (data_, size_);
}
data_ = newBlock;
}
};
/**
* Light-weight implementation of std::string
* @brief STL string
* @ingroup stl
* @param TAllocator Type of allocator for container. Default is @b std::allocator. For sharing use Share::Allocator instead.
*/
template <class TAllocator = std::allocator<char> >
class String {
typedef char TItem;
typedef Vector<TItem, TAllocator> TContainer;
typedef typename TAllocator::size_type size_type;
typedef typename TAllocator::difference_type difference_type;
typedef typename TAllocator::pointer pointer;
typedef typename TAllocator::const_pointer const_pointer;
typedef typename TAllocator::reference reference;
typedef typename TAllocator::const_reference const_reference;
public:
typedef typename TContainer::iterator iterator; ///< STL string iterator equivalent
typedef typename TContainer::const_iterator const_iterator; ///< STL string const_iterator equivalent
/**
* Construct empty string
*/
String():
array_ (1, '\0')
{
}
/**
* Construct string of desired size
* @param size Desired size of string.
* @param val Character to fill string.
*/
String (size_type size, const_reference val):
array_ (size+1, val)
{
array_ [size] = '\0';
}
/**
* Construct string from existing zero-ended string.
* @param sz Pointer to zero-ended string.
*/
String (const TItem *sz):
array_ (szLength (sz)+1)
{
TItem *i = array_.begin();
for (; *sz; sz++, i++)
*i = *sz;
*i = '\0';
}
/**
* Copy constructor
*/
String (const String &other):
array_ (other.array_)
{
}
/**
* assignment
*/
String& operator= (const TItem *sz) {
array_.resize (szLength (sz)+1);
TItem *i = array_.begin();
for (; *sz; sz++, i++)
*i = *sz;
*i = '\0';
return *this;
}
/**
* assignment
*/
String& operator= (const String &other) {
array_ = other.array_;
return *this;
}
/**
* @param index Index of desired character
* @return Return reference to character at desired position.
*/
reference operator[] (size_type index) {
return array_[index];
}
/**
* @copydoc operator[](size_type)
*/
const_reference operator[] (size_type index) const {
return array_[index];
}
/**
* @return Return iterator pointing to first character of string.
*/
iterator begin() {
return array_.begin();
}
/**
* @return Return itertor pointing behind the last character of string.
*/
iterator end() {
return array_.end()-1;
}
/**
* @copydoc begin()
*/
const_iterator begin() const {
return array_.begin();
}
/**
* @copydoc end()
*/
const_iterator end() const {
return array_.end()-1;
}
/**
* Lexical comparation with other string
* @param other Other string to compare to
* @return Return equivalen of strcmp (this, other)
*/
int compare (const String &other) const {
const TItem *s1 = begin();
const TItem *s2 = other.begin();
const TItem *s1end = end();
const TItem *s2end = other.end();
for (; s1!=s1end && s2!=s2end; s1++, s2++) {
if (*s1 < *s2)
return -1;
else if (*s1 > *s2)
return 1;
}
if (s1 != end())
return 1;
else if (s2 != other.end())
return -1;
else
return 0;
}
bool operator== (const String<TAllocator> &other) const { return 0==compare (other); }
bool operator!= (const String<TAllocator> &other) const { return 0!=compare (other); }
bool operator<= (const String<TAllocator> &other) const { return 0>=compare (other); }
bool operator>= (const String<TAllocator> &other) const { return 0<=compare (other); }
bool operator< (const String<TAllocator> &other) const { return 0> compare (other); }
bool operator> (const String<TAllocator> &other) const { return 0< compare (other); }
/**
* @note Not implemented yet.
*/
void append (const TItem *);
/**
* Replace string with empty string.
*/
void clear() {
array_.clear();
}
/**
* @return Return true if string is empty.
*/
bool empty() const {
return array_.empty();
}
/**
* @return String length
*/
size_type length() const {
return array_.size();
}
/**
* @return Return pointer to zero-ended string.
*/
const TItem* c_str() const {
return array_.begin();
}
private:
TContainer array_;
TAllocator alloc_;
private:
static size_type szLength (const TItem *sz) {
int len = 0;
while (*sz)
len++, sz++;
return len;
}
};
/**
* @brief Share::Vector string concatenation
*/
template <class A> String<A> operator+ (String<A> s1, const String<A> &s2)
{
s1.append (s2);
return s1;
}
/**
* Light-weight implementation of std::pair
* @brief STL pair
* @ingroup stl
*/
template <
class TFirst,
class TSecond
>
struct Pair {
TFirst first;
TSecond second;
};
/**
* Light-weight implementation of std::map
* @brief STL map
* @ingroup stl
* @param TKey Type of map key
* @param TValue Type of map value
* @param TAllocator Type of allocator for container. Default is @b std::allocator. For sharing use Share::Allocator instead.
*/
template <
class TKey,
class TValue,
class TAllocator = std::allocator< Pair<TKey, TValue> >
>
class Map {
/**
* Default hashTable size
*/
static const size_t defaultHtSize = 1 << 12;
typedef Pair<TKey, TValue> TData;
typedef TData& TData_reference;
typedef const TData* TData_const_pointer;
typedef size_t size_type;
typedef typename TAllocator::template rebind<Map>::other TMapAllocator;
typedef typename TMapAllocator::const_pointer TMap_const_pointer;
public:
/**
* @param htSize Size of hash table
* @note This is not standardized constructor.
*/
Map (size_type htSize= defaultHtSize):
htSize_ (htSize)
{
htArray_ = pItemAlloc_.allocate (htSize_);
for (size_type i=0; i<htSize_; i++)
htArray_[i]=0;
}
private:
struct Item;
typedef typename TAllocator::template rebind<Item>::other TItemAllocator;
typedef typename TItemAllocator::pointer TItem_pointer;
typedef typename TItemAllocator::const_pointer TItem_const_pointer;
typedef typename TItemAllocator::reference TItem_reference;
struct Item {
TData data;
TItem_pointer next;
};
typedef typename TAllocator::template rebind<TItem_pointer>::other TPItemAllocator;
typedef typename TPItemAllocator::pointer TPItem_pointer;
public:
/**
* @brief STL map const_iterator equivalent
* @ingroup stl
*/
class const_iterator {
public:
const_iterator():
hTable_ (0),
hashIndex_ (0),
item_ (0)
{
}
/**
* @return Return pointer to member.
*/
TData_const_pointer operator->() {
if (!item_)
return 0;
else
return &(item_-> data);
}
/**
* Implicit conversion to pointer.
*/
operator TData_const_pointer() {
return operator->();
}
/**
* iterator - step forward operation
*/
const_iterator& operator ++() {
if (item_)
item_ = item_-> next;
if (!item_) {
for (
hashIndex_++;
hashIndex_ < hTable_->htSize_ && hTable_->htArray_[hashIndex_] == 0;
hashIndex_ ++);
if (hashIndex_ < hTable_->htSize_)
item_ = hTable_-> htArray_ [hashIndex_];
}
return *this;
}
/**
* @copydoc operator++()
*/
const_iterator operator ++(int) {
const_iterator tmp = *this;
operator ++();
return tmp;
}
/**
* iterator comparatation
*/
bool operator== (const const_iterator &other) {
return
hTable_ == other.hTable_ &&
item_ == other.item_;
}
/**
* iterator negative comparation
*/
bool operator!= (const const_iterator &other) {
return !operator== (other);
}
private:
const_iterator (TMap_const_pointer ht, size_type hashIndex, TItem_const_pointer item):
hTable_ (ht),
hashIndex_ (hashIndex),
item_ (item)
{
}
private:
TMap_const_pointer hTable_;
size_type hashIndex_;
TItem_const_pointer item_;
friend class Map;
}; // (class const_iterator)
~Map() {
clear();
pItemAlloc_.deallocate (htArray_, htSize_);
}
/**
* Remove all items from map.
*/
void clear() {
TItem_pointer *ppCurrent = htArray_;
for (size_type hashIndex=0; hashIndex<htSize_; hashIndex++, ppCurrent++) {
Item *pCurrent = *ppCurrent;
while (pCurrent) {
Item *pNext = pCurrent->next;
itemAlloc_.destroy (pCurrent);
itemAlloc_.deallocate (pCurrent, 1);
pCurrent = pNext;
}
*ppCurrent = 0;
}
}
/**
* @brief Look up for key in map by key.
* @param key to look up
* @return Return iterator of found item, end() if not found.
*/
const_iterator find (const TKey &key) {
size_type hashIndex = hashFunction (key);
TItem_pointer pCurrent = htArray_ [hashIndex];
while (pCurrent && pCurrent->data.first != key)
pCurrent = pCurrent->next;
return const_iterator (this, hashIndex, pCurrent);
}
/**
* Look up for pair in map by key. New Pair is created if key is not found.
* @brief indexer
* @param key to look up
* @return Return reference to value.
*/
TValue& operator[] (const TKey &key) {
size_type hashIndex = hashFunction (key);
typedef typename TItemAllocator::difference_type TDiff;
TItem_pointer *ppCurrent = htArray_ + static_cast<TDiff>(hashIndex);
for (; *ppCurrent; ppCurrent = &((*ppCurrent)-> next)) {
TData_reference current = (*ppCurrent)-> data;
if (current.first == key)
return current.second;
}
Item item = {
{ key, TValue() },
0
};
*ppCurrent = itemAlloc_.allocate (1);
itemAlloc_.construct (*ppCurrent, item);
return (*ppCurrent)->data.second;
}
/**
* @return Return iterator to begin of map.
* @note There is no way to get map elements in specified order by const_iterator
*/
const_iterator begin() const {
const_iterator iter (this, 0, 0);
iter++;
return iter;
}
/**
* @return Return iterator to element behind end of map.
* @note There is no way to get map elements in specified order by const_iterator
*/
const_iterator end() const {
return const_iterator (this, 0, 0);
}
private:
size_t htSize_;
TPItem_pointer htArray_;
TItemAllocator itemAlloc_;
TPItemAllocator pItemAlloc_;
/**
* @note Implementation for string only
*/
template<class T> size_t hashFunction (const T &key) {
typedef typename T::const_iterator Iterator;
Iterator i= key.begin();
unsigned int h=0;
for (; i != key.end(); i++) {
unsigned char p = static_cast<unsigned char> (*i);
h = 31*h + p;
}
return h % htSize_;
}
};
}
#endif // SHARELIB_H