blob: 28a4d0bf114da01a71f082126c3af8056ce1af0c [file] [log] [blame]
// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
/**
* Generic templates for C++. These are templates that do not depend
* on any ucommon classes. They can be used for generic C++ programming.
* @file ucommon/generics.h
*/
#ifndef _UCOMMON_GENERICS_H_
#define _UCOMMON_GENERICS_H_
#ifndef _UCOMMON_CPR_H_
#include <ucommon/cpr.h>
#endif
#include <cstdlib>
#include <string.h>
#ifdef NEW_STDLIB
#include <stdexcept>
#endif
#if defined(NEW_STDLIB) || defined(OLD_STDLIB)
#define THROW(x) throw x
#define THROWS(x) throw(x)
#define THROWS_ANY throw()
#else
#define THROW(x) ::abort()
#define THROWS(x)
#define THROWS_ANY
#endif
NAMESPACE_UCOMMON
/**
* Generic smart pointer class. This is the original Common C++ "Pointer"
* class with a few additions.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <typename T>
class pointer
{
protected:
unsigned *counter;
T *object;
public:
inline void release(void) {
if(counter && --(*counter)==0) {
delete counter;
delete object;
}
object = NULL;
counter = NULL;
}
inline void retain(void) {
if(counter)
++*counter;
}
inline void set(T* ptr) {
if(object != ptr) {
release();
counter = new unsigned;
*counter = 1;
object = ptr;
}
}
inline void set(const pointer<T> &ref) {
if(object == ref.object)
return;
if(counter && --(*counter)==0) {
delete counter;
delete object;
}
object = ref.object;
counter = ref.counter;
if(counter)
++(*counter);
}
inline pointer() {
counter = NULL;
object = NULL;
}
inline explicit pointer(T* ptr = NULL) : object(ptr) {
if(object) {
counter = new unsigned;
*counter = 1;
}
else
counter = NULL;
}
inline pointer(const pointer<T> &ref) {
object = ref.object;
counter = ref.counter;
if(counter)
++(*counter);
}
inline pointer& operator=(const pointer<T> &ref) {
this->set(ref);
return *this;
}
inline pointer& operator=(T *ptr) {
this->set(ptr);
return *this;
}
inline ~pointer()
{release();}
inline T& operator*() const
{return *object;};
inline T* operator->() const
{return object;};
inline bool operator!() const
{return (counter == NULL);};
inline operator bool() const
{return counter != NULL;};
};
/**
* Generic smart array class. This is the original Common C++ "Pointer" class
* with a few additions for arrays.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <typename T>
class array_pointer
{
protected:
unsigned *counter;
T *array;
public:
inline void release(void) {
if(counter && --(*counter)==0) {
delete counter;
delete[] array;
}
array = NULL;
counter = NULL;
}
inline void retain(void) {
if(counter)
++*counter;
}
inline void set(T* ptr) {
if(array != ptr) {
release();
counter = new unsigned;
*counter = 1;
array = ptr;
}
}
inline void set(const array_pointer<T> &ref) {
if(array == ref.array)
return;
if(counter && --(*counter)==0) {
delete counter;
delete[] array;
}
array = ref.array;
counter = ref.counter;
if(counter)
++(*counter);
}
inline array_pointer() {
counter = NULL;
array = NULL;
}
inline explicit array_pointer(T* ptr = NULL) : array(ptr) {
if(array) {
counter = new unsigned;
*counter = 1;
}
else
counter = NULL;
}
inline array_pointer(const array_pointer<T> &ref) {
array = ref.array;
counter = ref.counter;
if(counter)
++(*counter);
}
inline array_pointer& operator=(const array_pointer<T> &ref) {
this->set(ref);
return *this;
}
inline array_pointer& operator=(T *ptr) {
this->set(ptr);
return *this;
}
inline ~array_pointer()
{release();}
inline T* operator*() const
{return array;};
inline T& operator[](size_t offset) const
{return array[offset];};
inline T* operator()(size_t offset) const
{return &array[offset];};
inline bool operator!() const
{return (counter == NULL);};
inline operator bool() const
{return counter != NULL;};
};
/**
* Manage temporary object stored on the heap. This is used to create a
* object on the heap who's scope is controlled by the scope of a member
* function call. Sometimes we have data types and structures which cannot
* themselves appear as auto variables. We may also have a limited stack
* frame size in a thread context, and yet have a dynamic object that we
* only want to exist during the life of the method call. Using temporary
* allows any type to be created from the heap but have a lifespan of a
* method's stack frame.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <typename T>
class temporary
{
protected:
T *object;
public:
/**
* Construct a temporary object, create our stack frame reference.
*/
inline temporary()
{object = NULL;};
/**
* Disable copy constructor.
*/
temporary(const temporary<T>&)
{::abort();};
/**
* Construct an assigned pointer.
*/
inline temporary(T *ptr)
{object = ptr;};
/**
* Assign a temporary object. This adds a pointer to an existing
* type to the current temporary pointer. If the temporary was
* already assigned, then it is deleted.
* @param temp object to assign.
*/
inline T& operator=(T *temp) {
if(object)
delete object;
object = temp;
return *this;
}
/**
* Assign a temporary object. This adds a pointer to an existing
* type to the current temporary pointer. If the temporary was
* already assigned, then it is deleted.
* @param temp object to assign.
*/
inline void set(T *temp) {
if(object)
delete object;
object = temp;
}
/**
* Access heap object through our temporary directly.
* @return reference to heap resident object.
*/
inline T& operator*() const
{return *object;};
/**
* Access members of our heap object through our temporary.
* @return member reference of heap object.
*/
inline T* operator->() const
{return object;};
inline operator bool() const
{return object != NULL;};
inline bool operator!() const
{return object == NULL;};
inline ~temporary() {
if(object)
delete object;
object = NULL;
}
};
/**
* Manage temporary array stored on the heap. This is used to create an
* array on the heap who's scope is controlled by the scope of a member
* function call. Sometimes we have data types and structures which cannot
* themselves appear as auto variables. We may also have a limited stack
* frame size in a thread context, and yet have a dynamic object that we
* only want to exist during the life of the method call. Using temporary
* allows any type to be created from the heap but have a lifespan of a
* method's stack frame.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <typename T>
class temp_array
{
protected:
T *array;
size_t size;
public:
/**
* Construct a temporary object, create our stack frame reference.
*/
inline temp_array(size_t s)
{array = new T[s]; size = s;};
/**
* Construct a temporary object with a copy of some initial value.
* @param initial object value to use.
*/
inline temp_array(const T& initial, size_t s) {
array = new T[s];
size = s;
for(size_t p = 0; p < s; ++p)
array[p] = initial;
}
inline void reset(size_t s)
{delete[] array; array = new T[s]; size = s;};
inline void reset(const T& initial, size_t s) {
if(array)
delete[] array;
array = new T[s];
size = s;
for(size_t p = 0; p < s; ++p)
array[p] = initial;
}
inline void set(const T& initial) {
for(size_t p = 0; p < size; ++p)
array[p] = initial;
}
/**
* Disable copy constructor.
*/
temp_array(const temp_array<T>&)
{::abort();};
inline operator bool() const
{return array != NULL;};
inline bool operator!() const
{return array == NULL;};
inline ~temp_array() {
if(array)
delete[] array;
array = NULL;
size = 0;
}
inline T& operator[](size_t offset) const {
crit(offset < size, "array out of bound");
return array[offset];
}
inline T* operator()(size_t offset) const {
crit(offset < size, "array out of bound");
return &array[offset];
}
};
/**
* Save and restore global objects in function call stack frames.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template<typename T>
class save_restore
{
private:
T *original;
T temp;
public:
/**
* Save object into local copy and keep reference to the original object.
* @param object to save.
*/
inline save_restore(T& object)
{original = &object; temp = object;};
/**
* Restore original when stack frame is released.
*/
inline ~save_restore()
{*original = temp;};
};
/**
* Convenience function to validate object assuming it is castable to bool.
* @param object we are testing.
* @return true if object valid.
*/
template<class T>
inline bool is(T& object)
{return object.operator bool();}
/**
* Convenience function to test pointer object. This solves issues where
* some compilers get confused between bool and pointer operators.
* @param object we are testing.
* @return true if object points to NULL.
*/
template<typename T>
inline bool isnull(T& object)
{return (bool)(object.operator*() == NULL);}
/**
* Convenience function to test pointer-pointer object. This solves issues
* where some compilers get confused between bool and pointer operators.
* @param object we are testing.
* @return true if object points to NULL.
*/
template<typename T>
inline bool isnullp(T *object)
{return (bool)(object->operator*() == NULL);}
/**
* Convenience function to duplicate object pointer to heap.
* @param object we are duping.
* @return heap pointer instance.
*/
template<typename T>
inline T* dup(const T& object)
{return new T(object);}
template<typename T>
inline void dupfree(T object)
{delete object;}
template<>
inline char *dup<char>(const char& object)
{return strdup(&object);}
template<>
inline void dupfree<char*>(char* object)
{::free(object);}
/**
* Convenience function to reset an existing object.
* @param object type to reset.
*/
template<typename T>
inline void reset_unsafe(T& object)
{new((caddr_t)&object) T;}
/**
* Convenience function to zero an object and restore type info.
* @param object to zero in memory.
*/
template<typename T>
inline void zero_unsafe(T& object)
{memset((void *)&object, 0, sizeof(T)); new((caddr_t)&object) T;}
/**
* Convenience function to copy class.
* @param target to copy into.
* @param source to copy from.
*/
template<typename T>
inline void copy_unsafe(T* target, const T* source)
{memcpy((void *)target, (void *)source, sizeof(T));}
/**
* Convenience function to store object pointer into object.
* @param target to copy into.
* @param source to copy from.
*/
template<typename T>
inline void store_unsafe(T& target, const T* source)
{memcpy((void *)&target, (void *)source, sizeof(T));}
/**
* Convenience function to swap objects.
* @param o1 to swap.
* @param o2 to swap.
*/
template<typename T>
inline void swap(T& o1, T& o2)
{cpr_memswap(&o1, &o2, sizeof(T));}
/**
* Convenience function to return max of two objects.
* @param o1 to check.
* @param o2 to check.
* @return max object.
*/
template<typename T>
inline T& (max)(T& o1, T& o2)
{
return o1 > o2 ? o1 : o2;
}
/**
* Convenience function to return min of two objects.
* @param o1 to check.
* @param o2 to check.
* @return min object.
*/
template<typename T>
inline T& (min)(T& o1, T& o2)
{
return o1 < o2 ? o1 : o2;
}
/**
* Convenience macro to range restrict values.
* @param value to check.
* @param low value.
* @param high value.
* @return adjusted value.
*/
template<typename T>
inline T& (limit)(T& value, T& low, T& high)
{
return (value < low) ? low : ((value > high) ? high : value);
}
END_NAMESPACE
#endif