1
0
Fork 0
arangodb/lib/Basics/RandomHeap.h

321 lines
10 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief random heap
///
/// @file
/// This structure allows only conventional access to a heap (which is
/// by means of removing the head element). To use it, you must derive
/// from it and implement function "static K key(const T&)", to implement
/// random access you must derive from it and overload
/// "location"/"setLocation" accessor and implement function
/// "static K& key(T&)".
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Richard Bruch
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_BASICS_RANDOM_HEAP_H
#define ARANGODB_BASICS_RANDOM_HEAP_H 1
#include "Basics/Common.h"
#include "Basics/Exceptions.h"
namespace triagens {
namespace basics {
// -----------------------------------------------------------------------------
// --SECTION-- struct HeapTraitsBase
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief random heap traits
////////////////////////////////////////////////////////////////////////////////
template <typename T, typename K = T, typename Compare = std::less<K> >
struct HeapTraitsBase {
typedef K KeyType;
bool operator() (const K& f, const K& s) const {
return _compare(f, s);
}
static void setLocation (T&, size_t) {/* do nothing */
}
// we only access head of queue
static size_t location (const T& item) {
return 1;
}
Compare _compare;
};
// -----------------------------------------------------------------------------
// --SECTION-- struct RandomHeap
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief random heap
////////////////////////////////////////////////////////////////////////////////
template <typename T, typename TRAITS = HeapTraitsBase<T> >
struct RandomHeap {
typedef TRAITS TraitsType;
typedef typename TraitsType::KeyType K;
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
RandomHeap ()
: _bufferLen(0), _traits() {
_queue = new T[1];
_queueLen = _bufferLen = 1;
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief referesh
///
// TODO find a better name for semantics of 'preserve'
////////////////////////////////////////////////////////////////////////////////
bool refresh (T& item, const K& key, bool & preserve) {
bool changed = false, inside = TraitsType::location(item);
if (_queueLen > 1 && item == _queue[1]) {
changed = true;
}
if (inside) {
remove(item);
}
TraitsType::key(item) = key;
if (preserve) {
insert(item);
}
if (_queueLen > 1 && item == _queue[1]) {
changed = true;
}
preserve = inside;
return changed;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief compare
////////////////////////////////////////////////////////////////////////////////
bool operator() (T& f, T& s) const {
return _traits(TraitsType::key(f), TraitsType::key(s));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief head
////////////////////////////////////////////////////////////////////////////////
T& head () {
if (_queueLen == 1) {
THROW_INTERNAL_ERROR("head has size 1");
}
return _queue[1];
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove
////////////////////////////////////////////////////////////////////////////////
void remove (T& item) {
size_t i = TraitsType::location(item);
TRI_ASSERT(i < _queueLen);
TRI_ASSERT(!(*this)(_queue[i], item) && !(*this)(item, _queue[i]));
TraitsType::setLocation(item, 0);
T* iptr = _queue + i, *tail = _queue + --_queueLen;
while ((i <<= 1) < _queueLen) {
// select the smaller child of iptr and move it upheap
T* pptr = _queue + i;
if (i < _queueLen && (*this)(*(pptr + 1), *pptr)) {
pptr++, i++;
}
*iptr = *pptr;
TraitsType::setLocation(*iptr, iptr - _queue);
iptr = pptr;
}
if (tail != iptr) {
adjust(*tail, iptr - _queue);
}
*tail = T();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief insert
////////////////////////////////////////////////////////////////////////////////
void insert (T& item) {
if (_bufferLen == _queueLen) { // no place for the new element
// we use the simple doubling which should be OK in this case
T* queue = new T[_bufferLen <<= 1];for(size_t i = 1; i < _queueLen; i ++) queue[i] = _queue[i];
delete [] _queue;
_queue = queue;
}
adjust(item, _queueLen ++);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief adjust
////////////////////////////////////////////////////////////////////////////////
void adjust(T& item, int i) {
T *iptr = _queue + i;
while(i > 1) {
T* pptr = _queue + (i >>= 1);
if ((*this)(*pptr, item)) {
break;
}
*iptr = *pptr;
TraitsType::setLocation(*iptr, iptr - _queue);
iptr = pptr;
}
*iptr = item;
TraitsType::setLocation(item, iptr - _queue);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate
////////////////////////////////////////////////////////////////////////////////
void validate () {
for(size_t i = 1; i < _queueLen; i ++) {
T child = _queue[i], *former = this->former(child);
if (!former) {
continue;
}
if ((*this)(child, former)) {
TRI_ASSERT(false);
THROW_INTERNAL_ERROR("cannot validate random head");
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief former
////////////////////////////////////////////////////////////////////////////////
T former (T wt) {
size_t index = TraitsType::location(wt);
if (index > 1) {
return _queue[index >> 1];
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief empty
////////////////////////////////////////////////////////////////////////////////
bool empty () {
return _queueLen == 1;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief size
////////////////////////////////////////////////////////////////////////////////
size_t size () {
return _queueLen - 1;
}
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief queue
////////////////////////////////////////////////////////////////////////////////
T* _queue;
////////////////////////////////////////////////////////////////////////////////
/// @brief buffer length
////////////////////////////////////////////////////////////////////////////////
size_t _bufferLen;
////////////////////////////////////////////////////////////////////////////////
/// @brief queue length
////////////////////////////////////////////////////////////////////////////////
size_t _queueLen;
////////////////////////////////////////////////////////////////////////////////
/// @brief traits
////////////////////////////////////////////////////////////////////////////////
TraitsType _traits;
};
}
}
#endif
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End: