blob: afeb69f777fd18c8d28f16059d9714ea341c13e4 [file] [log] [blame]
#ifndef UIMA_LOWLEVEL_HEAP_HPP
#define UIMA_LOWLEVEL_HEAP_HPP
/** \file lowlevel_heap.hpp .
-----------------------------------------------------------------------------
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-----------------------------------------------------------------------------
Description: Base Heap design. 32-bit heaps used for interop
-----------------------------------------------------------------------------
-------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Include dependencies */
/* ----------------------------------------------------------------------- */
#include "uima/pragmas.hpp"
#include "uima/lowlevel_typedefs.hpp"
#include "uima/macros.h"
#include <vector>
#if defined( _MSC_VER )
#pragma warning( push )
#pragma warning( disable : 4311 )
#pragma warning( disable : 4312 )
#endif
/* ----------------------------------------------------------------------- */
/* Constants */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Forward declarations */
/* ----------------------------------------------------------------------- */
namespace uima {
namespace internal {
class CASSerializer;
class CASDeserializer;
}
}
/* ----------------------------------------------------------------------- */
/* Types / Classes */
/* ----------------------------------------------------------------------- */
namespace uima {
namespace lowlevel {
namespace internal {
/**
* Generic implementation of a possibly segmented heap of cells of type T.
* Used in uima::lowlevel::FSHeap for the FS heap, the StringRef Heap,
* and the String heap. T must be an integral type.
*/
template <class T>
class UIMA_LINK_IMPORTSPEC Heap {
friend class uima::internal::CASSerializer;
friend class uima::internal::CASDeserializer;
#if defined(__GNUC__) && (__GNUC__ < 3)
//Older GNU compiler can't handle friend properly so we make public
public:
#else
private:
#endif
// start of the current heap segment
T* iv_pTHeap;
// current top of heap
T* iv_pTTopOfHeap;
// end of current allocated heap segment
T* iv_pTLastHeapCell;
// all starts of all used segments so far (most recently allocated first)
std::vector<T*> iv_vecUsedSegments;
// all ends of all used segments so far (most recently allocated first)
std::vector<T*> iv_vecUsedSegmentEnds;
// all tops of all used segments so far (most recently allocated first)
std::vector<T*> iv_vecUsedSegmentTops;
// next available cell on heap
WORD32 iv_topOfHeap;
// segment size
WORD32 iv_uiCellNumber;
// default value of the heap cells
int iv_iDefaultValue;
#ifdef BYEBYEPTRS
/**
* returns -1 if t lies in the current heap, an index >=0 into
* usedSegments, if t resides there, or -2 if t could not be found at all.
*/
int searchIndex(T* t) const {
if ( (t >= iv_pTHeap) && (t < iv_pTTopOfHeap) ) {
return -1;
}
WORD32 i;
for (i=0; i<iv_vecUsedSegments.size(); ++i) {
if ( (t>=iv_vecUsedSegments[i]) && (t< iv_vecUsedSegmentEnds[i] ) ) {
return(int) i;
}
}
return -2;
}
#endif
public:
Heap(WORD32 cells, int value)
: iv_pTHeap(NULL),
iv_pTTopOfHeap(NULL),
iv_pTLastHeapCell(NULL),
iv_uiCellNumber(cells),
iv_iDefaultValue(value) {
iv_pTHeap = new T[iv_uiCellNumber];
iv_topOfHeap = 1; // leave 0th cell empty
memset(iv_pTHeap, iv_iDefaultValue, (iv_uiCellNumber * sizeof(T)) );
}
~Heap() {
if (iv_pTHeap != NULL) {
assert( EXISTS(iv_pTHeap) );
delete[] iv_pTHeap;
}
iv_pTHeap = NULL;
}
bool debugIsValidHeapCell(TyFS cell) const {
if ( cell < 1 || cell >= iv_topOfHeap ) {
return false;
}
return true;
}
T* getHeapStart() const {
return iv_pTHeap;
}
WORD32 getTopOfHeap() const {
return iv_topOfHeap;
}
WORD32 getLastHeapCell() const {
return iv_uiCellNumber;
}
T getHeapValue(TyFS tyFS) const {
return iv_pTHeap[tyFS];
}
void setHeapValue(TyFS tyFS, T t) {
iv_pTHeap[tyFS] = t;
}
/**
* reserve n more heap cells; if necessary, increase heap size
*/
int increaseHeap(WORD32 n) {
//assert( n > 0 );
int result = iv_topOfHeap;
iv_topOfHeap += n;
// usual case, just return
if ( iv_topOfHeap < iv_uiCellNumber ) {
return result;
}
// calculate new heap size to be at least double current size
if ( n > iv_uiCellNumber ) {
iv_uiCellNumber += n;
} else {
iv_uiCellNumber *= 2;
}
T* iv_pTHeapNew = new T[iv_uiCellNumber];
assert( iv_pTHeapNew != NULL );
memcpy(iv_pTHeapNew, iv_pTHeap, result*sizeof(T));
memset(iv_pTHeapNew + result, iv_iDefaultValue, (iv_uiCellNumber - result)*sizeof(T));
delete[] iv_pTHeap;
iv_pTHeap = iv_pTHeapNew;
return result;
}
/**
* reset this heap. Paint over used cells.
*/
void reset() {
UIMA_TPRINT("resetting heap");
if ( iv_topOfHeap == 1 ) {
// nothing to be done
return;
}
// !TODO don't need to fill all heaps with default value?????
memset(iv_pTHeap, iv_iDefaultValue, iv_topOfHeap * sizeof(T) );
iv_topOfHeap = 1;
UIMA_TPRINT(" heap reset'd");
}
bool resides(TyFS t) const {
return debugIsValidHeapCell(t);
}
#ifdef BYEBYEPTRS
WORD32 getPageSize() const {
return iv_uiCellNumber;
}
WORD32 getSegmentNumber() const {
assert( iv_vecUsedSegments.size() == iv_vecUsedSegmentEnds.size() );
return iv_vecUsedSegmentEnds.size() + 1;
}
/**
* method used during serialization.
* sets the output parameter to a vector of pairs of pointers to
* the start and end, respectively, of the used heap segments
* in the order they were allocated.
*/
void getHeapSegments( vector<pair<T*, T*> >& rvecResult ) const {
assert( iv_vecUsedSegments.size() == iv_vecUsedSegmentEnds.size() );
WORD32 uiSegmentNum = iv_vecUsedSegmentEnds.size() + 1;
rvecResult.resize(uiSegmentNum);
if (uiSegmentNum == 1) {
rvecResult[0] = pair<T*, T*>(iv_pTHeap, iv_pTTopOfHeap);
return;
}
// fill result from back to front
rvecResult[uiSegmentNum-1] = pair<T*, T*>(iv_pTHeap, iv_pTTopOfHeap);
int i;
for (i=uiSegmentNum-2; i>=1; --i) {
rvecResult[i] = pair<T*, T*>(iv_vecUsedSegments[i], iv_vecUsedSegmentEnds[i]);
}
assert( i == 0 );
rvecResult[0] = pair<T*, T*>(iv_vecUsedSegments[0], iv_vecUsedSegmentEnds[0]);
}
/**
* method used during DEserialization.
* sets the output parameter to a vector of pairs of pointers to
* the start and TOP, respectively, of the used heap segments
* in the order they were allocated.
*/
void getHeapSegmentBounds( vector<pair<T*, T*> >& rvecResult ) const {
assert( iv_vecUsedSegments.size() == iv_vecUsedSegmentEnds.size() );
WORD32 uiSegmentNum = iv_vecUsedSegmentEnds.size() + 1;
rvecResult.resize(uiSegmentNum);
if (uiSegmentNum == 1) {
rvecResult[0] = pair<T*, T*>(iv_pTHeap, iv_pTLastHeapCell);
return;
}
// fill result from back to front
rvecResult[uiSegmentNum-1] = pair<T*, T*>(iv_pTHeap, iv_pTLastHeapCell);
int i;
for (i=uiSegmentNum-2; i>=1; --i) {
rvecResult[i] = pair<T*, T*>(iv_vecUsedSegments[i], iv_vecUsedSegmentTops[i]);
}
assert( i == 0 );
rvecResult[0] = pair<T*, T*>(iv_vecUsedSegments[0], iv_vecUsedSegmentTops[0]);
}
/**
* get a unique ID for a pointer into the heap.
*/
ptrdiff_t getUniqueID(T const * t) const {
if (iv_vecUsedSegmentEnds.size() == 0) {
if ( (t > iv_pTHeap) && (t < iv_pTTopOfHeap) ) {
return(t - iv_pTHeap);
}
} else {
// if in the first allocated segment
if ( (t>iv_vecUsedSegments[0]) && (t< iv_vecUsedSegmentEnds[0] ) ) {
return(t - iv_vecUsedSegments[0]);
}
// keep absolute number of heap cells
WORD32 uiAbsoluteHeapCellNum = iv_vecUsedSegmentEnds[0] - iv_vecUsedSegments[0];
WORD32 i;
WORD32 len = iv_vecUsedSegments.size();
// for each allocated heap segment
for (i=1; i<len; ++i) {
T* segmentStart = iv_vecUsedSegments[i];
T* segmentEnd = iv_vecUsedSegmentEnds[i];
if ( (t>segmentStart) && (t< segmentEnd ) ) {
return uiAbsoluteHeapCellNum - 1 + (t - segmentStart);
}
uiAbsoluteHeapCellNum += (segmentEnd - segmentStart) - 1;
}
// if in the current (most recently allocated) heap segment
if ( (t > iv_pTHeap) && (t < iv_pTTopOfHeap) ) {
return uiAbsoluteHeapCellNum + (t - iv_pTHeap) - 1;
}
}
// if we arrived here, something went wrong
assert(false);
return -1;
}
#endif
};
}
}
}
/* ----------------------------------------------------------------------- */
/* Implementation */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
#if defined( _MSC_VER )
#pragma warning( pop )
#endif
#endif