blob: f1f44daf02e05fa5cb14070f1a0257521d028e9a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Created on: 13 janv. 2017
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and implementation
******************************************************************************/
#ifndef BASE_SMARTTABLE_H_
#define BASE_SMARTTABLE_H_
#include <util/avm_assert.h>
#include <util/avm_debug.h>
#include <util/avm_injector.h>
#include <util/avm_numeric.h>
#include <base/ReferenceCounter.h>
#include <base/SmartPointer.h>
#include <printer/OutStream.h>
namespace sep
{
template< class T, class Tdestructor >
class SmartTable
{
protected:
/**
* TYPEDEF
*/
typedef SmartTable < T , Tdestructor > this_type;
typedef SmartPointer< T , Tdestructor > smart_pointer_t;
protected:
/**
* TYPEDEF
*/
typedef T value_type;
typedef T & reference_t;
typedef const T & const_reference_t;
typedef T * pointer_t;
typedef const T * const_pointer_t;
typedef T * & reference_pointer_t;
typedef const T * & const_reference_pointer_t;
typedef T * * pointer_pointer_t;
typedef const T * * const_pointer_pointer_t;
public:
typedef T * * iterator;
typedef T * const * const_iterator;
private:
/**
* Internal Table
*/
struct TableT : public ReferenceCounter,
AVM_INJECT_INSTANCE_COUNTER_CLASS( TableT )
{
/**
* ATTRIBUTES
*/
avm_size_t mSize;
pointer_pointer_t mElements;
/**
* CONSTRUCTOR
* Default
*/
TableT()
: ReferenceCounter( ),
mSize( 0 ),
mElements( NULL )
{
//!! NOTHING
}
TableT(avm_size_t aSize, pointer_t aDefaultValue = NULL)
: ReferenceCounter( ),
mSize( aSize ),
mElements( NULL )
{
alloc(aDefaultValue);
}
/**
* CONSTRUCTOR
* Copy
*/
TableT(const TableT & aTable)
: ReferenceCounter( ),
mSize( aTable.mSize ),
mElements( NULL )
{
acquire( aTable );
}
TableT(avm_size_t aSize, const TableT & aTable,
pointer_t aDefaultValue = NULL)
: ReferenceCounter( ),
mSize( aSize ),
mElements( NULL )
{
acquire_resize( aTable, aDefaultValue );
}
/**
* DESTRUCTOR
*/
virtual ~TableT()
{
destroyTable();
mSize = 0;
}
inline void destroyTable()
{
for( avm_size_t offset = 0 ; offset < mSize ; ++offset )
{
Tdestructor::destroy( mElements[ offset ] );
}
}
/**
* ALLOCATION
*/
inline void alloc(pointer_t aDefaultValue = NULL)
{
if( mSize > 0 )
{
mElements = new pointer_t[ mSize ];
for( avm_size_t offset = 0 ; offset < mSize ; ++offset )
{
mElements[offset] = aDefaultValue;
}
}
else
{
mElements = NULL;
}
}
/**
* Resize
*/
inline void resize(avm_size_t aSize, pointer_t aDefaultValue = NULL)
{
if( aSize == 0 )
{
destroyTable();
mSize = 0;
}
else if( mSize > 0 )
{
avm_size_t oldSize = mSize;
pointer_pointer_t oldELements = mElements;
mElements = new pointer_t[ mSize = aSize ];
avm_size_t offset = 0;
// The size increased
if( aSize >= oldSize )
{
for( ; offset < oldSize ; ++offset )
{
mElements[offset] = oldELements[offset];
}
// Completion
for( ; offset < aSize ; ++offset )
{
mElements[offset] = aDefaultValue;
}
}
// The size decreased
else
{
for( ; offset < aSize ; ++offset )
{
mElements[offset] = oldELements[offset];
}
// Deletion
for( ; offset < oldSize ; ++offset )
{
Tdestructor::destroy( mElements[ offset ] );
}
}
delete [] oldELements;
}
else
{
mSize = aSize;
alloc(aDefaultValue);
}
}
/**
* acquire
* release
* release_acquire
*/
inline void acquire(const TableT & aTable)
{
if( mSize > 0 )
{
mElements = new pointer_t[ mSize ];
// Acquire
for( avm_size_t offset = 0 ; offset < mSize ; ++offset )
{
acquire(offset, aTable.mElements[offset]);
}
}
else
{
mElements = NULL;
}
}
inline void acquire_resize(
const TableT & aTable, pointer_t aDefaultValue)
{
if( mSize > 0 )
{
mElements = new pointer_t[ mSize ];
avm_size_t offset = 0;
avm_size_t minBound = std::min(mSize, aTable.mSize);
// Acquire
for( ; offset < minBound ; ++offset )
{
acquire(offset, aTable.mElements[offset]);
}
// Completion if need
for( ; offset < mSize ; ++offset )
{
mElements[offset] = aDefaultValue;
}
}
else
{
mElements = NULL;
}
}
inline void acquire(avm_size_t offset, pointer_t anElement)
{
if( anElement != NULL )
{
anElement->incrRefCount();
}
mElements[offset] = anElement;
}
inline void release(avm_size_t offset, pointer_t anElement)
{
Tdestructor::destroy( mElements[offset] );
mElements[offset] = anElement;
}
inline void release_acquire(avm_size_t offset, pointer_t anElement)
{
Tdestructor::destroy( mElements[offset] );
if( anElement != NULL )
{
anElement->incrRefCount();
}
mElements[offset] = anElement;
}
/**
* Writable
*/
inline TableT * clone_acquire() const
{
return( new TableT(*this) );
}
inline TableT * clone_resize_acquire(
avm_size_t aSize, pointer_t aDefaultValue = NULL) const
{
return( new TableT(aSize, *this, aDefaultValue) );
}
};
protected:
/**
* TYPEDEF
*/
typedef TableT table_type;
typedef TableT * table_pointer_t;
protected:
/*
* ATTRIBUTES
*/
table_pointer_t mTable;
public:
/**
* CONSTRUCTOR
* Default
*/
explicit SmartTable(table_pointer_t aTable = NULL)
: mTable( aTable )
{
//!! NOTHING
}
SmartTable(avm_size_t aSize, pointer_t aDefaultValue = NULL)
: mTable( new table_type(aSize, aDefaultValue) )
{
//!! NOTHING
}
SmartTable(avm_size_t aSize,
const SmartTable & aSmartTable, pointer_t aDefaultValue = NULL)
: mTable( NULL )
{
if( aSize == aSmartTable.size() )
{
acquire( aSmartTable.mTable );
}
else
{
mTable = aSmartTable.mTable
->clone_resize_acquire(aSize, aDefaultValue);
}
}
/**
* CONSTRUCTOR
* Copy
*/
SmartTable(const SmartTable & aSmartTable)
: mTable( NULL )
{
acquire( aSmartTable.mTable );
}
template< class U >
SmartTable(const SmartTable< U , Tdestructor > & aSmartTable)
: mTable( NULL )
{
acquire( aSmartTable.mTable );
}
/**
* DESTRUCTOR
*/
~SmartTable()
{
destroy();
}
inline void destroy()
{
destroyTable( mTable );
}
inline void destroyTable(table_pointer_t & aTable)
{
if( aTable != NULL )
{
if( aTable->isUnique() )
{
delete( aTable );
}
else
{
aTable->decrRefCount();
}
aTable = NULL;
}
}
/**
* mSize
*/
inline avm_size_t size() const
{
return( (mTable == NULL) ? 0 : mTable->mSize );
}
inline bool empty() const
{
return( (mTable == NULL) || (mTable->mSize == 0) );
}
inline bool nonempty() const
{
return( (mTable != NULL) && (mTable->mSize > 0) );
}
inline bool populated() const
{
return( (mTable != NULL) && (mTable->mSize > 1) );
}
/**
* GETTER
* for element at given position by reference
* return( [const_]pointer_t )
*/
inline pointer_t at(avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( mTable->mElements[offset] );
}
inline const_pointer_t at(avm_size_t offset) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( mTable->mElements[offset] );
}
/**
* GETTER
* for element at given position
* return( [const_]reference_t )
*/
inline reference_t ref(avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( *( mTable->mElements[offset] ) );
}
inline const_reference_t ref(avm_size_t offset) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( *( mTable->mElements[offset] ) );
}
/**
* SETTER
* for element at given position
*/
inline void set(avm_size_t offset, pointer_t anElement) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
mTable->mElements[offset] = anElement;
}
inline void append(pointer_t anElement) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( 0 , size() )
<< SEND_EXIT;
avm_size_t offset = 0;
for( ; offset < mTable->mSize ; ++offset )
{
if( mTable->mElements[ offset ] == NULL )
{
mTable->mElements[offset] = anElement;
return;
}
}
AVM_OS_ASSERT_FATAL_ERROR_EXIT( offset < mTable->mSize )
<< "Unexpected a full SmartTable in method append(...) !"
<< SEND_EXIT;
}
/**
* SETTER
* for element at given position
* update reference counter:> release acquire
*/
inline void assign(avm_size_t offset, pointer_t anElement) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
mTable->release_acquire(offset, anElement);
}
inline void assign(avm_size_t offset,
const smart_pointer_t & anElement) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
mTable->release_acquire(offset, anElement.raw_pointer());
}
/**
* GETTER
* for element at given position
* return( Smart Pointer )
*/
template< class SmartPointerT >
inline SmartPointerT to_sp(avm_size_t offset) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
if( //(mTable != NULL) && (mTable->mSize > offset) &&
(mTable->mElements[ offset ] != NULL) )
{
mTable->mElements[ offset ]->incrRefCount();
return( SmartPointerT( mTable->mElements[offset] ) );
}
return( SmartPointerT() );
}
/**
* GETTER
* for element at given position
* operator[]
* return( [const_]reference_t )
*/
inline reference_t operator[](avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( *( mTable->mElements[offset] ) );
}
inline const_reference_t operator[](avm_size_t offset) const
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
return( *( mTable->mElements[offset] ) );
}
/**
* GETTER
* for element at ( front | back ) position
* return( [const_]pointer_t )
*/
inline reference_pointer_t front()
{
return((size() == 0) ? NULL : mTable->mElements[ 0 ] );
}
inline const_reference_pointer_t front() const
{
return( (size() == 0) ? NULL : mTable->mElements[ 0 ] );
}
inline reference_pointer_t back()
{
return( (size() == 0) ? NULL : mTable->mElements[mTable->mSize - 1] );
}
inline const_reference_pointer_t back() const
{
return( (size() == 0) ? NULL : mTable->mElements[mTable->mSize - 1] );
}
/**
* ITERATOR
*/
inline iterator begin()
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
return( mTable->mElements );
}
inline const_iterator begin() const
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
return( mTable->mElements );
}
inline iterator end()
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
return( mTable->mElements + size() );
}
inline const_iterator end() const
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
return( mTable->mElements + size() );
}
/**
* REFCOUNT
*/
inline avm_uint32_t getRefCount() const
{
return( ( mTable == NULL ) ? 0 : mTable->getRefCount() );
}
inline bool isUnique() const
{
return( (mTable == NULL) ? false : mTable->isUnique() );
}
inline bool isMultiple() const
{
return( (mTable == NULL) ? false : mTable->isMultiple() );
}
/**
* AVM DEBUG REF COUNTER
*/
inline void AVM_DEBUG_REF_COUNTER(OutStream & os) const
{
AVM_IF_DEBUG_FLAG( REFERENCE_COUNTING )
if( mTable != NULL )
{
os << " /* < ref: " << mTable->getRefCount() << " > */";
}
else
{
os << " /* < ref: SmartTable<null> */";
}
os << std::flush;
AVM_ENDIF_DEBUG_FLAG( REFERENCE_COUNTING )
}
/**
* WRITABILITY
*/
inline bool isWritable() const
{
return( getRefCount() == 1 );
}
inline bool isnotWritable() const
{
return( getRefCount() != 1 );
}
inline void makeWritable()
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
if( mTable->isMultiple() )
{
mTable->decrRefCount();
mTable = mTable->clone_acquire();
}
}
inline void makeWritable(avm_size_t offset)
{
makeWritable();
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
if( mTable->mElements[offset]->isMultiple() )
{
mTable->mElements[offset]->decrRefCount();
mTable->mElements[offset] = mTable->mElements[offset]->clone();
}
}
/**
* GETTER
* for witable element at given position
* return( reference_pointer_t )
*/
inline reference_pointer_t getWritable(avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
makeWritable();
if( mTable->mElements[offset]->isMultiple() )
{
mTable->mElements[offset]->decrRefCount();
mTable->mElements[offset] = mTable->mElements[offset]->clone();
}
return( mTable->mElements[offset] );
}
/**
* GETTER
* for witable element at given position
* return( reference_t )
*/
inline reference_t refWritable(avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
makeWritable();
if( mTable->mElements[offset]->isMultiple() )
{
mTable->mElements[offset]->decrRefCount();
mTable->mElements[offset] = mTable->mElements[offset]->clone();
}
return( *( mTable->mElements[offset] ) );
}
// template< class ElementT >
// inline reference_pointer_t getWritable(ElementT * anElement)
// {
// return( getWritable( anElement->getOffset() ) );
// }
/**
* GETTER
* for witable element at given position
* return( SmartPointerT )
*/
template< class SmartPointerT >
inline SmartPointerT spWritable(avm_size_t offset)
{
AVM_OS_ASSERT_FATAL_ARRAY_INDEX_EXIT( offset , size() )
<< SEND_EXIT;
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
makeWritable();
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable->mElements[offset] )
<< " pointer in an SmartTable at offset: " << offset << " !!!"
<< SEND_EXIT;
if( mTable->mElements[offset]->isMultiple() )
{
mTable->mElements[offset]->decrRefCount();
mTable->mElements[offset] = mTable->mElements[offset]->clone();
}
mTable->mElements[ offset ]->incrRefCount();
return( SmartPointerT(mTable->mElements[offset]) );
}
/**
* RESIZE
*/
inline void makeWritableResize(
avm_size_t aSize, pointer_t aDefaultValue = NULL)
{
AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
<< " Table in an SmartTable !!!"
<< SEND_EXIT;
if( mTable->isMultiple() )
{
mTable->decrRefCount();
mTable = mTable->clone_resize_acquire(aSize, aDefaultValue);
}
else // if( mTable->isUnique() > 1 )
{
mTable->resize(aSize, aDefaultValue);
}
}
/**
* [IN]VALIDITY
*/
inline bool isNull() const
{
return( mTable == NULL );
}
inline bool isNull(avm_size_t offset) const
{
// AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
// << " Table in an SmartTable !!!"
// << SEND_EXIT;
return( (mTable == NULL)
|| (mTable->mElements[offset] == NULL) );
}
inline bool invalid() const
{
return( mTable == NULL );
}
inline bool invalid(avm_size_t offset) const
{
// AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
// << " Table in an SmartTable !!!"
// << SEND_EXIT;
return( (mTable == NULL)
|| (mTable->mElements[offset] == NULL) );
}
inline bool isnotNull() const
{
return( mTable != NULL );
}
inline bool isnotNull(avm_size_t offset) const
{
// AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
// << " Table in an SmartTable !!!"
// << SEND_EXIT;
return( (mTable != NULL)
&& (mTable->mElements[offset] != NULL) );
}
inline bool valid() const
{
return( mTable != NULL );
}
inline bool valid(avm_size_t offset) const
{
// AVM_OS_ASSERT_FATAL_NULL_POINTER_EXIT( mTable )
// << " Table in an SmartTable !!!"
// << SEND_EXIT;
return( (mTable != NULL)
&& (mTable->mElements[offset] != NULL) );
}
/**
* SWAP
* FLUSH
*/
inline void swap(SmartTable & other)
{
std::swap(mTable, other.mTable);
}
inline void flush(SmartTable & other)
{
release( other.mTable );
other.mTable = NULL;
}
/**
* GETTER
* mTable
*/
inline avm_address_t raw_address() const
{
return( avm_address_t( mTable ) );
}
/**
* ASSIGNMENT
*/
inline SmartTable & operator=(table_pointer_t aTable)
{
if( mTable != aTable )
{
release( aTable );
}
return( *this );
}
inline SmartTable & operator=(const SmartTable & other)
{
if( mTable != other.mTable )
{
release_acquire( other.mTable );
}
return( *this );
}
/**
* COMPARISON
* OPERATOR
*/
inline bool operator==(table_pointer_t aTable) const
{
return( mTable == aTable );
}
inline bool operator==(const SmartTable & other) const
{
return( mTable == other.mTable );
}
template<class U>
inline bool operator==(
const SmartTable< U , Tdestructor > & other) const
{
return( mTable == other.raw_pointer() );
}
inline bool operator!=(table_pointer_t aTable) const
{
return( mTable != aTable );
}
inline bool operator!=(const SmartTable & other) const
{
return( mTable != other.mTable );
}
template<class U>
inline bool operator!=(
const SmartTable< U , Tdestructor > & other) const
{
return( mTable != other.raw_pointer() );
}
protected:
/**
* acquire
* release
* release_acquire
*/
// increment the count
inline void acquire(table_pointer_t aTable)
{
if( aTable != NULL )
{
aTable->incrRefCount();
}
mTable = aTable;
}
// decrement the count, delete if it is 0
inline void release(table_pointer_t aTable)
{
destroyTable( mTable );
mTable = aTable;
}
inline void release_acquire(table_pointer_t aTable)
{
destroyTable( mTable );
if( aTable != NULL )
{
aTable->incrRefCount();
}
mTable = aTable;
}
public:
/**
* Serialization
*/
inline std::string str() const
{
std::ostringstream oss;
if( mTable != NULL )
{
if( mTable->mSize > 0 )
{
oss << "[ " << mTable->mElements[ 0 ]->str();
for( avm_size_t offset = 1 ; offset < mTable->mSize ; ++offset )
{
if( mTable->mElements[ offset ] != NULL )
{
oss << " , " << mTable->mElements[ offset ]->str();
}
else
{
oss << " , null< T * >";
}
}
oss << " ]";
return( oss.str() );
}
else
{
return( "empty<SmartTable>" );
}
}
else
{
return( "null<SmartTable>" );
}
}
inline std::string toString(
const AvmIndent & indent = AVM_TAB_INDENT) const
{
StringOutStream oss(indent);
toStream( oss );
return( oss.str() );
}
inline void toStream(OutStream & os) const
{
if( mTable != NULL )
{
if( mTable->mSize > 0 )
{
for( avm_size_t offset = 0 ; offset < mTable->mSize ; ++offset )
{
if( mTable->mElements[ offset ] != NULL )
{
mTable->mElements[ offset ]->toStream(os);
}
else
{
os << TAB << "null< T * >" << EOL;
}
os << std::flush;
}
}
else
{
os << TAB << "empty<SmartTable>" << EOL_FLUSH;
}
}
else
{
os << TAB << "null<SmartTable>" << EOL_FLUSH;
}
}
};
} /* namespace sep */
#endif /* BASE_SMARTTABLE_H_ */