first check in seems to work
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/19/94
|
||||
//
|
||||
// $Id: ami.h,v 1.19 2003/04/17 11:59:40 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_H
|
||||
#define _AMI_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Get a stream implementation.
|
||||
#include <ami_stream.h>
|
||||
|
||||
// Get templates for ami_scan().
|
||||
#include <ami_scan.h>
|
||||
|
||||
// Get templates for ami_merge().
|
||||
#include <ami_merge.h>
|
||||
|
||||
// Get templates for ami_sort().
|
||||
#include <ami_sort.h>
|
||||
|
||||
// Get templates for general permutation.
|
||||
#include <ami_gen_perm.h>
|
||||
|
||||
// Get templates for bit permuting.
|
||||
#include <ami_bit_permute.h>
|
||||
|
||||
// Get a collection implementation.
|
||||
#include <ami_coll.h>
|
||||
|
||||
// Get a block implementation.
|
||||
#include <ami_block.h>
|
||||
|
||||
// Get templates for AMI_btree.
|
||||
#include <ami_btree.h>
|
||||
|
||||
#endif // _AMI_H
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: ami_bit_permute.cpp
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/9/95
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(ami_bit_permute_cpp,"$Id: ami_bit_permute.cpp,v 1.4 2003/04/20 06:44:01 tavi Exp $");
|
||||
|
||||
#include <ami_bit_permute.h>
|
||||
|
||||
AMI_bit_perm_object::AMI_bit_perm_object(const bit_matrix &A,
|
||||
const bit_matrix &c) :
|
||||
mA(A), mc(c)
|
||||
{
|
||||
}
|
||||
|
||||
AMI_bit_perm_object::~AMI_bit_perm_object(void)
|
||||
{
|
||||
}
|
||||
|
||||
bit_matrix AMI_bit_perm_object::A(void)
|
||||
{
|
||||
return mA;
|
||||
}
|
||||
|
||||
bit_matrix AMI_bit_perm_object::c(void)
|
||||
{
|
||||
return mc;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: ami_bit_permute.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/9/95
|
||||
//
|
||||
// $Id: ami_bit_permute.h,v 1.8 2004/08/12 12:35:29 jan Exp $
|
||||
//
|
||||
// For the moment this is done in terms of general permutations.
|
||||
// This will obviously change in the future.
|
||||
//
|
||||
#ifndef _AMI_BIT_PERMUTE_H
|
||||
#define _AMI_BIT_PERMUTE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Get bit_matrix.
|
||||
#include <bit_matrix.h>
|
||||
|
||||
// Get AMI_gen_perm_object.
|
||||
#include <ami_gen_perm_object.h>
|
||||
// Get the AMI_general_permute().
|
||||
#include <ami_gen_perm.h>
|
||||
|
||||
class AMI_bit_perm_object {
|
||||
private:
|
||||
// The matrices that define the permutation.
|
||||
bit_matrix mA;
|
||||
bit_matrix mc;
|
||||
public:
|
||||
AMI_bit_perm_object(const bit_matrix &A,
|
||||
const bit_matrix &c);
|
||||
~AMI_bit_perm_object(void);
|
||||
|
||||
bit_matrix A(void);
|
||||
bit_matrix c(void);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class bmmc_as_gen_po : public AMI_gen_perm_object {
|
||||
private:
|
||||
bit_matrix *src_bits;
|
||||
bit_matrix A;
|
||||
bit_matrix c;
|
||||
public:
|
||||
bmmc_as_gen_po(AMI_bit_perm_object &bpo) :
|
||||
A(bpo.A()), c(bpo.c())
|
||||
{
|
||||
tp_assert(A.rows() == A.cols(), "A is not square.");
|
||||
tp_assert(c.cols() == 1, "c is not a column vector.");
|
||||
tp_assert(c.rows() == A.cols(), "A and c dimensions do not match.");
|
||||
src_bits = new bit_matrix(c.rows(),1);
|
||||
};
|
||||
|
||||
AMI_err initialize(TPIE_OS_OFFSET /*stream_len*/) {
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TPIE_OS_OFFSET destination(TPIE_OS_OFFSET input_offset) {
|
||||
|
||||
*src_bits = input_offset;
|
||||
|
||||
bit_matrix r1 = A * *src_bits;
|
||||
bit_matrix res = r1 + c;
|
||||
|
||||
return TPIE_OS_OFFSET(res);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef TPIE_LIBRARY
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_BMMC_permute(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream,
|
||||
AMI_bit_perm_object *bpo)
|
||||
{
|
||||
TPIE_OS_OFFSET sz_len = instream->stream_len();
|
||||
|
||||
TPIE_OS_OFFSET sz_pow2;
|
||||
unsigned int bits;
|
||||
|
||||
// Make sure the length of the input stream is a power of two.
|
||||
|
||||
for (sz_pow2 = 1, bits = 0; sz_pow2 < sz_len; sz_pow2 += sz_pow2) {
|
||||
bits++;
|
||||
}
|
||||
|
||||
if (sz_pow2 != sz_len) {
|
||||
return AMI_ERROR_NOT_POWER_OF_2;
|
||||
}
|
||||
|
||||
// Make sure the number of bits in the permutation matrix matches
|
||||
// the log of the number of items in the input stream.
|
||||
|
||||
{
|
||||
bit_matrix A = bpo->A();
|
||||
bit_matrix c = bpo->c();
|
||||
|
||||
if (A.rows() != bits) {
|
||||
return AMI_ERROR_BIT_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
if (A.cols() != bits) {
|
||||
return AMI_ERROR_BIT_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
if (c.rows() != bits) {
|
||||
return AMI_ERROR_BIT_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
if (c.cols() != 1) {
|
||||
return AMI_ERROR_BIT_MATRIX_BOUNDS;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the general permutation object.
|
||||
bmmc_as_gen_po<T> gpo(*bpo);
|
||||
|
||||
// Do the permutation.
|
||||
return AMI_general_permute(instream, outstream,
|
||||
(AMI_gen_perm_object *)&gpo);
|
||||
}
|
||||
|
||||
#endif // ndef TPIE_LIBRARY
|
||||
|
||||
#endif // _AMI_BIT_PERMUTE_H
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_block.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// Definition and implementation of the AMI_block class.
|
||||
//
|
||||
// $Id: ami_block.h,v 1.9 2005/01/21 17:29:26 tavi Exp $
|
||||
//
|
||||
|
||||
#ifndef _AMI_BLOCK_H
|
||||
#define _AMI_BLOCK_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// The AMI_block_base class.
|
||||
#include <ami_block_base.h>
|
||||
|
||||
// The b_vector class.
|
||||
#include <b_vector.h>
|
||||
|
||||
template<class E, class I, class BTECOLL = BTE_COLLECTION >
|
||||
class AMI_block: public AMI_block_base<BTECOLL> {
|
||||
protected:
|
||||
using AMI_block_base<BTECOLL>::bid_;
|
||||
using AMI_block_base<BTECOLL>::dirty_;
|
||||
using AMI_block_base<BTECOLL>::pdata_;
|
||||
using AMI_block_base<BTECOLL>::per_;
|
||||
using AMI_block_base<BTECOLL>::pcoll_;
|
||||
|
||||
public:
|
||||
using AMI_block_base<BTECOLL>::bid;
|
||||
|
||||
// typedef typename BTECOLL::block_id_t id_t;
|
||||
|
||||
// The array of links.
|
||||
b_vector<AMI_bid> lk;
|
||||
|
||||
// The array of elements.
|
||||
b_vector<E> el;
|
||||
|
||||
typedef typename b_vector<AMI_bid>::iterator lk_iterator;
|
||||
typedef typename b_vector<E>::iterator el_iterator;
|
||||
|
||||
public:
|
||||
// Compute the capacity of the el vector statically (but you have to
|
||||
// give the correct block size and number of links!). It can also be
|
||||
// used to figure out how many elements would fit into a block with
|
||||
// a given size and a given number of links.
|
||||
static size_t el_capacity(size_t block_size, size_t links);
|
||||
|
||||
// Constructor. Read and initialize a block with a given ID. If the
|
||||
// ID is missing or 0, a new block is created.
|
||||
AMI_block(AMI_collection_single<BTECOLL>* pacoll, size_t links, AMI_bid bid = 0);
|
||||
|
||||
// Get a reference to the info field.
|
||||
I* info();
|
||||
const I* info() const;
|
||||
};
|
||||
|
||||
|
||||
////////// ***Implementation*** ///////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
////////// **AMI_block** ///////////
|
||||
////////////////////////////////////
|
||||
|
||||
template<class E, class I, class BTECOLL>
|
||||
size_t AMI_block<E,I,BTECOLL>::el_capacity(size_t block_size, size_t links) {
|
||||
return (size_t) ((block_size - sizeof(I) - links * sizeof(AMI_bid)) / sizeof(E));
|
||||
}
|
||||
|
||||
template<class E, class I, class BTECOLL>
|
||||
AMI_block<E,I,BTECOLL>::AMI_block(AMI_collection_single<BTECOLL>* pacoll,
|
||||
size_t links, AMI_bid _bid):
|
||||
AMI_block_base<BTECOLL>(pacoll, _bid),
|
||||
lk((AMI_bid*)pdata_, links),
|
||||
el((E*) ((char*) pdata_ + links * sizeof(AMI_bid)),
|
||||
el_capacity(pcoll_->block_size(), links))
|
||||
{
|
||||
}
|
||||
|
||||
template<class E, class I, class BTECOLL>
|
||||
I* AMI_block<E,I,BTECOLL>::info() {
|
||||
return (I*) (((char*) pdata_ + (lk.capacity()*sizeof(AMI_bid) +
|
||||
el.capacity()*sizeof(E))));
|
||||
}
|
||||
|
||||
template<class E, class I, class BTECOLL>
|
||||
const I* AMI_block<E,I,BTECOLL>::info() const {
|
||||
return (I*) (((char*) pdata_ + (lk.capacity()*sizeof(AMI_bid) +
|
||||
el.capacity()*sizeof(E))));
|
||||
}
|
||||
|
||||
#endif // _AMI_BLOCK_H
|
||||
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_block_base.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_block_base.h,v 1.14 2004/08/17 16:47:38 jan Exp $
|
||||
//
|
||||
// Definition of the AMI_block_base class and supporting types:
|
||||
// AMI_bid, AMI_block_status.
|
||||
//
|
||||
|
||||
#ifndef _AMI_BLOCK_BASE_H
|
||||
#define _AMI_BLOCK_BASE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// The AMI error codes.
|
||||
#include <ami_err.h>
|
||||
// The AMI_COLLECTION class.
|
||||
#include <ami_coll.h>
|
||||
|
||||
// AMI block id type.
|
||||
typedef TPIE_BLOCK_ID_TYPE AMI_bid;
|
||||
|
||||
// Block status type.
|
||||
enum AMI_block_status {
|
||||
AMI_BLOCK_STATUS_VALID = 0,
|
||||
AMI_BLOCK_STATUS_INVALID = 1
|
||||
};
|
||||
|
||||
|
||||
template<class BTECOLL>
|
||||
class AMI_block_base {
|
||||
public:
|
||||
// typedef typename BTECOLL::block_id_t id_t;
|
||||
|
||||
protected:
|
||||
|
||||
// Pointer to the block collection.
|
||||
BTECOLL * pcoll_;
|
||||
|
||||
// Unique ID. Represents the offset of the block in the blocks file.
|
||||
AMI_bid bid_;
|
||||
|
||||
// Dirty bit. If set, the block needs to be written back.
|
||||
char dirty_;
|
||||
|
||||
// Pointer to the actual data.
|
||||
void * pdata_;
|
||||
|
||||
// Persistence flag.
|
||||
persistence per_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor.
|
||||
// Read and initialize a block with a given ID.
|
||||
// When bid is missing or 0, a new block is created.
|
||||
AMI_block_base(AMI_collection_single<BTECOLL>* pacoll, AMI_bid bid = 0)
|
||||
: bid_(bid), dirty_(0), per_(PERSIST_PERSISTENT) {
|
||||
pcoll_ = pacoll->bte();
|
||||
if (bid != 0) {
|
||||
// Get an existing block from disk.
|
||||
if (pcoll_->get_block(bid_, pdata_) != BTE_ERROR_NO_ERROR)
|
||||
pdata_ = NULL;
|
||||
} else {
|
||||
// Create a new block in the collection.
|
||||
if (pcoll_->new_block(bid_, pdata_) != BTE_ERROR_NO_ERROR)
|
||||
pdata_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
AMI_err sync() {
|
||||
if (pcoll_->sync_block(bid_, pdata_) != BTE_ERROR_NO_ERROR)
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
else
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Get the block id.
|
||||
AMI_bid bid() const { return bid_; }
|
||||
|
||||
// Get a reference to the dirty bit.
|
||||
char& dirty() { return dirty_; };
|
||||
char dirty() const { return dirty_; }
|
||||
|
||||
// Copy block rhs into this block.
|
||||
AMI_block_base<BTECOLL>& operator=(const AMI_block_base<BTECOLL>& rhs) {
|
||||
if (pcoll_ == rhs.pcoll_) {
|
||||
memcpy(pdata_, rhs.pdata_, pcoll_->block_size());
|
||||
dirty_ = 1;
|
||||
} else
|
||||
pdata_ = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Get the block's status.
|
||||
AMI_block_status status() const {
|
||||
return (pdata_ == NULL) ?
|
||||
AMI_BLOCK_STATUS_INVALID: AMI_BLOCK_STATUS_VALID;
|
||||
}
|
||||
|
||||
// Return true if the block is valid.
|
||||
bool is_valid() const {
|
||||
return (pdata_ != NULL);
|
||||
}
|
||||
|
||||
// Return true if the block is invalid.
|
||||
bool operator!() const {
|
||||
return (pdata_ == NULL);
|
||||
}
|
||||
|
||||
void persist(persistence per) { per_ = per; }
|
||||
|
||||
persistence persist() const { return per_; }
|
||||
|
||||
size_t block_size() const { return pcoll_->block_size(); }
|
||||
|
||||
// Destructor.
|
||||
~AMI_block_base() {
|
||||
// Check first the status of the collection.
|
||||
if (pdata_ != NULL){
|
||||
if (per_ == PERSIST_PERSISTENT) {
|
||||
// Write back the block.
|
||||
pcoll_->put_block(bid_, pdata_);
|
||||
} else {
|
||||
// Delete the block from the collection.
|
||||
pcoll_->delete_block(bid_, pdata_);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //_AMI_BLOCK_BASE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,238 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_cache.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_cache.h,v 1.10 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
// Declaration and definition of AMI_CACHE_MANAGER
|
||||
// implementation(s).
|
||||
//
|
||||
|
||||
#ifndef _AMI_CACHE_H
|
||||
#define _AMI_CACHE_H
|
||||
|
||||
// Get the STL pair class.
|
||||
#include <utility>
|
||||
// Get the logging macros.
|
||||
#include <tpie_log.h>
|
||||
// Get the b_vector class.
|
||||
#include <b_vector.h>
|
||||
|
||||
// The only implementation is AMI_cache_manager_lru.
|
||||
#define AMI_CACHE_MANAGER AMI_cache_manager_lru
|
||||
|
||||
// Base class for all implementations.
|
||||
class AMI_cache_manager_base {
|
||||
protected:
|
||||
|
||||
// Max size.
|
||||
TPIE_OS_SIZE_T capacity_;
|
||||
|
||||
// Associativity.
|
||||
TPIE_OS_SIZE_T assoc_;
|
||||
|
||||
// Behavior.
|
||||
int behavior_;
|
||||
|
||||
// Constructor. Protected to prevent instantiation of this class.
|
||||
AMI_cache_manager_base(TPIE_OS_SIZE_T capacity, TPIE_OS_SIZE_T assoc):
|
||||
capacity_(capacity), assoc_(assoc), behavior_(0) {}
|
||||
|
||||
public:
|
||||
// Set behavior. TODO: Expand.
|
||||
int behavior(int b) { behavior_ = b; return behavior_; }
|
||||
// Inquire behavior.
|
||||
int behavior() const { return behavior_; }
|
||||
};
|
||||
|
||||
// Implementation using an LRU replacement policy.
|
||||
template<class T, class W>
|
||||
class AMI_cache_manager_lru: public AMI_cache_manager_base {
|
||||
protected:
|
||||
|
||||
typedef pair<TPIE_OS_OFFSET,T> item_type_;
|
||||
|
||||
// The array of items.
|
||||
item_type_ * pdata_;
|
||||
|
||||
// The number of sets (equals capacity / associativity).
|
||||
TPIE_OS_SIZE_T sets_;
|
||||
|
||||
// The writeout function object.
|
||||
W writeout_;
|
||||
|
||||
public:
|
||||
|
||||
AMI_cache_manager_lru(TPIE_OS_SIZE_T capacity, TPIE_OS_SIZE_T assoc = 0);
|
||||
|
||||
// Read an item from the cache based on the key k. The item is
|
||||
// passed to the user and *removed* from the cache (but not written
|
||||
// out).
|
||||
bool read(TPIE_OS_OFFSET k, T& item);
|
||||
|
||||
// Write an item to the cache based on the key k. If the set where
|
||||
// the item should go is full, the last item (ie, the l.r.u. item)
|
||||
// is written out.
|
||||
bool write(TPIE_OS_OFFSET k, const T& item);
|
||||
|
||||
// Erase an item from the cache based on the key k. The item is
|
||||
// written out first.
|
||||
bool erase(TPIE_OS_OFFSET k);
|
||||
|
||||
// Write out all items in the cache.
|
||||
void flush();
|
||||
|
||||
~AMI_cache_manager_lru();
|
||||
};
|
||||
|
||||
template<class T, class W>
|
||||
AMI_cache_manager_lru<T,W>::AMI_cache_manager_lru(size_t capacity, size_t assoc):
|
||||
AMI_cache_manager_base(capacity, assoc == 0 ? capacity: assoc), writeout_() {
|
||||
|
||||
size_t i;
|
||||
|
||||
if (capacity_ != 0) {
|
||||
if (assoc_ > capacity_) {
|
||||
TP_LOG_WARNING_ID("Associativity too big.");
|
||||
TP_LOG_WARNING_ID("Associativity reduced to capacity.");
|
||||
assoc_ = capacity_;
|
||||
}
|
||||
|
||||
if (capacity_ % assoc_ != 0) {
|
||||
TP_LOG_WARNING_ID("Capacity is not multiple of associativity.");
|
||||
TP_LOG_WARNING_ID("Capacity reduced.");
|
||||
capacity_ = (capacity_ / assoc_) * assoc_;
|
||||
}
|
||||
|
||||
// The number of cache lines.
|
||||
sets_ = capacity_ / assoc_;
|
||||
|
||||
// Initialize the array (mark all positions empty).
|
||||
pdata_ = new item_type_[capacity_];
|
||||
for (i = 0; i < capacity_; i++) {
|
||||
pdata_[i].first = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
pdata_ = NULL;
|
||||
sets_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class W>
|
||||
inline bool AMI_cache_manager_lru<T,W>::read(TPIE_OS_OFFSET k, T& item) {
|
||||
|
||||
TPIE_OS_SIZE_T i;
|
||||
if (capacity_ == 0)
|
||||
return false;
|
||||
|
||||
assert(k != 0);
|
||||
|
||||
// The cache line, based on the key k.
|
||||
b_vector<item_type_> set(&pdata_[(k % sets_) * assoc_], assoc_);
|
||||
|
||||
// Find the item using the key.
|
||||
for (i = 0; i < assoc_; i++) {
|
||||
if (set[i].first == k)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == assoc_)
|
||||
return false;
|
||||
|
||||
// memcpy(&item, &set[i].second, sizeof(T));
|
||||
item = set[i].second;
|
||||
|
||||
// Erase the item from the cache.
|
||||
// NB: We don't write it out because we pass it up to the user.
|
||||
if (assoc_ > 1)
|
||||
set.erase(i);
|
||||
|
||||
// Mark the last item empty.
|
||||
set[assoc_ - 1].first = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class W>
|
||||
inline bool AMI_cache_manager_lru<T,W>::write(TPIE_OS_OFFSET k, const T& item) {
|
||||
|
||||
assert(k != 0);
|
||||
|
||||
if (capacity_ == 0) {
|
||||
|
||||
writeout_(item);
|
||||
|
||||
} else {
|
||||
|
||||
// The cache line, based on the key k.
|
||||
b_vector<item_type_> set(&pdata_[(k % sets_) * assoc_], assoc_);
|
||||
|
||||
// Write out the item in the last position.
|
||||
if (set[assoc_ - 1].first != 0) {
|
||||
writeout_(set[assoc_ - 1].second);
|
||||
}
|
||||
|
||||
// Insert in the first position.
|
||||
if (assoc_ > 1)
|
||||
set.insert(item_type_(k, item), 0);
|
||||
else {
|
||||
set[0] = item_type_(k, item);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class W>
|
||||
bool AMI_cache_manager_lru<T,W>::erase(TPIE_OS_OFFSET k) {
|
||||
|
||||
TPIE_OS_SIZE_T i;
|
||||
assert(k != 0);
|
||||
|
||||
// The cache line, based on the key k.
|
||||
b_vector<item_type_> set(&pdata_[(k % sets_) * assoc_], assoc_);
|
||||
|
||||
// Find the item using the key.
|
||||
for (i = 0; i < set.capacity(); i++) {
|
||||
if (set[i].first == k)
|
||||
break;
|
||||
}
|
||||
|
||||
// If not found, return false.
|
||||
if (i == set.capacity())
|
||||
return false;
|
||||
|
||||
// Write out the item in position i;
|
||||
writeout_(set[i].second);
|
||||
|
||||
// Erase the item from the cache.
|
||||
set.erase(i);
|
||||
|
||||
// Mark last item in the set as empty.
|
||||
set[set.capacity() - 1].first = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T, class W>
|
||||
void AMI_cache_manager_lru<T,W>::flush() {
|
||||
TPIE_OS_SIZE_T i;
|
||||
for (i = 0; i < capacity_; i++) {
|
||||
if (pdata_[i].first != 0) {
|
||||
writeout_(pdata_[i].second);
|
||||
pdata_[i].first = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class W>
|
||||
AMI_cache_manager_lru<T,W>::~AMI_cache_manager_lru() {
|
||||
flush();
|
||||
if (capacity_ > 0) {
|
||||
delete [] pdata_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _AMI_CACHE_H
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// File: ami_coll.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_coll.h,v 1.8 2003/05/08 22:12:21 tavi Exp $
|
||||
//
|
||||
// Front end for the AMI_COLLECTION implementations.
|
||||
//
|
||||
#ifndef _AMI_COLL_H
|
||||
#define _AMI_COLL_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <ami_coll_base.h>
|
||||
#include <ami_coll_single.h>
|
||||
|
||||
// AMI_collection_single is the only implementation, so make it easy
|
||||
// to get to.
|
||||
|
||||
#define AMI_collection AMI_collection_single
|
||||
|
||||
#ifdef BTE_COLLECTION
|
||||
# define AMI_COLLECTION AMI_collection_single< BTE_COLLECTION >
|
||||
#endif
|
||||
|
||||
#endif // _AMI_COLL_H
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_coll_base.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_coll_base.h,v 1.4 2004/08/17 16:47:45 jan Exp $
|
||||
//
|
||||
// Basic definitions for all AMI_COLLECTION implementations.
|
||||
//
|
||||
#ifndef _AMI_COLL_BASE_H
|
||||
#define _AMI_COLL_BASE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// AMI collection types passed to constructors
|
||||
enum AMI_collection_type {
|
||||
AMI_READ_COLLECTION = 1, // Open existing collection for reading
|
||||
AMI_WRITE_COLLECTION, // Open for writing. Create if non-existent
|
||||
AMI_READ_WRITE_COLLECTION // Open to read and write.
|
||||
};
|
||||
|
||||
// AMI collection status.
|
||||
enum AMI_collection_status {
|
||||
AMI_COLLECTION_STATUS_VALID = 0,
|
||||
AMI_COLLECTION_STATUS_INVALID = 1
|
||||
};
|
||||
|
||||
#endif // _AMI_COLL_BASE_H
|
||||
@@ -0,0 +1,117 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_coll_single.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_coll_single.h,v 1.14 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
// AMI collection entry points implemented on top of a single BTE.
|
||||
//
|
||||
#ifndef _AMI_COLL_SINGLE_H
|
||||
#define _AMI_COLL_SINGLE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// For persist type.
|
||||
#include <persist.h>
|
||||
// Get an appropriate BTE collection.
|
||||
#include <bte_coll.h>
|
||||
// For AMI_collection_type and AMI_collection_status.
|
||||
#include <ami_coll_base.h>
|
||||
// The tpie_tempnam() function.
|
||||
#include <tpie_tempnam.h>
|
||||
// Get the tpie_stats_coll class for collection statistics.
|
||||
#include <tpie_stats_coll.h>
|
||||
|
||||
template < class BTECOLL = BTE_COLLECTION >
|
||||
class AMI_collection_single {
|
||||
public:
|
||||
|
||||
// Initialize a temporary collection.
|
||||
AMI_collection_single(TPIE_OS_SIZE_T logical_block_factor = 1);
|
||||
|
||||
// Initialize a named collection.
|
||||
AMI_collection_single(char* path_name,
|
||||
AMI_collection_type ct = AMI_READ_WRITE_COLLECTION,
|
||||
TPIE_OS_SIZE_T logical_block_factor = 1);
|
||||
|
||||
// Return the total number of used blocks.
|
||||
TPIE_OS_OFFSET size() const { return btec_->size(); }
|
||||
|
||||
// Return the logical block size in bytes.
|
||||
TPIE_OS_SIZE_T block_size() const { return btec_->block_size(); }
|
||||
|
||||
// Return the logical block factor.
|
||||
TPIE_OS_SIZE_T block_factor() const { return btec_->block_factor(); }
|
||||
|
||||
// Set the persistence flag.
|
||||
void persist(persistence p) { btec_->persist(p); }
|
||||
|
||||
// Inquire the persistence status.
|
||||
persistence persist() const { return btec_->persist(); }
|
||||
|
||||
// Inquire the status.
|
||||
AMI_collection_status status() const { return status_; }
|
||||
bool is_valid() const { return status_ == AMI_COLLECTION_STATUS_VALID; }
|
||||
bool operator!() const { return !is_valid(); }
|
||||
|
||||
// User data to be stored in the header.
|
||||
void *user_data() { return btec_->user_data(); }
|
||||
|
||||
// Destructor.
|
||||
~AMI_collection_single() { delete btec_; }
|
||||
|
||||
BTECOLL* bte() { return btec_; }
|
||||
|
||||
const tpie_stats_collection& stats() const { return btec_->stats(); }
|
||||
|
||||
static const tpie_stats_collection& gstats()
|
||||
{ return BTECOLL::gstats(); }
|
||||
|
||||
private:
|
||||
|
||||
BTECOLL *btec_;
|
||||
AMI_collection_status status_;
|
||||
|
||||
// Allow AMI_block base direct access to the BTE_COLLECTION.
|
||||
// friend class AMI_block_base;
|
||||
};
|
||||
|
||||
template <class BTECOLL>
|
||||
AMI_collection_single<BTECOLL>::AMI_collection_single(TPIE_OS_SIZE_T lbf) {
|
||||
|
||||
char *temp_path = tpie_tempnam("AMI");
|
||||
|
||||
btec_ = new BTECOLL(temp_path, BTE_WRITE_COLLECTION, lbf);
|
||||
tp_assert(btec_ != NULL, "new failed to create a new BTE_COLLECTION.");
|
||||
btec_->persist(PERSIST_DELETE);
|
||||
|
||||
if (btec_->status() == BTE_COLLECTION_STATUS_VALID)
|
||||
status_ = AMI_COLLECTION_STATUS_VALID;
|
||||
else
|
||||
status_ = AMI_COLLECTION_STATUS_INVALID;
|
||||
}
|
||||
|
||||
template <class BTECOLL>
|
||||
AMI_collection_single<BTECOLL>::AMI_collection_single(char* path_name,
|
||||
AMI_collection_type ct, TPIE_OS_SIZE_T lbf) {
|
||||
|
||||
BTE_collection_type btect;
|
||||
|
||||
if (ct == AMI_READ_COLLECTION)
|
||||
btect = BTE_READ_COLLECTION;
|
||||
else
|
||||
btect = BTE_WRITE_COLLECTION;
|
||||
|
||||
btec_ = new BTECOLL(path_name, btect, lbf);
|
||||
tp_assert(btec_ != NULL, "new failed to create a new BTE_COLLECTION.");
|
||||
btec_->persist(PERSIST_PERSISTENT);
|
||||
|
||||
if (btec_->status() == BTE_COLLECTION_STATUS_VALID)
|
||||
status_ = AMI_COLLECTION_STATUS_VALID;
|
||||
else
|
||||
status_ = AMI_COLLECTION_STATUS_INVALID;
|
||||
}
|
||||
|
||||
#endif // _AMI_COLL_SINGLE_H
|
||||
@@ -0,0 +1,146 @@
|
||||
//
|
||||
// File: ami_device.cpp
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 8/22/93
|
||||
//
|
||||
|
||||
#include "versions.h"
|
||||
VERSION(ami_device_cpp,"$Id: ami_device.cpp,v 1.14 2004/08/12 12:53:42 jan Exp $");
|
||||
|
||||
#include "lib_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ami_err.h>
|
||||
#include <ami_device.h>
|
||||
|
||||
|
||||
AMI_device::AMI_device(void)
|
||||
{
|
||||
TP_LOG_DEBUG_ID("In AMI_device(void).");
|
||||
}
|
||||
|
||||
|
||||
AMI_device::AMI_device(unsigned int count, char **strings)
|
||||
{
|
||||
char *s, *t;
|
||||
|
||||
argc = count;
|
||||
if (argc) {
|
||||
argv = new char*[argc];
|
||||
|
||||
while (count--) {
|
||||
argv[count] = new char[strlen(strings[count]) + 1];
|
||||
// for (s = strings[count], t = argv[count]; *t++ = *s++; )
|
||||
// [tavi] modified to avoid warning.
|
||||
for (s = strings[count], t = argv[count]; *t; *t++ = *s++)
|
||||
;
|
||||
}
|
||||
|
||||
} else {
|
||||
argv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AMI_device::~AMI_device(void)
|
||||
{
|
||||
dispose_contents();
|
||||
}
|
||||
|
||||
|
||||
const char * AMI_device::operator[](unsigned int index)
|
||||
{
|
||||
return argv[index];
|
||||
}
|
||||
|
||||
unsigned int AMI_device::arity()
|
||||
{
|
||||
return argc;
|
||||
}
|
||||
|
||||
void AMI_device::dispose_contents(void)
|
||||
{
|
||||
if (argc) {
|
||||
while (argc--) {
|
||||
delete argv[argc];
|
||||
}
|
||||
|
||||
tp_assert((argv != NULL), "Nonzero argc and NULL argv.");
|
||||
|
||||
delete argv;
|
||||
}
|
||||
}
|
||||
|
||||
AMI_err AMI_device::set_to_path(const char *path)
|
||||
{
|
||||
const char *s, *t;
|
||||
unsigned int ii;
|
||||
|
||||
dispose_contents();
|
||||
|
||||
// Count the components
|
||||
for (argc = 1, s = path; *s; s++) {
|
||||
if (*s == '|') {
|
||||
argc++;
|
||||
}
|
||||
}
|
||||
|
||||
argv = new char*[argc];
|
||||
|
||||
// copy the components one by one. t points to the start of the
|
||||
// current component and s is used to scan to the end of it.
|
||||
|
||||
for (ii = 0, s = t = path; ii < argc; ii++, t = ++s) {
|
||||
// Move past the current component.
|
||||
while (*s && (*s != '|'))
|
||||
s++;
|
||||
|
||||
tp_assert(((*s == '|') || (ii == argc - 1)),
|
||||
"Path ended before all components found.");
|
||||
|
||||
// Copy the current component.
|
||||
argv[ii] = new char[s - t + 1];
|
||||
strncpy(argv[ii], t, s - t);
|
||||
argv[ii][s - t] = '\0';
|
||||
|
||||
// make sure there is no trailing /
|
||||
for(TPIE_OS_LONGLONG i=s-t-1; i && (argv[ii][i]) == '/'; i--) {
|
||||
argv[ii][i] = '\0';
|
||||
}
|
||||
tp_assert(strlen(argv[ii]) > 0, "non-null path specified");
|
||||
tp_assert(strlen(argv[ii]) == 1 ||
|
||||
argv[ii][strlen(argv[ii])] != '/', "no / suffix");
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
AMI_err AMI_device::read_environment(const char *name)
|
||||
{
|
||||
char *env_value = getenv(name);
|
||||
|
||||
if (env_value == NULL) {
|
||||
return AMI_ERROR_ENV_UNDEFINED;
|
||||
}
|
||||
|
||||
return set_to_path(env_value);
|
||||
}
|
||||
|
||||
|
||||
// Output of a device description:
|
||||
ostream &operator<<(ostream &os, const AMI_device &dev)
|
||||
{
|
||||
unsigned int ii;
|
||||
|
||||
for (ii = 0; ii < dev.argc; ii++) {
|
||||
os << dev.argv[ii];
|
||||
if (ii < dev.argc - 1) {
|
||||
os << '|';
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 1993 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_device.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 8/22/93
|
||||
//
|
||||
// $Id: ami_device.h,v 1.4 2003/09/12 01:44:29 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_DEVICE_H
|
||||
#define _AMI_DEVICE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class AMI_device {
|
||||
friend ostream &operator<<(ostream &os, const AMI_device &dev);
|
||||
private:
|
||||
void dispose_contents(void);
|
||||
protected:
|
||||
unsigned int argc;
|
||||
char **argv;
|
||||
public:
|
||||
AMI_device(void);
|
||||
AMI_device(unsigned int count, char **strings);
|
||||
~AMI_device(void);
|
||||
AMI_err set_to_path(const char *path);
|
||||
AMI_err read_environment(const char *name);
|
||||
const char * operator[](unsigned int index);
|
||||
unsigned int arity(void);
|
||||
};
|
||||
|
||||
// Output operator
|
||||
ostream &operator<<(ostream &os, const AMI_device &dev);
|
||||
|
||||
#endif // _AMI_DEVICE_H
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// File: ami_err.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// (from Darren's ami_base.h)
|
||||
// Created: 12/29/01
|
||||
// $Id: ami_err.h,v 1.4 2005/07/07 20:38:39 adanner Exp $
|
||||
//
|
||||
// AMI error codes, moved here from ami_base.h
|
||||
//
|
||||
|
||||
#ifndef _AMI_ERR_H
|
||||
#define _AMI_ERR_H
|
||||
|
||||
// AMI error codes are returned using the AMI_err type.
|
||||
enum AMI_err {
|
||||
AMI_ERROR_NO_ERROR = 0,
|
||||
AMI_ERROR_IO_ERROR,
|
||||
AMI_ERROR_END_OF_STREAM,
|
||||
AMI_ERROR_READ_ONLY,
|
||||
AMI_ERROR_OS_ERROR,
|
||||
AMI_ERROR_BASE_METHOD,
|
||||
AMI_ERROR_BTE_ERROR,
|
||||
AMI_ERROR_MM_ERROR,
|
||||
AMI_ERROR_OBJECT_INITIALIZATION,
|
||||
AMI_ERROR_OBJECT_INVALID,
|
||||
AMI_ERROR_PERMISSION_DENIED,
|
||||
AMI_ERROR_INSUFFICIENT_MAIN_MEMORY,
|
||||
AMI_ERROR_INSUFFICIENT_AVAILABLE_STREAMS,
|
||||
AMI_ERROR_ENV_UNDEFINED,
|
||||
AMI_ERROR_NO_MAIN_MEMORY_OPERATION,
|
||||
AMI_ERROR_BIT_MATRIX_BOUNDS,
|
||||
AMI_ERROR_NOT_POWER_OF_2,
|
||||
AMI_ERROR_NULL_POINTER,
|
||||
|
||||
AMI_ERROR_GENERIC_ERROR = 0xfff,
|
||||
|
||||
// Values returned by scan objects.
|
||||
AMI_SCAN_DONE = 0x1000,
|
||||
AMI_SCAN_CONTINUE,
|
||||
|
||||
// Values returned by merge objects.
|
||||
AMI_MERGE_DONE = 0x2000,
|
||||
AMI_MERGE_CONTINUE,
|
||||
AMI_MERGE_OUTPUT,
|
||||
AMI_MERGE_READ_MULTIPLE,
|
||||
|
||||
// Matrix related errors
|
||||
AMI_MATRIX_BOUNDS = 0x3000,
|
||||
|
||||
// Values returned by sort routines.
|
||||
AMI_SORT_ALREADY_SORTED = 0x4000
|
||||
|
||||
};
|
||||
|
||||
#endif // _AMI_ERR_H
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_gen_perm.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 11/1/94
|
||||
//
|
||||
// $Id: ami_gen_perm.h,v 1.14 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
// General permutation.
|
||||
//
|
||||
#ifndef _AMI_GEN_PERM_H
|
||||
#define _AMI_GEN_PERM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get AMI_scan_object.
|
||||
#include <ami_scan.h>
|
||||
// Get AMI_sort
|
||||
#include <ami_sort.h>
|
||||
|
||||
#include <ami_gen_perm_object.h>
|
||||
|
||||
// (tavi) moved dest_obj definition down due to error in gcc 2.8.1
|
||||
template<class T> class dest_obj;
|
||||
|
||||
// A comparison operator that simply compares destinations (for sorting).
|
||||
template<class T>
|
||||
int operator<(const dest_obj<T> &s, const dest_obj<T> &t)
|
||||
{
|
||||
return s.dest < t.dest;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int operator>(const dest_obj<T> &s, const dest_obj<T> &t)
|
||||
{
|
||||
return s.dest > t.dest;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
class gen_perm_add_dest : AMI_scan_object {
|
||||
private:
|
||||
AMI_gen_perm_object *pgp;
|
||||
off_t input_offset;
|
||||
public:
|
||||
gen_perm_add_dest(AMI_gen_perm_object *gpo) : pgp(gpo) {};
|
||||
virtual ~gen_perm_add_dest(void) {};
|
||||
AMI_err initialize(void) { input_offset = 0; return AMI_ERROR_NO_ERROR; };
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin, dest_obj<T> *out,
|
||||
AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
if (!(*sfout = *sfin)) {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
*out = dest_obj<T>(in, pgp->destination(input_offset++));
|
||||
return AMI_SCAN_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
class gen_perm_strip_dest : AMI_scan_object {
|
||||
public:
|
||||
AMI_err initialize(void) { return AMI_ERROR_NO_ERROR; };
|
||||
AMI_err operate(const dest_obj<T> &in, AMI_SCAN_FLAG *sfin, T *out,
|
||||
AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
if (!(*sfout = *sfin)) {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
*out = in.t;
|
||||
return AMI_SCAN_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
class dest_obj {
|
||||
private:
|
||||
T t;
|
||||
TPIE_OS_OFFSET dest;
|
||||
public:
|
||||
dest_obj(void) {};
|
||||
dest_obj(T t_in, TPIE_OS_OFFSET d) : t(t_in), dest(d) {};
|
||||
~dest_obj(void) {};
|
||||
|
||||
// The second alternative caused problems on Win32 (jv)
|
||||
//#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
|
||||
friend int operator< <> (const dest_obj<T> &s, const dest_obj<T> &t);
|
||||
friend int operator> <> (const dest_obj<T> &s, const dest_obj<T> &t);
|
||||
//#else
|
||||
// friend int operator< (const dest_obj<T> &s, const dest_obj<T> &t);
|
||||
// friend int operator> (const dest_obj<T> &s, const dest_obj<T> &t);
|
||||
//#endif
|
||||
friend AMI_err gen_perm_strip_dest<T>::operate(const dest_obj<T> &in,
|
||||
AMI_SCAN_FLAG *sfin, T *out,
|
||||
AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_general_permute(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream,
|
||||
AMI_gen_perm_object *gpo) {
|
||||
|
||||
AMI_err ae;
|
||||
gen_perm_add_dest<T> gpad(gpo);
|
||||
gen_perm_strip_dest<T> gpsd;
|
||||
AMI_STREAM< dest_obj<T> > sdo_in;
|
||||
AMI_STREAM< dest_obj<T> > sdo_out;
|
||||
|
||||
// Initialize
|
||||
ae = gpo->initialize(instream->stream_len());
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Scan the stream, producing an output stream that labels each
|
||||
// item with its destination.
|
||||
ae = AMI_scan((AMI_STREAM<T> *)instream, &gpad,
|
||||
(AMI_STREAM< dest_obj<T> > *)&sdo_in);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Sort by destination.
|
||||
ae = AMI_sort(&sdo_in, &sdo_out);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Scan to strip off the destinations.
|
||||
ae = AMI_scan((AMI_STREAM< dest_obj<T> > *)&sdo_out, &gpsd,
|
||||
(AMI_STREAM<T> *)outstream);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#endif // _AMI_GEN_PERM_H
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// File: ami_gen_perm_object.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/15/94
|
||||
//
|
||||
// $Id: ami_gen_perm_object.h,v 1.4 2003/04/17 12:22:15 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_GEN_PERM_OBJECT_H
|
||||
#define _AMI_GEN_PERM_OBJECT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// For AMI_err.
|
||||
#include <ami_err.h>
|
||||
|
||||
// A class of object that computes permutation destinations.
|
||||
class AMI_gen_perm_object {
|
||||
public:
|
||||
virtual AMI_err initialize(TPIE_OS_OFFSET len) = 0;
|
||||
virtual TPIE_OS_OFFSET destination(TPIE_OS_OFFSET src) = 0;
|
||||
};
|
||||
|
||||
#endif // _AMI_GEN_PERM_OBJECT_H
|
||||
@@ -0,0 +1,242 @@
|
||||
// Copyright (c) 1995 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_kb_dist.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 3/11/95
|
||||
//
|
||||
// $Id: ami_kb_dist.h,v 1.10 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
// Radix based distribution for single or striped AMI layers.
|
||||
//
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// If we have not already seen this file with KB_KEY undefined or
|
||||
// KB_KEY is defined, we will process the file.
|
||||
|
||||
#if !(defined(_AMI_KB_DIST_H)) || defined(KB_KEY)
|
||||
|
||||
#ifdef KB_KEY
|
||||
|
||||
#define _KB_CONCAT(a,b) a ## b
|
||||
#define _AMI_KB_DIST(kbk) _KB_CONCAT(AMI_kb_dist_,kbk)
|
||||
|
||||
#else
|
||||
|
||||
// KB_KEY is not defined, so set the flag so we won't come through
|
||||
// this file again with KB_KEY unset, and set KB_KEY to kb_key
|
||||
// temporarily. We also Set the macro for the name of the function
|
||||
// defined in this file.
|
||||
|
||||
#define _AMI_KB_DIST_H
|
||||
#define KB_KEY kb_key
|
||||
|
||||
#ifdef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#error _HAVE_TEMP_KB_KEY_DEFINITION_ already defined.
|
||||
#else
|
||||
#define _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#endif
|
||||
|
||||
#define _AMI_KB_DIST(kbk) AMI_kb_dist
|
||||
|
||||
#endif
|
||||
|
||||
#include <ami_stream.h>
|
||||
#include <ami_key.h>
|
||||
|
||||
// This is a hack. The reason it is here is that if AMI_STREAM<char>
|
||||
// is used directly in the template for AMI_kb_dist() a parse error is
|
||||
// generated at compile time. I suspect this may be a bug in the
|
||||
// template instantiation code in g++ 2.6.3.
|
||||
|
||||
#ifndef _DEFINED_TYPE_AMISC_
|
||||
#define _DEFINED_TYPE_AMISC_
|
||||
typedef AMI_STREAM<char> type_amisc;
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
AMI_err _AMI_KB_DIST(KB_KEY)(AMI_STREAM<T> &instream,
|
||||
type_amisc &name_stream,
|
||||
const key_range &range, TPIE_OS_OFFSET &max_size)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
size_t sz_avail;
|
||||
size_t single_stream_usage;
|
||||
|
||||
// How many ouput streams will there be?
|
||||
unsigned int output_streams;
|
||||
|
||||
unsigned int ii;
|
||||
|
||||
// How much main memory do we have?
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// How much memory does a single stream need in the worst case?
|
||||
if ((ae = instream.main_memory_usage(&single_stream_usage,
|
||||
MM_STREAM_USAGE_MAXIMUM)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// How many output streams can we buffer in that amount of space?
|
||||
// Recall that we also need a pointer and a range for each stream.
|
||||
output_streams = (unsigned int)((sz_avail - 2 * single_stream_usage) /
|
||||
(single_stream_usage + sizeof(AMI_STREAM<T> *) + sizeof(range)));
|
||||
|
||||
// We need at least two output streams.
|
||||
if (output_streams < 2) {
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
|
||||
// Make sure we don't use more streams than are available.
|
||||
{
|
||||
unsigned available_streams = instream.available_streams();
|
||||
|
||||
if ((available_streams != (unsigned)-1) &&
|
||||
(available_streams < output_streams)) {
|
||||
output_streams = available_streams;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AMI_RADIX_POWER_OF_TWO
|
||||
// Adjust the number of output streams so that it is a power of two.
|
||||
|
||||
#endif
|
||||
|
||||
// Create the output streams and initialize the ranges they cover to
|
||||
// be empty.
|
||||
|
||||
AMI_STREAM<T> **out_streams = new AMI_STREAM<T> *[output_streams];
|
||||
key_range *out_ranges = new key_range[output_streams];
|
||||
|
||||
for (ii = 0; ii < output_streams; ii++) {
|
||||
|
||||
// This needs to be fixed to eliminate the max size parameter.
|
||||
// This should be done system-wide.
|
||||
out_streams[ii] = new AMI_STREAM<T>;
|
||||
|
||||
out_ranges[ii].min = KEY_MAX;
|
||||
out_ranges[ii].max = KEY_MIN;
|
||||
}
|
||||
|
||||
// Scan the input putting each item in the right output stream.
|
||||
|
||||
instream.seek(0);
|
||||
|
||||
unsigned int index_denom = (((range.max - range.min) / output_streams)
|
||||
+ 1);
|
||||
|
||||
while (1) {
|
||||
T *in;
|
||||
kb_key k;
|
||||
|
||||
ae = instream.read_item(&in);
|
||||
if (ae == AMI_ERROR_END_OF_STREAM) {
|
||||
break;
|
||||
} else if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
k = (unsigned int)KB_KEY(*in);
|
||||
|
||||
#ifdef AMI_RADIX_POWER_OF_TWO
|
||||
// Do it with shifting and masking.
|
||||
|
||||
#else
|
||||
ii = (k - range.min) / index_denom;
|
||||
#endif
|
||||
|
||||
ae = out_streams[ii]->write_item(*in);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
if (k < out_ranges[ii].min) {
|
||||
out_ranges[ii].min = k;
|
||||
}
|
||||
if (k > out_ranges[ii].max) {
|
||||
out_ranges[ii].max = k;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write the names and ranges of all non-empty output streams.
|
||||
|
||||
for (ii = 0, max_size = 0; ii < output_streams; ii++) {
|
||||
char *stream_name;
|
||||
TPIE_OS_OFFSET stream_len;
|
||||
|
||||
if ((stream_len = out_streams[ii]->stream_len()) > 0) {
|
||||
|
||||
// cerr << stream_len << '\n';
|
||||
|
||||
// Is it the biggest one so far?
|
||||
|
||||
if (stream_len > max_size) {
|
||||
max_size = stream_len;
|
||||
}
|
||||
|
||||
// Get the and write the name of the stream.
|
||||
|
||||
ae = out_streams[ii]->name(&stream_name);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = name_stream.write_array(stream_name,
|
||||
strlen(stream_name) + 1);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// For purposes of efficiency, and to avoid having another
|
||||
// stream, we are going to cast the new range to an array of
|
||||
// characters and tack it onto the stream name stream.
|
||||
// We then do the same thing with the length of the stream.
|
||||
|
||||
ae = name_stream.write_array((const char *)(out_ranges+ii),
|
||||
sizeof(key_range));
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = name_stream.write_array((const char *)&stream_len,
|
||||
sizeof(stream_len));
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// The semantics of name() are to allocate space for the
|
||||
// buffer it returns. We are responsible for giving it back.
|
||||
delete [] stream_name;
|
||||
|
||||
// Make this stream persist on disk since it is not empty.
|
||||
out_streams[ii]->persist(PERSIST_PERSISTENT);
|
||||
|
||||
}
|
||||
|
||||
// Delete the stream.
|
||||
delete out_streams[ii];
|
||||
|
||||
}
|
||||
|
||||
delete [] out_streams;
|
||||
|
||||
// We're done.
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifdef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#undef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#undef KB_KEY
|
||||
#endif
|
||||
|
||||
#ifdef _KB_CONCAT
|
||||
#undef _KB_CONCAT
|
||||
#endif
|
||||
#undef _AMI_KB_DIST
|
||||
|
||||
#endif // !(defined(_AMI_KB_DIST_H)) || defined(KB_KEY)
|
||||
@@ -0,0 +1,519 @@
|
||||
// Copyright (c) 1995 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_kb_sort.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 3/12/95
|
||||
//
|
||||
// $Id: ami_kb_sort.h,v 1.10 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
|
||||
// This header file can be included in one of two ways, either with a
|
||||
// KB_KEY macro defined, in which case it is assumed to be the name of
|
||||
// a function (typically inline) for extracting a key from an object
|
||||
// of type T, or undefined, in which case the conversion operator
|
||||
// kb_key() will be used by default. This file can be included
|
||||
// multiple times in the former case, but only once in the latter.
|
||||
|
||||
|
||||
// If we have not already seen this file with KB_KEY undefined or
|
||||
// KB_KEY is defined, we will process the file.
|
||||
|
||||
#if !(defined(_AMI_KB_SORT_H)) || defined(KB_KEY)
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <ami_key.h>
|
||||
#include <ami_kb_dist.h>
|
||||
|
||||
#ifdef KB_KEY
|
||||
|
||||
#define _KB_CONCAT(a,b) a ## b
|
||||
#define _AMI_KB_SORT(kbk) _KB_CONCAT(AMI_kb_sort_,kbk)
|
||||
#define _AMI_MM_KB_SORT(kbk) _KB_CONCAT(AMI_mm_kb_sort_,kbk)
|
||||
#define _AMI_KB_DIST(kbk) _KB_CONCAT(AMI_kb_dist_,kbk)
|
||||
|
||||
#else
|
||||
|
||||
// KB_KEY is not defined, so set the flag so we won't come through
|
||||
// this file again with KB_KEY unset, and set KB_KEY to kb_key
|
||||
// temporarily. We also Set the macro for the name of the function
|
||||
// defined in this file.
|
||||
|
||||
#define _AMI_KB_SORT_H
|
||||
#define KB_KEY kb_key
|
||||
|
||||
#ifdef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#error _HAVE_TEMP_KB_KEY_DEFINITION_ already defined.
|
||||
#else
|
||||
#define _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#endif
|
||||
|
||||
#define _AMI_KB_SORT(kbk) AMI_kb_sort
|
||||
#define _AMI_MM_KB_SORT(kbk) AMI_mm_kb_sort
|
||||
#define _AMI_KB_DIST(kbk) AMI_kb_dist
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _DEFINED_STATIC_KEY_MIN_MAX
|
||||
#define _DEFINED_STATIC_KEY_MIN_MAX
|
||||
static key_range min_max(KEY_MIN, KEY_MAX);
|
||||
#endif // _DEFINED_STATIC_KEY_MIN_MAX
|
||||
|
||||
#ifndef _AMI_BUCKET_LIST_ELEM
|
||||
#define _AMI_BUCKET_LIST_ELEM
|
||||
|
||||
template<class T>
|
||||
class AMI_bucket_list_elem
|
||||
{
|
||||
public:
|
||||
T data;
|
||||
AMI_bucket_list_elem<T> *next;
|
||||
AMI_bucket_list_elem() : next(0) {};
|
||||
~AMI_bucket_list_elem() {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err _AMI_MM_KB_SORT(KB_KEY)(AMI_STREAM<T> &instream,
|
||||
AMI_STREAM<T> &outstream,
|
||||
const key_range &range);
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err _AMI_KB_SORT(KB_KEY)(AMI_STREAM<T> &instream,
|
||||
AMI_STREAM<T> &outstream,
|
||||
const key_range &range)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
// Memory sizes.
|
||||
size_t sz_avail, sz_stream;
|
||||
// Stream sizes.
|
||||
TPIE_OS_OFFSET max_size, stream_len;
|
||||
|
||||
// Check whether the problem fits in main memory.
|
||||
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
instream.main_memory_usage(&sz_stream, MM_STREAM_USAGE_MAXIMUM);
|
||||
|
||||
if (sz_avail < 4 * sz_stream) {
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
|
||||
// Account for the two name streams.
|
||||
|
||||
sz_avail -= 2*sz_stream;
|
||||
|
||||
// If it fits, simply read it, sort it, and write it.
|
||||
|
||||
stream_len = instream.stream_len();
|
||||
|
||||
if (sz_avail >= stream_len * (sizeof(T) +
|
||||
sizeof(AMI_bucket_list_elem<T> *) +
|
||||
sizeof(AMI_bucket_list_elem<T>))) {
|
||||
return _AMI_MM_KB_SORT(KB_KEY)(instream, outstream, range);
|
||||
}
|
||||
|
||||
// It did not fit, so we have to distribute it.
|
||||
|
||||
// Create streams of temporary file names.
|
||||
AMI_STREAM<char> *name_stream, *name_stream2 = NULL;
|
||||
|
||||
name_stream = new AMI_STREAM<char>;
|
||||
|
||||
// Do the first level distribution.
|
||||
|
||||
ae = _AMI_KB_DIST(KB_KEY)(instream, *name_stream, range, max_size);
|
||||
|
||||
// Do the rest of the levels of distribution, continuing until all
|
||||
// streams are small or have a single key and then, in a final
|
||||
// iteration, sorting the streams internally and concatenating
|
||||
// them. In some bad cases we will end up with one or more large
|
||||
// streams of all the same key, but these are detected and treated
|
||||
// as small streams.
|
||||
|
||||
bool some_stream_is_large = ((max_size *
|
||||
(sizeof(T) + 4 +
|
||||
sizeof(AMI_bucket_list_elem<T> *) +
|
||||
sizeof(AMI_bucket_list_elem<T>))) >
|
||||
sz_avail);
|
||||
|
||||
while (1) {
|
||||
|
||||
// Create a new stream of temporary stream names.
|
||||
tp_assert(name_stream2 == NULL, "Non-null target name stream.");
|
||||
name_stream2 = new AMI_STREAM<char>;
|
||||
|
||||
// Is this the last (special) iteration.
|
||||
bool last_iteration = !some_stream_is_large;
|
||||
|
||||
// We have not seen a large stream yet.
|
||||
some_stream_is_large = false;
|
||||
|
||||
// Iterate over the streams by reading their names out of
|
||||
// stream_name and recursing on each one.
|
||||
|
||||
name_stream->seek(0);
|
||||
|
||||
while (1) {
|
||||
// The range of keys in the stream being read.
|
||||
key_range stream_range;
|
||||
char *pc_read;
|
||||
char *pc;
|
||||
char stream_name[255];
|
||||
|
||||
// Read the next stream name. We start by reading the
|
||||
// first character and checking for an EOS condition
|
||||
// indicating there are no more streams.
|
||||
|
||||
pc = stream_name;
|
||||
ae = name_stream->read_item(&pc_read);
|
||||
if (ae == AMI_ERROR_END_OF_STREAM) {
|
||||
// We hit the end of the stream name stream, so we
|
||||
// should break out of the while loop over the streams
|
||||
// that are named.
|
||||
break;
|
||||
} else if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
*pc = *pc_read;
|
||||
|
||||
// Now loop to read the rest of the name.
|
||||
|
||||
while (*pc != '\0') {
|
||||
ae = name_stream->read_item(&pc_read);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
*(++pc) = *pc_read;
|
||||
|
||||
tp_assert(pc < stream_name+254, "Read too far.");
|
||||
}
|
||||
|
||||
// Read its range.
|
||||
{
|
||||
TPIE_OS_OFFSET range_size = sizeof(stream_range);
|
||||
ae = name_stream->read_array((char *)&stream_range,
|
||||
&range_size);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
// Read its length.
|
||||
{
|
||||
TPIE_OS_OFFSET length_size = sizeof(stream_len);
|
||||
ae = name_stream->read_array((char *)&stream_len,
|
||||
&length_size);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_iteration) {
|
||||
if ((stream_len * (sizeof(T) + 4 +
|
||||
sizeof(AMI_bucket_list_elem<T> *) +
|
||||
sizeof(AMI_bucket_list_elem<T>)) >
|
||||
sz_avail) &&
|
||||
(stream_range.max > stream_range.min + 1)) {
|
||||
|
||||
// If it is too big but does not contain all the same key,
|
||||
// distribute it again.
|
||||
|
||||
some_stream_is_large = true;
|
||||
|
||||
AMI_STREAM<T> curr_stream(stream_name);
|
||||
|
||||
// We only need to read the intermediate stream once.
|
||||
|
||||
curr_stream.persist(PERSIST_READ_ONCE);
|
||||
|
||||
ae = _AMI_KB_DIST(KB_KEY)(curr_stream, *name_stream2,
|
||||
stream_range, max_size);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// It is either small or contains only a single
|
||||
// key, so just pass it without further
|
||||
// processing.
|
||||
|
||||
// Write the name.
|
||||
ae = name_stream2->write_array(stream_name,
|
||||
strlen(stream_name) + 1);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Write the range.
|
||||
|
||||
ae = name_stream2->write_array((const char *)&stream_range,
|
||||
sizeof(stream_range));
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Write the length.
|
||||
|
||||
ae = name_stream2->write_array((const char *)&stream_len,
|
||||
sizeof(stream_len));
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// This is the last iteration.
|
||||
|
||||
// Open the stream.
|
||||
|
||||
AMI_STREAM<T> curr_stream(stream_name);
|
||||
|
||||
// We only need to read the intermediate stream once.
|
||||
|
||||
curr_stream.persist(PERSIST_READ_ONCE);
|
||||
|
||||
// Check whether it is truly small or just all one key.
|
||||
|
||||
if (stream_range.min == stream_range.max) {
|
||||
|
||||
// If it is all one key, simply concatenate it
|
||||
// onto the output.
|
||||
|
||||
T *pt;
|
||||
|
||||
while(1) {
|
||||
ae = curr_stream.read_item(&pt);
|
||||
if (ae == AMI_ERROR_END_OF_STREAM) {
|
||||
break;
|
||||
} else if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
ae = outstream.write_item(*pt);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Read the contents into main memory; sort them,
|
||||
// and write them out.
|
||||
|
||||
ae = _AMI_MM_KB_SORT(KB_KEY)(curr_stream, outstream,
|
||||
stream_range);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We just finished reading all named streams at the current
|
||||
// level of recursion. Now we want to set up for the next
|
||||
// level. To do this, we get rid of the names we just
|
||||
// processed and replace them by the names we need to process
|
||||
// next. Of course, this is only done if we are not in the last
|
||||
// iteration.
|
||||
|
||||
delete name_stream;
|
||||
|
||||
if (!last_iteration) {
|
||||
name_stream = name_stream2;
|
||||
name_stream2 = NULL;
|
||||
} else {
|
||||
delete name_stream2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// Main memory key bucket sorting.
|
||||
|
||||
template<class T>
|
||||
AMI_err _AMI_MM_KB_SORT(KB_KEY)(AMI_STREAM<T> &instream,
|
||||
AMI_STREAM<T> &outstream,
|
||||
const key_range &range)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
size_t sz_avail;
|
||||
TPIE_OS_OFFSET stream_len;
|
||||
|
||||
TPIE_OS_OFFSET ii,jj;
|
||||
|
||||
// Check available main memory.
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// How long is the input stream?
|
||||
stream_len = instream.stream_len();
|
||||
|
||||
// Verify that we have enough memory.
|
||||
if (sz_avail < stream_len * (sizeof(T) +
|
||||
sizeof(AMI_bucket_list_elem<T> *) +
|
||||
sizeof(AMI_bucket_list_elem<T>))) {
|
||||
cerr << '\n' << (TPIE_OS_LONGLONG)sz_avail << ' ' << (TPIE_OS_LONGLONG)stream_len << '\n';
|
||||
cerr << sizeof(T) << ' ' << sizeof(AMI_bucket_list_elem<T> *) <<
|
||||
' ' << sizeof(AMI_bucket_list_elem<T>);
|
||||
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
|
||||
// Allocate the space for the data and for the bucket list elements.
|
||||
// We know that stream_len items fit in main memory, so it is safe to cast.
|
||||
T *indata = new T[(TPIE_OS_SIZE_T)stream_len];
|
||||
|
||||
AMI_bucket_list_elem<T> **buckets =
|
||||
new AMI_bucket_list_elem<T>*[(TPIE_OS_SIZE_T)stream_len];
|
||||
|
||||
AMI_bucket_list_elem<T> *list_space =
|
||||
new AMI_bucket_list_elem<T>[(TPIE_OS_SIZE_T)stream_len];
|
||||
|
||||
// Read the input stream.
|
||||
|
||||
instream.seek(0);
|
||||
{
|
||||
TPIE_OS_OFFSET sl2 = stream_len;
|
||||
ae = instream.read_array(indata, &sl2);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
delete[] indata;
|
||||
delete[] buckets;
|
||||
delete[] list_space;
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty out the buckets.
|
||||
|
||||
for (ii = stream_len; ii--; ) {
|
||||
buckets[ii] = NULL;
|
||||
}
|
||||
|
||||
// Scan the input, assigning each item to the appropriate bucket.
|
||||
|
||||
AMI_bucket_list_elem<T> *list_elem;
|
||||
|
||||
unsigned int bucket_index_denom = (unsigned int)(((range.max - range.min) /
|
||||
stream_len) + 1);
|
||||
|
||||
if (!bucket_index_denom) {
|
||||
bucket_index_denom = 1;
|
||||
}
|
||||
|
||||
for (ii = stream_len, list_elem = list_space;
|
||||
ii--; list_elem++ ) {
|
||||
unsigned int bucket_index;
|
||||
|
||||
bucket_index = ((unsigned int)((KB_KEY)(indata[ii])) - range.min) /
|
||||
bucket_index_denom;
|
||||
|
||||
tp_assert(bucket_index < (unsigned long)stream_len, "Bucket index too large.");
|
||||
|
||||
list_elem->data = indata[ii];
|
||||
list_elem->next = buckets[bucket_index];
|
||||
buckets[bucket_index] = list_elem;
|
||||
}
|
||||
|
||||
tp_assert(list_elem == list_space + stream_len,
|
||||
"Didn't use the right number of list elements.");
|
||||
|
||||
|
||||
// Scan the buckets to put the data back in the input array. In
|
||||
// order to make the sort stable, we have to be sure to read the
|
||||
// lists corresponding to the buckets in the correct order. The
|
||||
// elements that appeared earlier in the orginal data were written
|
||||
// later (i.e. towards the front of the lists) so we should
|
||||
// rebuild the data array from the 0th element upwards.
|
||||
|
||||
#define VERIFY_OCCUPANCY 0
|
||||
#if VERIFY_OCCUPANCY
|
||||
unsigned int max_occupancy = 0;
|
||||
unsigned int buckets_occupied = 0;
|
||||
#endif
|
||||
for (ii = 0, jj = 0; ii < (unsigned)stream_len; ii++) {
|
||||
#if VERIFY_OCCUPANCY
|
||||
unsigned int cur_occupancy = 0;
|
||||
#endif
|
||||
for (list_elem = buckets[ii]; list_elem != NULL;
|
||||
list_elem = list_elem->next) {
|
||||
#if VERIFY_OCCUPANCY
|
||||
cur_occupancy++;
|
||||
#endif
|
||||
indata[jj++] = list_elem->data;
|
||||
}
|
||||
#if VERIFY_OCCUPANCY
|
||||
if (cur_occupancy > max_occupancy) {
|
||||
max_occupancy = cur_occupancy;
|
||||
}
|
||||
if (cur_occupancy != 0) {
|
||||
buckets_occupied++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VERIFY_OCCUPANCY
|
||||
cerr << "Max occupancy = " << max_occupancy << '\n';
|
||||
cerr << "Buckets occupied = " << buckets_occupied << '\n';
|
||||
cerr << "Stream length = " << stream_len << '\n';
|
||||
#endif
|
||||
|
||||
// Do an insertion sort across the whole data set.
|
||||
|
||||
{
|
||||
T *p, *q, test;
|
||||
|
||||
for (p = indata + 1; p < indata + stream_len; p++) {
|
||||
for (q = p - 1, test = *p;
|
||||
(q >= indata) && (KB_KEY(*q) > KB_KEY(test)); q--) {
|
||||
*(q+1) = *q;
|
||||
}
|
||||
*(q+1) = test;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the results.
|
||||
|
||||
ae = outstream.write_array(indata, stream_len);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
delete [] indata;
|
||||
delete [] buckets;
|
||||
delete [] list_space;
|
||||
return ae;
|
||||
}
|
||||
|
||||
delete [] indata;
|
||||
delete [] buckets;
|
||||
delete [] list_space;
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifdef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#undef _HAVE_TEMP_KB_KEY_DEFINITION_
|
||||
#undef KB_KEY
|
||||
#endif
|
||||
|
||||
#ifdef _KB_CONCAT
|
||||
#undef _KB_CONCAT
|
||||
#endif
|
||||
#undef _AMI_KB_SORT
|
||||
#undef _AMI_KB_MM_SORT
|
||||
#undef _AMI_KB_MM_DIST
|
||||
|
||||
|
||||
#endif // !(defined(_AMI_KB_SORT_H)) || defined(KB_KEY)
|
||||
@@ -0,0 +1,556 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_kdtree_base.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// Supporting types for AMI_kdtree and AMI_kdbtree:
|
||||
// AMI_kdtree_status, link_type_t,
|
||||
// AMI_kdtree_params, Bin_node_default,
|
||||
// AMI_kdbtree_status, AMI_kdbtree_params,
|
||||
// region_t, kdb_item_t, path_stack_item_t.
|
||||
//
|
||||
// $Id: ami_kd_base.h,v 1.9 2005/02/12 20:29:10 tavi Exp $
|
||||
//
|
||||
|
||||
#ifndef _AMI_KD_BASE_H
|
||||
#define _AMI_KD_BASE_H
|
||||
|
||||
// For ostream.
|
||||
#include <iostream>
|
||||
// For min, max.
|
||||
#include <algorithm>
|
||||
#include <ami_block_base.h>
|
||||
#include <ami_point.h>
|
||||
|
||||
// AMI_KDTREE_STORE_WEIGHTS determines whether weights are stored in all
|
||||
// binary kd-tree nodes (when set to 1), or just in block nodes (when set
|
||||
// to 0). Setting to 1 results in bigger binary nodes and, consequently,
|
||||
// smaller fanout. The weights are used to dramatically improve the
|
||||
// performance of range *counting* queries (not range reporting
|
||||
// queries). Caveat emptor: avoid often change of this parameter. Trying to
|
||||
// open an existing kd-tree with the wrong value for this parameter will
|
||||
// generate an invalid kd-tree.
|
||||
#ifndef AMI_KDTREE_STORE_WEIGHTS
|
||||
# define AMI_KDTREE_STORE_WEIGHTS 0
|
||||
#endif
|
||||
|
||||
// AMI_KDTREE_USE_EXACT_SPLIT determines how points on the median line are
|
||||
// distributed. If set to 1, some of the points go into the left child,
|
||||
// some into the right child; the search procedure should look into both
|
||||
// children. If set to 0, only the left child contains those points. In
|
||||
// theory, this is a tradeoff between space utilization and query
|
||||
// performance. However, query performance is rarely affected, so a value
|
||||
// of 1 is appropriate for most instances. Trying to open an existing
|
||||
// kd-tree with the wrong value for this parameter will generate an invalid
|
||||
// kd-tree.
|
||||
#ifndef AMI_KDTREE_USE_EXACT_SPLIT
|
||||
# define AMI_KDTREE_USE_EXACT_SPLIT 1
|
||||
#endif
|
||||
|
||||
// AMI_KDTREE_USE_KDBTREE_LEAF determines what the info field of a leaf
|
||||
// contains. Setting to 1 gives a three-element info field, similar to
|
||||
// the one used by the K-D-B-tree. This allows a kd-tree to be
|
||||
// transformed into a K-D-B-tree without touching the leaves, but it
|
||||
// wastes 4 bytes in every leaf. If set to 0, the info field of a leaf
|
||||
// contains only two 4-byte elements. Caveat emptor: avoid often
|
||||
// change of this parameter. Trying to open an existing kd-tree with
|
||||
// the wrong value for this parameter will generate an invalid kd-tree.
|
||||
#ifndef AMI_KDTREE_USE_KDBTREE_LEAF
|
||||
# define AMI_KDTREE_USE_KDBTREE_LEAF 1
|
||||
#endif
|
||||
|
||||
// AMI_KDTREE_USE_REAL_MEDIAN determines the kd-tree splitting method. If
|
||||
// set to 1, medians are used. If set to 0, the weight of the left branch
|
||||
// is always a power of 2. This allows kd-trees to be very compact in terms
|
||||
// of storage utilization. The only place this value is checked is the
|
||||
// median() method of the kd-tree.
|
||||
#ifndef AMI_KDTREE_USE_REAL_MEDIAN
|
||||
# define AMI_KDTREE_USE_REAL_MEDIAN 0
|
||||
#endif
|
||||
|
||||
// The default grid size (on each dimension) for the grid bulk loading.
|
||||
#ifndef AMI_KDTREE_GRID_SIZE
|
||||
# define AMI_KDTREE_GRID_SIZE 256
|
||||
#endif
|
||||
|
||||
// Loading methods. These bits can be combined, but not all
|
||||
// combinations are valid.
|
||||
#define AMI_KDTREE_LOAD_SORT 0x1
|
||||
#define AMI_KDTREE_LOAD_SAMPLE 0x2
|
||||
#define AMI_KDTREE_LOAD_BINARY 0x4
|
||||
#define AMI_KDTREE_LOAD_GRID 0x8
|
||||
|
||||
|
||||
// AMI_kdtree status type.
|
||||
enum AMI_kdtree_status {
|
||||
AMI_KDTREE_STATUS_VALID = 0,
|
||||
AMI_KDTREE_STATUS_INVALID = 1,
|
||||
};
|
||||
|
||||
// Node type type.
|
||||
typedef unsigned short int link_type_t;
|
||||
#define BLOCK_NODE 0u
|
||||
#define BLOCK_LEAF 1u
|
||||
#define BIN_NODE 2u
|
||||
#define GRID_INDEX 3u
|
||||
|
||||
|
||||
// AMI_kdtree run-time parameters.
|
||||
class AMI_kdtree_params {
|
||||
public:
|
||||
|
||||
// Max number of Value's in a leaf. 0 means use all available capacity.
|
||||
TPIE_OS_SIZE_T leaf_size_max;
|
||||
// Max number of Key's in a node. 0 means use all available capacity.
|
||||
TPIE_OS_SIZE_T node_size_max;
|
||||
// How much bigger is the leaf logical block than the system block.
|
||||
TPIE_OS_SIZE_T leaf_block_factor;
|
||||
// How much bigger is the node logical block than the system block.
|
||||
TPIE_OS_SIZE_T node_block_factor;
|
||||
// The max number of leaves cached.
|
||||
TPIE_OS_SIZE_T leaf_cache_size;
|
||||
// The max number of nodes cached.
|
||||
TPIE_OS_SIZE_T node_cache_size;
|
||||
// Max height of a binary node inside a block node (other than
|
||||
// root). The root binary node has height 0. A default value, based
|
||||
// on node capacity, is used if set to 0.
|
||||
TPIE_OS_SIZE_T max_intranode_height;
|
||||
// Max height of a binary node inside the root block node. The root
|
||||
// binary node has height 0. A default value, based on node
|
||||
// capacity, is used if set to 0.
|
||||
TPIE_OS_SIZE_T max_intraroot_height;
|
||||
// The grid size on each dimension, for grid bulk loading.
|
||||
TPIE_OS_SIZE_T grid_size;
|
||||
|
||||
// The default parameter values.
|
||||
AMI_kdtree_params():
|
||||
leaf_size_max(0), node_size_max(0),
|
||||
leaf_block_factor(1), node_block_factor(1),
|
||||
leaf_cache_size(8), node_cache_size(8),
|
||||
max_intranode_height(0), max_intraroot_height(0),
|
||||
grid_size(AMI_KDTREE_GRID_SIZE) {}
|
||||
};
|
||||
|
||||
|
||||
// A base class for all binary node implementations. This is not a complete
|
||||
// implementation of a kd-tree binary node!
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class AMI_kdtree_bin_node_base {
|
||||
public:
|
||||
|
||||
void initialize(const AMI_point<coord_t, dim> &p, TPIE_OS_SIZE_T d) {
|
||||
assert(d < dim);
|
||||
discr_val_ = p[d];
|
||||
discr_dim_ = d;
|
||||
}
|
||||
TPIE_OS_SIZE_T get_discriminator_dim() {
|
||||
return discr_dim_;
|
||||
}
|
||||
coord_t get_discriminator_val() {
|
||||
return discr_val_;
|
||||
}
|
||||
int discriminate(const AMI_point<coord_t, dim> &p) const {
|
||||
return (p[discr_dim_] < discr_val_) ? -1: (p[discr_dim_] > discr_val_) ? 1: 0;
|
||||
}
|
||||
// int discriminate(const AMI_point<coord_t, dim> &p) const {
|
||||
// return (p[discr_dim_] <= discr_val_) ? -1: 1;
|
||||
// }
|
||||
|
||||
#if AMI_KDTREE_STORE_WEIGHTS
|
||||
TPIE_OS_OFFSET &low_weight() {
|
||||
return lo_weight_;
|
||||
}
|
||||
TPIE_OS_OFFSET &high_weight() {
|
||||
return hi_weight_;
|
||||
}
|
||||
TPIE_OS_OFFSET low_weight() const {
|
||||
return lo_weight_;
|
||||
}
|
||||
TPIE_OS_SIZE_T high_weight() const {
|
||||
return hi_weight_;
|
||||
}
|
||||
private:
|
||||
TPIE_OS_OFFSET lo_weight_;
|
||||
TPIE_OS_OFFSET hi_weight_;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The split coordinate (the split hyperplane crosses the orthogonal
|
||||
// axis in this value).
|
||||
coord_t discr_val_;
|
||||
// The dimension orthogonal to the split hyperplane. Should be less than dim.
|
||||
TPIE_OS_SIZE_T discr_dim_;
|
||||
};
|
||||
|
||||
|
||||
// The default binary node implementation.
|
||||
// (All binary node implementations should have the same public interface).
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class AMI_kdtree_bin_node_default: public AMI_kdtree_bin_node_base<coord_t, dim> {
|
||||
public:
|
||||
|
||||
void set_low_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
lo_child_ = idx;
|
||||
lo_type_ = idx_type;
|
||||
}
|
||||
void set_high_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
hi_child_ = idx;
|
||||
hi_type_ = idx_type;
|
||||
}
|
||||
void get_low_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = lo_child_;
|
||||
idx_type = lo_type_;
|
||||
}
|
||||
void get_high_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = hi_child_;
|
||||
idx_type = hi_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
// The low child (i.e., its position in the block node).
|
||||
TPIE_OS_SIZE_T lo_child_;
|
||||
link_type_t lo_type_;
|
||||
// The high child (i.e., its position in the block node).
|
||||
TPIE_OS_SIZE_T hi_child_;
|
||||
link_type_t hi_type_;
|
||||
};
|
||||
|
||||
|
||||
// Another binary node implementation, smaller than the default (uses short
|
||||
// int instead of TPIE_OS_SIZE_T and link_type_t).
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class AMI_kdtree_bin_node_short: public AMI_kdtree_bin_node_base<coord_t, dim> {
|
||||
public:
|
||||
|
||||
void set_low_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
lo_child_ = (unsigned short) idx;
|
||||
lo_type_ = (unsigned short) idx_type;
|
||||
}
|
||||
void set_high_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
hi_child_ = (unsigned short) idx;
|
||||
hi_type_ = (unsigned short) idx_type;
|
||||
}
|
||||
void get_low_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = (TPIE_OS_SIZE_T) lo_child_;
|
||||
idx_type = (link_type_t) lo_type_;
|
||||
}
|
||||
void get_high_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = (TPIE_OS_SIZE_T) hi_child_;
|
||||
idx_type = (link_type_t) hi_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
// The low child (i.e., its position in the block node).
|
||||
unsigned short lo_child_;
|
||||
unsigned short lo_type_;
|
||||
// The high child (i.e., its position in the block node).
|
||||
unsigned short hi_child_;
|
||||
unsigned short hi_type_;
|
||||
};
|
||||
|
||||
|
||||
// Yet another binary node type. Same functionality as the default
|
||||
// type, but much more compact.
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class AMI_kdtree_bin_node_small: public AMI_kdtree_bin_node_base<coord_t, dim> {
|
||||
public:
|
||||
|
||||
void set_low_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
lo_child_ = ((unsigned short) idx << 2) | ((unsigned short) idx_type & 0x3);
|
||||
}
|
||||
void set_high_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
hi_child_ = ((unsigned short) idx << 2) | ((unsigned short) idx_type & 0x3);
|
||||
}
|
||||
|
||||
void get_low_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = lo_child_ >> 2;
|
||||
idx_type = (link_type_t) (lo_child_ & 0x3);
|
||||
}
|
||||
void get_high_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = hi_child_ >> 2;
|
||||
idx_type = (link_type_t) (hi_child_ & 0x3);
|
||||
}
|
||||
|
||||
private:
|
||||
// The low child and type together.
|
||||
unsigned short lo_child_;
|
||||
// The high child and type together.
|
||||
unsigned short hi_child_;
|
||||
};
|
||||
|
||||
|
||||
// A binary node larger than the default. Stores an entire point as a
|
||||
// discriminator, instead of just one value. Does not inherit from the base
|
||||
// class.
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class AMI_kdtree_bin_node_large {
|
||||
public:
|
||||
void initialize(const AMI_point<coord_t, dim> &p, TPIE_OS_SIZE_T d) {
|
||||
discr_val_ = p;
|
||||
discr_dim_ = d;
|
||||
}
|
||||
void set_low_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
lo_child_ = idx;
|
||||
lo_type_ = idx_type;
|
||||
}
|
||||
void set_high_child(TPIE_OS_SIZE_T idx, link_type_t idx_type) {
|
||||
hi_child_ = idx;
|
||||
hi_type_ = idx_type;
|
||||
}
|
||||
int discriminate(const AMI_point<coord_t, dim> &p) const {
|
||||
return (p[discr_dim_] < discr_val_[discr_dim_]) ? -1:
|
||||
(p[discr_dim_] > discr_val_[discr_dim_]) ? 1:
|
||||
(p[(discr_dim_+1)%dim] < discr_val_[(discr_dim_+1)%dim]) ? -1 :
|
||||
(p[(discr_dim_+1)%dim] == discr_val_[(discr_dim_+1)%dim]) ? 0: 1;
|
||||
}
|
||||
void get_low_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = lo_child_;
|
||||
idx_type = lo_type_;
|
||||
}
|
||||
void get_high_child(TPIE_OS_SIZE_T &idx, link_type_t &idx_type) const {
|
||||
idx = hi_child_;
|
||||
idx_type = hi_type_;
|
||||
}
|
||||
#if AMI_KDTREE_STORE_WEIGHTS
|
||||
TPIE_OS_OFFSET &low_weight() {
|
||||
return lo_weight_;
|
||||
}
|
||||
TPIE_OS_OFFSET &high_weight() {
|
||||
return hi_weight_;
|
||||
}
|
||||
TPIE_OS_OFFSET low_weight() const {
|
||||
return lo_weight_;
|
||||
}
|
||||
TPIE_OS_OFFSET high_weight() const {
|
||||
return hi_weight_;
|
||||
}
|
||||
private:
|
||||
TPIE_OS_OFFSET lo_weight_;
|
||||
TPIE_OS_OFFSET hi_weight_;
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
// The split point.
|
||||
AMI_point<coord_t, dim> discr_val_;
|
||||
// The dimension orthogonal to the split hyperplane. Should be less than dim.
|
||||
TPIE_OS_SIZE_T discr_dim_;
|
||||
// The low child (i.e., its position in the block node).
|
||||
TPIE_OS_SIZE_T lo_child_;
|
||||
link_type_t lo_type_;
|
||||
// The high child (i.e., its position in the block node).
|
||||
TPIE_OS_SIZE_T hi_child_;
|
||||
link_type_t hi_type_;
|
||||
};
|
||||
|
||||
|
||||
///// AMI_kdbtree stuff /////
|
||||
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class region_t {
|
||||
protected:
|
||||
// The low and high coordinates. The boolean bit is true iff the
|
||||
// box is bounded on that dimension.
|
||||
// pair<coord_t, bool> lo_[dim];
|
||||
// pair<coord_t, bool> hi_[dim];
|
||||
coord_t lo_[dim];
|
||||
coord_t hi_[dim];
|
||||
|
||||
// Contains the bounded bits: least significant bit is for low
|
||||
// boundary, and second least significant bit is for upper
|
||||
// boundary.
|
||||
unsigned char bd_[dim];
|
||||
|
||||
#define LO_BD_MASK ((unsigned char) 1)
|
||||
#define HI_BD_MASK ((unsigned char) 2)
|
||||
|
||||
// char lo_bd_[dim];
|
||||
// char hi_bd_[dim];
|
||||
public:
|
||||
region_t() {
|
||||
for (int i = 0; i < dim; i++)
|
||||
bd_[i] = 0;
|
||||
// lo_bd_[i] = hi_bd_[i] = 0; //false;
|
||||
}
|
||||
|
||||
// Initialize this box with the values stored in points p1 and p2.
|
||||
region_t(const AMI_point<coord_t, dim>& p1, const AMI_point<coord_t, dim>& p2) {
|
||||
for (TPIE_OS_SIZE_T i = 0; i < dim; i++) {
|
||||
lo_[i] = min(p1[i], p2[i]);
|
||||
// lo_bd_[i] = 1;//true;
|
||||
bd_[i] |= LO_BD_MASK; // true on low bd.
|
||||
hi_[i] = max(p1[i], p2[i]);
|
||||
// hi_bd_[i] = 1;//true;
|
||||
bd_[i] |= HI_BD_MASK; // true on high bd.
|
||||
if (p1[i] == p2[i])
|
||||
TP_LOG_WARNING_ID(" region_t: points have one identical coordinate.");
|
||||
}
|
||||
}
|
||||
|
||||
coord_t lo(TPIE_OS_SIZE_T d) const { return lo_[d]; }
|
||||
coord_t& lo(TPIE_OS_SIZE_T d) { return lo_[d]; }
|
||||
|
||||
coord_t hi(TPIE_OS_SIZE_T d) const { return hi_[d]; }
|
||||
coord_t& hi(TPIE_OS_SIZE_T d) { return hi_[d]; }
|
||||
|
||||
bool is_bounded_lo(TPIE_OS_SIZE_T d) const { return (bd_[d] & LO_BD_MASK) != 0; }
|
||||
bool is_bounded_hi(TPIE_OS_SIZE_T d) const { return (bd_[d] & HI_BD_MASK) != 0; }
|
||||
bool is_bounded(TPIE_OS_SIZE_T d) const
|
||||
{ return is_bounded_lo(d) && is_bounded_hi(d); }
|
||||
bool is_bounded() const {
|
||||
TPIE_OS_SIZE_T i;
|
||||
for (i = 0; i < dim; i++)
|
||||
if (!is_bounded(i))
|
||||
break;
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
void set_bounded_lo(TPIE_OS_SIZE_T d, bool b) { bd_[d] |= (b ? LO_BD_MASK: 0); }
|
||||
void set_bounded_hi(TPIE_OS_SIZE_T d, bool b) { bd_[d] |= (b ? HI_BD_MASK: 0); }
|
||||
|
||||
coord_t span(TPIE_OS_SIZE_T d) const { return hi(d) - lo(d); }
|
||||
|
||||
AMI_point<coord_t, dim> point_lo() const {
|
||||
AMI_point<coord_t, dim> p;
|
||||
for (TPIE_OS_SIZE_T i = 0; i < dim; i++)
|
||||
p[i] = lo_[i];
|
||||
return p;
|
||||
}
|
||||
|
||||
AMI_point<coord_t, dim> point_hi() const {
|
||||
AMI_point<coord_t, dim> p;
|
||||
for (TPIE_OS_SIZE_T i = 0; i < dim; i++)
|
||||
p[i] = hi_[i];
|
||||
return p;
|
||||
}
|
||||
|
||||
// Cutout the portion of the region that's higher than the given
|
||||
// coordinate.
|
||||
void cutout_hi(coord_t v, TPIE_OS_SIZE_T d) {
|
||||
hi_[d] = v;
|
||||
// hi_bd_[d] = 1;//true;
|
||||
bd_[d] |= HI_BD_MASK;
|
||||
}
|
||||
|
||||
// Cutout the portion of the region that's lower than the given
|
||||
// coordinate.
|
||||
void cutout_lo(coord_t v, TPIE_OS_SIZE_T d) {
|
||||
lo_[d] = v;
|
||||
// lo_bd_[d] = 1;//true;
|
||||
bd_[d] |= LO_BD_MASK;
|
||||
}
|
||||
|
||||
// Return true if this box contains point p.
|
||||
bool contains(const AMI_point<coord_t, dim>& p) const {
|
||||
TPIE_OS_SIZE_T i;
|
||||
for (i = 0; i < dim; i++) {
|
||||
if ((is_bounded_lo(i) && p[i] < lo_[i]) ||
|
||||
(is_bounded_hi(i) && p[i] > hi_[i]))
|
||||
break;
|
||||
}
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
// Return true if this box intersects box r.
|
||||
bool intersects(const region_t<coord_t, dim>& r) const {
|
||||
TPIE_OS_SIZE_T i;
|
||||
for (i = 0; i < dim; i++) {
|
||||
if ((r.is_bounded_lo(i) && relative_to_plane(r.lo_[i], i) == -1) ||
|
||||
(r.is_bounded_hi(i) && relative_to_plane(r.hi_[i], i) == 1))
|
||||
break;
|
||||
}
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
// Return the position of this box relative to the hyperplane
|
||||
// orthogonal to dimension d and passing through sp: -1 if left of
|
||||
// the hyperplane, 1 if right of the hyperplane, and 0 if it
|
||||
// intersects the hyperplane.
|
||||
int relative_to_plane(coord_t sp, TPIE_OS_SIZE_T d) const {
|
||||
if (is_bounded_hi(d) && !(sp < hi_[d]))
|
||||
return -1;
|
||||
if (is_bounded_lo(d) && !(lo_[d] < sp))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#undef LO_BD_MASK
|
||||
#undef HI_BD_MASK
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
class kdb_item_t {
|
||||
public:
|
||||
// For this purpose, every interval in region is considered open on
|
||||
// the left and closed on the right.
|
||||
region_t<coord_t, dim> region;
|
||||
link_type_t type;
|
||||
AMI_bid bid;
|
||||
kdb_item_t(const region_t<coord_t, dim>& r, AMI_bid b, link_type_t t):
|
||||
region(r), bid(b), type(t) {}
|
||||
kdb_item_t() {}
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
ostream &operator<<(ostream& s, const kdb_item_t<coord_t, dim>& ki) {
|
||||
s << "[";
|
||||
for (TPIE_OS_SIZE_T i = 0; i < dim; i++) {
|
||||
if (ki.region.is_bounded_lo(i))
|
||||
s << ki.region.lo(i);
|
||||
else
|
||||
s << "-INF";
|
||||
s << " ";
|
||||
}
|
||||
for (TPIE_OS_SIZE_T i = 0; i < dim; i++) {
|
||||
if (ki.region.is_bounded_hi(i))
|
||||
s << ki.region.hi(i);
|
||||
else
|
||||
s << "INF";
|
||||
s << " ";
|
||||
}
|
||||
s << (ki.type == BLOCK_NODE ? 'N': 'L') << ki.bid;
|
||||
s << "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
template<class coord_t, TPIE_OS_SIZE_T dim>
|
||||
struct path_stack_item_t {
|
||||
kdb_item_t<coord_t, dim> item;
|
||||
TPIE_OS_SIZE_T d;
|
||||
TPIE_OS_SIZE_T el_idx; //
|
||||
path_stack_item_t(const kdb_item_t<coord_t, dim>& ki, TPIE_OS_SIZE_T di,
|
||||
TPIE_OS_SIZE_T idx = 0): item(ki), d(di), el_idx(idx) {}
|
||||
path_stack_item_t() {}
|
||||
};
|
||||
|
||||
// Kdtree status type.
|
||||
enum AMI_kdbtree_status {
|
||||
AMI_KDBTREE_STATUS_VALID = 0,
|
||||
AMI_KDBTREE_STATUS_INVALID = 1,
|
||||
AMI_KDBTREE_STATUS_KDTREE = 2, // For opening the kdb-tree as a kd-tree.
|
||||
};
|
||||
|
||||
// Split heuristics
|
||||
enum split_heuristic_t {
|
||||
CYCLICAL,
|
||||
LONGEST_SPAN,
|
||||
RANDOM,
|
||||
};
|
||||
|
||||
class AMI_kdbtree_params: public AMI_kdtree_params {
|
||||
public:
|
||||
AMI_kdbtree_params(): AMI_kdtree_params(), split_heuristic(LONGEST_SPAN) {}
|
||||
AMI_kdbtree_params(AMI_kdtree_params p): AMI_kdtree_params(p), split_heuristic(LONGEST_SPAN) {}
|
||||
split_heuristic_t split_heuristic;
|
||||
};
|
||||
|
||||
#endif // _AMI_KD_BASE_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 1995 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_key.cpp
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 3/12/95
|
||||
//
|
||||
|
||||
#include "versions.h"
|
||||
#include "ami_key.h"
|
||||
|
||||
VERSION(ami_key_cpp,"$Id: ami_key.cpp,v 1.3 2003/04/17 20:42:24 jan Exp $");
|
||||
|
||||
|
||||
key_range::key_range(kb_key min_key, kb_key max_key) {
|
||||
this->min = min_key;
|
||||
this->max = max_key;
|
||||
}
|
||||
|
||||
key_range::key_range(void) {
|
||||
this->min = 0;
|
||||
this->max = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 1995 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_key.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 3/12/95
|
||||
//
|
||||
// $Id: ami_key.h,v 1.2 2003/04/17 12:34:44 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_KEY_H
|
||||
#define _AMI_KEY_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Temporary until the configuration script is edited to determine word
|
||||
// size.
|
||||
#define UINT32 unsigned long
|
||||
|
||||
|
||||
// Radix keys are unsigned 32 bit integers.
|
||||
typedef UINT32 kb_key;
|
||||
|
||||
#define KEY_MAX 0x80000000
|
||||
#define KEY_MIN 0
|
||||
|
||||
// A range of keys. A stream having this range of keys is guarantted
|
||||
// to have no keys < min and no keys >= max.
|
||||
class key_range {
|
||||
public:
|
||||
kb_key min;
|
||||
kb_key max;
|
||||
key_range(void);
|
||||
key_range(kb_key min_key, kb_key max_key);
|
||||
};
|
||||
|
||||
#endif // _AMI_KEY_H
|
||||
@@ -0,0 +1,545 @@
|
||||
// Copyright (c) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_logmethod.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_logmethod.h,v 1.9 2005/01/21 16:55:48 tavi Exp $
|
||||
//
|
||||
// Logmethod_base, Logmethod2 and LogmethodB declarations and
|
||||
// definitions.
|
||||
//
|
||||
|
||||
#ifndef _LOGMETHOD_H
|
||||
#define _LOGMETHOD_H
|
||||
|
||||
#include <portability.h>
|
||||
|
||||
// For vector
|
||||
#include <vector>
|
||||
// For pair
|
||||
#include <utility>
|
||||
// TPIE stuff.
|
||||
#include <ami_stream.h>
|
||||
#include <ami_coll.h>
|
||||
|
||||
#include <tpie_stats_tree.h>
|
||||
|
||||
#define LM_PATH_NAME_LENGTH 128
|
||||
|
||||
template<class Tp, class T0p=Tp>
|
||||
class Logmethod_params {
|
||||
public:
|
||||
size_t cached_blocks;
|
||||
Tp tree_params;
|
||||
T0p tree0_params;
|
||||
|
||||
Logmethod_params(): cached_blocks(16), tree_params(), tree0_params() {}
|
||||
};
|
||||
|
||||
|
||||
// Requirements common to T and T0:
|
||||
// key_t [key type]
|
||||
// size_t size();
|
||||
// bool erase(const Value&);
|
||||
// bool find(const Value&);
|
||||
// size_t window_query(const Value&, const Value&, AMI_STREAM<Value>*);
|
||||
// void persist(persistence);
|
||||
// void unload(AMI_STREAM<Value>*);
|
||||
//
|
||||
// Requirements specific to T:
|
||||
// const Tp& params();
|
||||
// void load(AMI_STREAM<Value>*);
|
||||
// T(char*, AMI_collection_type, Tp);
|
||||
// ~T();
|
||||
//
|
||||
// Requirements specific to T0:
|
||||
// const T0p& params();
|
||||
// size_t os_block_count();
|
||||
// void insert(const Value&);
|
||||
// T0(char*, AMI_cllection_type, T0p);
|
||||
// ~T0();
|
||||
|
||||
template<class Key, class Value, class T, class Tp, class T0 = T, class T0p = Tp>
|
||||
class Logmethod_base {
|
||||
public:
|
||||
typedef AMI_STREAM<Value> stream_t;
|
||||
typedef Logmethod_params<Tp, T0p> params_t;
|
||||
// Delete a point.
|
||||
bool erase(const Value& p);
|
||||
// Point query.
|
||||
bool find(const Value& p);
|
||||
// Window query. Report results in stream os.
|
||||
TPIE_OS_OFFSET window_query(const Key &lop, const Key &hip, stream_t* os);
|
||||
void persist(persistence per);
|
||||
// Inquire the mbr.
|
||||
const pair<Value, Value> &mbr();
|
||||
// Inquire the size.
|
||||
TPIE_OS_OFFSET size() const { return header_.size; }
|
||||
// Inquire the run-time parameters.
|
||||
const Logmethod_params<Tp, T0p>& params() const { return params_; }
|
||||
// Inquire the statistics.
|
||||
const tpie_stats_tree &stats();
|
||||
// Destructor. Delete all trees.
|
||||
~Logmethod_base();
|
||||
|
||||
protected:
|
||||
// Constructor. Create a new struct. with the given base name for
|
||||
// all its files. Protected to avoid instantiation of this base
|
||||
// class.
|
||||
Logmethod_base(const char *base_file_name, const Logmethod_params<Tp, T0p>& params);
|
||||
|
||||
class header_type {
|
||||
public:
|
||||
TPIE_OS_OFFSET size; // The total number of elements stored in the structure.
|
||||
TPIE_OS_SIZE_T last_tree; // the index of the last tree in the trees_ vector
|
||||
header_type(): size(0), last_tree(0) {}
|
||||
};
|
||||
|
||||
// Run-time parameters.
|
||||
Logmethod_params<Tp, T0p> params_;
|
||||
// Critical information (will be written in the header of the first tree)
|
||||
header_type header_;
|
||||
// The first tree.
|
||||
T0 *tree0_;
|
||||
// The vector of trees, in increasing size.
|
||||
vector< T* > trees_;
|
||||
// The base name of all trees.
|
||||
char base_file_name_[LM_PATH_NAME_LENGTH];
|
||||
// String used for constructing tree names.
|
||||
char temp_name_[LM_PATH_NAME_LENGTH];
|
||||
// Minimum bounding rectangle.
|
||||
pair<Value, Value> mbr_;
|
||||
bool mbr_is_set_;
|
||||
// Persistence flag.
|
||||
persistence per_;
|
||||
// Statistics.
|
||||
tpie_stats_tree stats_;
|
||||
|
||||
// Create a tree name in temp_name_ from base_file_name_ and the
|
||||
// given index.
|
||||
void create_tree(size_t idx);
|
||||
};
|
||||
|
||||
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
class Logmethod2: public Logmethod_base<Key, Value, T, Tp, T0, T0p> {
|
||||
protected:
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::tree0_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::trees_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::params_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::stats_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::header_;
|
||||
|
||||
public:
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::create_tree;
|
||||
|
||||
Logmethod2(const char *base_file_name, const Logmethod_params<Tp, T0p> ¶ms);
|
||||
bool insert(const Value& p);
|
||||
};
|
||||
|
||||
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
class LogmethodB: public Logmethod_base<Key, Value, T, Tp, T0, T0p> {
|
||||
protected:
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::tree0_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::trees_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::params_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::stats_;
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::header_;
|
||||
|
||||
public:
|
||||
using Logmethod_base<Key, Value, T, Tp, T0, T0p>::create_tree;
|
||||
|
||||
LogmethodB(const char *base_file_name, const Logmethod_params<Tp, T0p> ¶ms);
|
||||
bool insert(const Value& p);
|
||||
static size_t B;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
/////////// ***Implementation*** ///////////
|
||||
////////////////////////////////////////////
|
||||
|
||||
#define LOGMETHOD_BASE Logmethod_base<Key, Value, T, Tp, T0, T0p>
|
||||
#define LOGMETHOD2 Logmethod2<Key, Value, T, Tp, T0, T0p>
|
||||
#define LOGMETHODB LogmethodB<Key, Value, T, Tp, T0, T0p>
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
///////// **Logmethod_base** //////////
|
||||
///////////////////////////////////////
|
||||
|
||||
//// *Logmethod_base::Logmethod_base* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
LOGMETHOD_BASE::Logmethod_base(const char *base_file_name,
|
||||
const Logmethod_params<Tp, T0p> ¶ms):
|
||||
header_(), params_(params), tree0_(NULL), trees_(0), per_(PERSIST_PERSISTENT), stats_() {
|
||||
|
||||
// Copy the name and make sure it has two free positions, to be
|
||||
// filled later with a unique number for each tree.
|
||||
strncpy(base_file_name_, base_file_name, LM_PATH_NAME_LENGTH - 4);
|
||||
mbr_is_set_ = false;
|
||||
strcpy(temp_name_, base_file_name_);
|
||||
|
||||
TPIE_OS_FILE_DESCRIPTOR fd; // file descriptor for the header file.
|
||||
|
||||
// Try to open header file read-only.
|
||||
if (TPIE_OS_IS_VALID_FILE_DESCRIPTOR(fd = TPIE_OS_OPEN_ORDONLY(base_file_name_))) {
|
||||
if (TPIE_OS_READ(fd, &header_, sizeof(header_)) != sizeof(header_)) {
|
||||
TP_LOG_WARNING_ID("Corrupt header file.");
|
||||
assert(0);
|
||||
}
|
||||
TPIE_OS_CLOSE(fd);
|
||||
|
||||
assert(header_.last_tree < 100);
|
||||
size_t i;
|
||||
// Initialize trees.
|
||||
for (i = 0; i <= header_.last_tree; i++) {
|
||||
trees_.insert(trees_.end(), NULL);
|
||||
create_tree(i);
|
||||
}
|
||||
// Get the real params.
|
||||
params_.tree0_params = tree0_->params();
|
||||
if (i >= 1)
|
||||
params_.tree_params = trees_[1]->params();
|
||||
} else {
|
||||
TP_LOG_APP_DEBUG_ID("Creating new logmethod structure.");
|
||||
// Bogus entry in the trees_ vector.
|
||||
trees_.insert(trees_.end(), NULL);
|
||||
// Create tree0_.
|
||||
create_tree(0);
|
||||
}
|
||||
}
|
||||
|
||||
//// *Logmethod_base::erase* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
bool LOGMETHOD_BASE::erase(const Value& p) {
|
||||
|
||||
bool ans = false;
|
||||
|
||||
if (tree0_->size() > 0 && tree0_->erase(p)) {
|
||||
ans = true;
|
||||
} else {
|
||||
for (size_t i = 1; i < trees_.size(); i++) {
|
||||
if (trees_[i]->size() > 0 && trees_[i]->erase(p)) {
|
||||
ans = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ans)
|
||||
header_.size--;
|
||||
return ans;
|
||||
}
|
||||
|
||||
//// *Logmethod_base::find* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
bool LOGMETHOD_BASE::find(const Value& p) {
|
||||
|
||||
bool ans = false;
|
||||
|
||||
// Search in all nonempty trees_.
|
||||
if (tree0_->size() > 0 && tree0_->find(p)) {
|
||||
ans = true;
|
||||
} else {
|
||||
for (size_t i = 1; i < trees_.size(); i++) {
|
||||
// Order is important! Short circuit evaluation.
|
||||
if (trees_[i]->size() > 0 && trees_[i]->find(p)) {
|
||||
ans = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
//// *Logmethod_base::window_query* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
TPIE_OS_OFFSET LOGMETHOD_BASE::window_query(const Key &lop, const Key &hip,
|
||||
AMI_STREAM<Value>* stream) {
|
||||
TPIE_OS_OFFSET result = 0;
|
||||
TPIE_OS_SIZE_T i;
|
||||
if (tree0_->size() > 0)
|
||||
result += tree0_->window_query(lop, hip, stream);
|
||||
|
||||
for (i = 1; i < trees_.size(); i++) {
|
||||
if (trees_[i]->size() > 0)
|
||||
result += trees_[i]->window_query(lop, hip, stream);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//// *Logmethod_base::persist* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
void LOGMETHOD_BASE::persist(persistence per) {
|
||||
per_ = per;
|
||||
}
|
||||
|
||||
//// *Logmethod_base::~Logmethod_base* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
LOGMETHOD_BASE::~Logmethod_base() {
|
||||
TPIE_OS_FILE_DESCRIPTOR fd;
|
||||
|
||||
if (per_ == PERSIST_PERSISTENT) {
|
||||
header_.last_tree = trees_.size() - 1;
|
||||
// Open the header file (create if not present).
|
||||
if (!TPIE_OS_IS_VALID_FILE_DESCRIPTOR(fd = TPIE_OS_OPEN_OEXCL(base_file_name_, TPIE_OS_FLAG_USE_MAPPING_FALSE))) {
|
||||
// if ((fd = open(base_file_name_, O_RDWR | O_CREAT | O_EXCL,
|
||||
// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
|
||||
|
||||
// Try again, hoping it exists.
|
||||
if (!TPIE_OS_IS_VALID_FILE_DESCRIPTOR(fd = TPIE_OS_OPEN_ORDWR(base_file_name_, TPIE_OS_FLAG_USE_MAPPING_FALSE))) {
|
||||
// if ((fd = open(base_file_name_, O_RDWR)) == -1) {
|
||||
TP_LOG_WARNING_ID("Error creating header file.");
|
||||
TP_LOG_WARNING_ID(strerror(errno));
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
TPIE_OS_WRITE(fd, &header_, sizeof(header_));
|
||||
}
|
||||
|
||||
if (TPIE_OS_CLOSE(fd)) {
|
||||
TP_LOG_FATAL_ID("Failed to close() ");
|
||||
TP_LOG_FATAL_ID(base_file_name_);
|
||||
}
|
||||
|
||||
if (per_ == PERSIST_DELETE) {
|
||||
if (TPIE_OS_UNLINK(base_file_name_)) {
|
||||
TP_LOG_FATAL_ID("Failed to unlink() ");
|
||||
TP_LOG_FATAL_ID(base_file_name_);
|
||||
}
|
||||
}
|
||||
|
||||
tree0_->persist(per_);
|
||||
delete tree0_;
|
||||
tree0_ = NULL;
|
||||
|
||||
for (size_t i = 1; i < trees_.size(); i++) {
|
||||
trees_[i]->persist(per_);
|
||||
delete trees_[i];
|
||||
trees_[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//// *Logmethod_base::mbr* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
const pair<Value, Value>& LOGMETHOD_BASE::mbr() {
|
||||
size_t i;
|
||||
if (!mbr_is_set_) {
|
||||
if (tree0_->size() > 0) {
|
||||
if (mbr_is_set_) {
|
||||
mbr_.first.set_min(tree0_->mbr().first);
|
||||
mbr_.second.set_max(tree0_->mbr().second);
|
||||
} else {
|
||||
mbr_.first = tree0_->mbr().first;
|
||||
mbr_.second = tree0_->mbr().second;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < trees_.size(); i++) {
|
||||
if (trees_[i]->size() > 0) {
|
||||
if (mbr_is_set_) {
|
||||
mbr_.first.set_min(trees_[i]->mbr().first);
|
||||
mbr_.second.set_max(trees_[i]->mbr().second);
|
||||
} else {
|
||||
mbr_.first = trees_[i]->mbr().first;
|
||||
mbr_.second = trees_[i]->mbr().second;
|
||||
}
|
||||
}
|
||||
}
|
||||
mbr_is_set_ = true;
|
||||
}
|
||||
return mbr_;
|
||||
}
|
||||
|
||||
//// *Logmethod_base::create_tree* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
void LOGMETHOD_BASE::create_tree(TPIE_OS_SIZE_T idx) {
|
||||
TPIE_OS_SIZE_T i = strlen(base_file_name_);
|
||||
temp_name_[i ] = '0' + (char)((idx/10) % 10);
|
||||
temp_name_[i+1] = '0' + (char)(idx % 10);
|
||||
temp_name_[i+2] = '\0';
|
||||
if (idx == 0) {
|
||||
if (sizeof(T0p) == 0)
|
||||
tree0_ = new T0(temp_name_, AMI_WRITE_COLLECTION);
|
||||
else
|
||||
tree0_ = new T0(temp_name_, AMI_WRITE_COLLECTION,
|
||||
params_.tree0_params);
|
||||
} else {
|
||||
if (sizeof(Tp) == 0)
|
||||
trees_[idx] = new T(temp_name_, AMI_WRITE_COLLECTION);
|
||||
else
|
||||
trees_[idx] = new T(temp_name_, AMI_WRITE_COLLECTION,
|
||||
params_.tree_params);
|
||||
}
|
||||
}
|
||||
|
||||
//// *Logmethod_base::stats* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
const tpie_stats_tree &LOGMETHOD_BASE::stats() {
|
||||
for (int i = 1; i < trees_.size(); i++) {
|
||||
if (trees_[i]->size() > 0)
|
||||
stats_.record(trees_[i]->stats());
|
||||
}
|
||||
return stats_;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
/////////// **Logmethod2** ////////////
|
||||
///////////////////////////////////////
|
||||
|
||||
|
||||
//// *Logmethod2::Logmethod2* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
LOGMETHOD2::Logmethod2(const char* base_file_name,
|
||||
const Logmethod_params<Tp, T0p> ¶ms):
|
||||
Logmethod_base<Key, Value, T, Tp, T0, T0p>(base_file_name, params) {
|
||||
}
|
||||
|
||||
//// *Logmethod2::insert* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
bool LOGMETHOD2::insert(const Value& p) {
|
||||
|
||||
assert(tree0_ != NULL);
|
||||
|
||||
if (tree0_->os_block_count() < params_.cached_blocks) {
|
||||
|
||||
// tree0_ must have insert capabilities, ie, the T0 class
|
||||
// must have insert capabilities.
|
||||
tree0_->insert(p);
|
||||
|
||||
} else {
|
||||
// cout << "trees_[0]->os_block_count(): " << trees_[0]->os_block_count() << endl;
|
||||
// cout << " leaf_count: " << trees_[0]->leaf_count()
|
||||
// << " node_count: " << trees_[0]->node_count() << endl;
|
||||
// cout << "trees_[0]->size(): " << trees_[0]->size() << endl;
|
||||
// cout << " node_cache_size: " << trees_[0]->params().node_cache_size
|
||||
// << " leaf_cache_size: " << trees_[0]->params().leaf_cache_size << endl;
|
||||
|
||||
// First unload all relevant trees to a stream.
|
||||
|
||||
typename LOGMETHOD_BASE::stream_t *stream = new typename LOGMETHOD_BASE::stream_t;
|
||||
stream->persist(PERSIST_DELETE);
|
||||
|
||||
tree0_->unload(stream);
|
||||
tree0_->persist(PERSIST_DELETE);
|
||||
delete tree0_;
|
||||
/// create_tree(0);
|
||||
|
||||
// Free index. The index of the first empty tree.
|
||||
size_t fi = 1;
|
||||
while (fi < trees_.size() && trees_[fi]->size() > 0) {
|
||||
trees_[fi]->unload(stream);
|
||||
trees_[fi]->persist(PERSIST_DELETE);
|
||||
stats_.record(trees_[fi]->stats());
|
||||
delete trees_[fi];
|
||||
/// create_tree(fi);
|
||||
fi++;
|
||||
}
|
||||
|
||||
// Add a new tree position if necessary (ie, no empty tree found).
|
||||
if (fi == trees_.size()) {
|
||||
trees_.insert(trees_.end(), NULL);
|
||||
create_tree(fi);
|
||||
}
|
||||
|
||||
assert(trees_[fi]->size() == 0);
|
||||
|
||||
// Write the new guy.
|
||||
stream->write_item(p);
|
||||
|
||||
// Create a new tree from stream.
|
||||
trees_[fi]->load(stream);
|
||||
delete stream;
|
||||
|
||||
// Create empty trees in positions 0 to fi-1.
|
||||
for (int ii = 0; ii < fi; ii++)
|
||||
create_tree(ii);
|
||||
}
|
||||
|
||||
header_.size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
/////////// **LogmethodB** /////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
//// *LogmethodB::LogmethodB* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
LOGMETHODB::LogmethodB(const char* base_file_name,
|
||||
const Logmethod_params<Tp, T0p> ¶ms):
|
||||
Logmethod_base<Key, Value, T, Tp, T0, T0p>(base_file_name, params) {
|
||||
}
|
||||
|
||||
//// *LogmethodB::insert* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
bool LOGMETHODB::insert(const Value& p) {
|
||||
|
||||
assert(tree0_ != NULL);
|
||||
|
||||
// Check whether the cached block is full.
|
||||
if (tree0_->os_block_count() < params_.cached_blocks) {
|
||||
|
||||
tree0_->insert(p);
|
||||
|
||||
} else {
|
||||
|
||||
size_t fi;
|
||||
typename LOGMETHOD_BASE::stream_t *stream = new typename LOGMETHOD_BASE::stream_t;
|
||||
stream->persist(PERSIST_DELETE);
|
||||
|
||||
tree0_->unload(stream);
|
||||
tree0_->persist(PERSIST_DELETE);
|
||||
delete tree0_;
|
||||
|
||||
// Write the new guy.
|
||||
stream->write_item(p);
|
||||
|
||||
// Now unload all relevant trees to stream.
|
||||
fi = 0;
|
||||
TPIE_OS_OFFSET b_to_fi = stream->stream_len();
|
||||
|
||||
while (stream->stream_len() >= b_to_fi) {
|
||||
fi++;
|
||||
b_to_fi *= B;
|
||||
|
||||
if (fi == trees_.size())
|
||||
break;
|
||||
|
||||
if (trees_[fi]->size() > 0) {
|
||||
trees_[fi]->unload(stream);
|
||||
trees_[fi]->persist(PERSIST_DELETE);
|
||||
stats_.record(trees_[fi]->stats());
|
||||
delete trees_[fi];
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new tree position if necessary.
|
||||
if (fi == trees_.size()) {
|
||||
trees_.insert(trees_.end(), NULL);
|
||||
}
|
||||
|
||||
create_tree(fi);
|
||||
|
||||
assert(trees_[fi] != NULL);
|
||||
|
||||
trees_[fi]->load(stream);
|
||||
|
||||
for (int ii = 0; ii < fi; ii++)
|
||||
create_tree(ii);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
header_.size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//// *LogmethodB::B* ////
|
||||
template<class Key, class Value, class T, class Tp, class T0, class T0p>
|
||||
size_t LOGMETHODB::B = 100;
|
||||
|
||||
#endif // _LOGMETHOD_H
|
||||
@@ -0,0 +1,519 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_matrix.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/9/94
|
||||
//
|
||||
// $Id: ami_matrix.h,v 1.14 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_MATRIX_H
|
||||
#define _AMI_MATRIX_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
//#define QUICK_MATRIX_MULT 1
|
||||
#define AGGARWAL_MATRIX_MULT 1
|
||||
|
||||
#define INTERNAL_TIMING 1
|
||||
|
||||
#ifdef INTERNAL_TIMING
|
||||
# include <cpu_timer.h>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include <matrix.h>
|
||||
|
||||
#include <ami_matrix_pad.h>
|
||||
#include <ami_matrix_blocks.h>
|
||||
#include <ami_stream_arith.h>
|
||||
|
||||
#include <ami_gen_perm.h>
|
||||
|
||||
template<class T>
|
||||
class AMI_matrix : public AMI_STREAM<T> {
|
||||
private:
|
||||
TPIE_OS_OFFSET r,c;
|
||||
public:
|
||||
AMI_matrix(TPIE_OS_OFFSET row, TPIE_OS_OFFSET col);
|
||||
~AMI_matrix(void);
|
||||
TPIE_OS_OFFSET rows();
|
||||
TPIE_OS_OFFSET cols();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_matrix<T>::AMI_matrix(TPIE_OS_OFFSET row, TPIE_OS_OFFSET col) :
|
||||
r(row), c(col), AMI_STREAM<T>()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_matrix<T>::~AMI_matrix(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET AMI_matrix<T>::rows(void)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET AMI_matrix<T>::cols(void)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
// Add two matrices.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_add(AMI_matrix<T> &op1, AMI_matrix<T> &op2,
|
||||
AMI_matrix<T> &res)
|
||||
{
|
||||
AMI_scan_add<T> sa;
|
||||
|
||||
// We should do some bound checking here.
|
||||
|
||||
return AMI_scan((AMI_STREAM<T> *)&op1, (AMI_STREAM<T> *)&op2,
|
||||
&sa, (AMI_STREAM<T> *)&res);
|
||||
}
|
||||
|
||||
// Subtract.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_sub(AMI_matrix<T> &op1, AMI_matrix<T> &op2,
|
||||
AMI_matrix<T> &res)
|
||||
{
|
||||
AMI_scan_sub<T> ss;
|
||||
|
||||
// We should do some bound checking here.
|
||||
|
||||
return AMI_scan((AMI_STREAM<T> *)&op1, (AMI_STREAM<T> *)&op2,
|
||||
&ss, (AMI_STREAM<T> *)&res);
|
||||
}
|
||||
|
||||
|
||||
// Matrix multiply.
|
||||
|
||||
// For standard (non-Strassen) matrix multiply, there are at least two
|
||||
// algorithms with the same asymptotic complexity. There is the 4 way
|
||||
// divide and conquer algorithms of Vitter and Shriver and there is
|
||||
// the technique which divides the matrix into blocks of size
|
||||
// $sqrt(M/B) \times sqrt(M/B)$. The latter has a smaller constant and is
|
||||
// simpler to implement, so we chose to use it.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_mult(AMI_matrix<T> &op1, AMI_matrix<T> &op2,
|
||||
AMI_matrix<T> &res)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
TPIE_OS_SIZE_T sz_avail;
|
||||
TPIE_OS_SIZE_T mm_matrix_extent;
|
||||
TPIE_OS_SIZE_T single_stream_usage;
|
||||
|
||||
// Check bounds on the matrices to make sure they match up.
|
||||
if ((op1.cols() != op2.rows()) || (res.rows() != op1.rows()) ||
|
||||
(res.cols() != op2.cols())) {
|
||||
return AMI_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
// Check available main memory.
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// How much memory does a single streamneed in the worst case?
|
||||
|
||||
if ((ae = op1.main_memory_usage(&single_stream_usage,
|
||||
MM_STREAM_USAGE_MAXIMUM)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Will the problem fit in main memory?
|
||||
|
||||
{
|
||||
TPIE_OS_OFFSET sz_op1 = op1.rows() * op1.cols() * sizeof(T);
|
||||
TPIE_OS_OFFSET sz_op2 = op2.rows() * op2.cols() * sizeof(T);
|
||||
TPIE_OS_OFFSET sz_res = res.rows() * res.cols() * sizeof(T);
|
||||
|
||||
if (sz_avail > sz_op1 + sz_op2 + sz_res + 3 * single_stream_usage +
|
||||
3 * sizeof(matrix<T>)) {
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
T *tmp_read;
|
||||
|
||||
// Main memory copies of the matrices.
|
||||
matrix<T> mm_op1((TPIE_OS_SIZE_T)op1.rows(), (TPIE_OS_SIZE_T)op1.cols());
|
||||
matrix<T> mm_op2((TPIE_OS_SIZE_T)op2.rows(), (TPIE_OS_SIZE_T)op2.cols());
|
||||
matrix<T> mm_res((TPIE_OS_SIZE_T)res.rows(), (TPIE_OS_SIZE_T)res.cols());
|
||||
|
||||
// Read in the matrices and solve in main memory.
|
||||
|
||||
op1.seek(0);
|
||||
for (ii = 0; ii < op1.rows(); ii++ ) {
|
||||
for (jj = 0; jj < op1.cols(); jj++ ) {
|
||||
ae = op1.read_item(&tmp_read);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
mm_op1[ii][jj] = *tmp_read;
|
||||
}
|
||||
}
|
||||
|
||||
op2.seek(0);
|
||||
for (ii = 0; ii < op2.rows(); ii++ ) {
|
||||
for (jj = 0; jj < op2.cols(); jj++ ) {
|
||||
ae = op2.read_item(&tmp_read);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
mm_op2[ii][jj] = *tmp_read;
|
||||
}
|
||||
}
|
||||
|
||||
#if QUICK_MATRIX_MULT
|
||||
quick_matrix_mult_in_place(mm_op1, mm_op2, mm_res);
|
||||
#elif defined(AGGARWAL_MATRIX_MULT)
|
||||
aggarwal_matrix_mult_in_place(mm_op1, mm_op2, mm_res);
|
||||
#else
|
||||
perform_mult_in_place((matrix_base<T> &)mm_op1,
|
||||
(matrix_base<T> &)mm_op2,
|
||||
(matrix_base<T> &)mm_res);
|
||||
#endif
|
||||
|
||||
// Write out the result.
|
||||
res.seek(0);
|
||||
for (ii = 0; ii < res.rows(); ii++ ) {
|
||||
for (jj = 0; jj < res.cols(); jj++ ) {
|
||||
ae = res.write_item(mm_res[ii][jj]);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We now know the problem does not fit in main memory.
|
||||
|
||||
{
|
||||
|
||||
TPIE_OS_SIZE_T num_active_streams = 4 + 4;
|
||||
TPIE_OS_SIZE_T mm_matrix_space;
|
||||
TPIE_OS_SIZE_T single_stream_usage;
|
||||
|
||||
// What is the maximum extent of any matrix we will try to
|
||||
// load into memory? We may have up to four in memory at any
|
||||
// given time. To be safe, let each one have a stream behind
|
||||
// it and let there be some additional active streams such as
|
||||
// ....
|
||||
|
||||
if ((ae = op1.main_memory_usage(&single_stream_usage,
|
||||
MM_STREAM_USAGE_MAXIMUM)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
mm_matrix_space = sz_avail - num_active_streams * single_stream_usage;
|
||||
|
||||
mm_matrix_space /= 3;
|
||||
|
||||
#ifdef AGGARWAL_MATRIX_MULT_IN_PLACE
|
||||
// Recall that a temporary vector is used, so we solve x^2 + x = m
|
||||
// for x, instead of the usual x^2 = m.
|
||||
mm_matrix_extent = (TPIE_OS_SIZE_T)(sqrt(1.0 +
|
||||
4 * (double)mm_matrix_space /
|
||||
sizeof(T)) / 2) - 1;
|
||||
#else
|
||||
mm_matrix_extent = (TPIE_OS_SIZE_T)sqrt((double)mm_matrix_space /
|
||||
sizeof(T));
|
||||
#endif
|
||||
// How many rows and columns of chunks in each matrix?
|
||||
|
||||
TPIE_OS_OFFSET chunkrows1 = ((op1.rows() - 1) /
|
||||
mm_matrix_extent) + 1;
|
||||
TPIE_OS_OFFSET chunkcols1 = ((op1.cols() - 1) /
|
||||
mm_matrix_extent) + 1;
|
||||
TPIE_OS_OFFSET chunkrows2 = ((op2.rows() - 1) /
|
||||
mm_matrix_extent) + 1;
|
||||
TPIE_OS_OFFSET chunkcols2 = ((op2.cols() - 1) /
|
||||
mm_matrix_extent) + 1;
|
||||
|
||||
// Now shrink the main memory matrix extent as much as possible
|
||||
// given the constraint that the number of chunk rows and cols
|
||||
// in each matrix cannot decrease.
|
||||
|
||||
TPIE_OS_SIZE_T min_rows_per_chunk1 = (TPIE_OS_SIZE_T)((op1.rows() + chunkrows1 - 1) /
|
||||
chunkrows1);
|
||||
TPIE_OS_SIZE_T min_cols_per_chunk1 = (TPIE_OS_SIZE_T)((op1.cols() + chunkcols1 - 1) /
|
||||
chunkcols1);
|
||||
|
||||
TPIE_OS_SIZE_T min_rows_per_chunk2 = (TPIE_OS_SIZE_T)((op2.rows() + chunkrows2 - 1) /
|
||||
chunkrows2);
|
||||
TPIE_OS_SIZE_T min_cols_per_chunk2 = (TPIE_OS_SIZE_T)((op2.cols() + chunkcols2 - 1) /
|
||||
chunkcols2);
|
||||
|
||||
// Adjust the main memory matrix extent so that an integral
|
||||
// multiple of it is just a little bit larger than the inputs.
|
||||
|
||||
// Note that we are still assuming square chunks. We can do
|
||||
// better than this in some cases if we are willing to allow
|
||||
// non-square matrices.
|
||||
|
||||
mm_matrix_extent = min_rows_per_chunk1;
|
||||
if (mm_matrix_extent < min_rows_per_chunk2)
|
||||
mm_matrix_extent = min_rows_per_chunk2;
|
||||
if (mm_matrix_extent < min_cols_per_chunk1)
|
||||
mm_matrix_extent = min_cols_per_chunk1;
|
||||
if (mm_matrix_extent < min_cols_per_chunk2)
|
||||
mm_matrix_extent = min_cols_per_chunk2;
|
||||
|
||||
// How many rows and cols in padded matrices.
|
||||
|
||||
TPIE_OS_OFFSET rowsp1 = mm_matrix_extent * (((op1.rows() - 1) /
|
||||
mm_matrix_extent) + 1);
|
||||
TPIE_OS_OFFSET colsp1 = mm_matrix_extent * (((op1.cols() - 1) /
|
||||
mm_matrix_extent) + 1);
|
||||
|
||||
TPIE_OS_OFFSET rowsp2 = mm_matrix_extent * (((op2.rows() - 1) /
|
||||
mm_matrix_extent) + 1);
|
||||
TPIE_OS_OFFSET colsp2 = mm_matrix_extent * (((op2.cols() - 1) /
|
||||
mm_matrix_extent) + 1);
|
||||
|
||||
|
||||
// Padded matrices.
|
||||
|
||||
AMI_matrix<T> *op1p = new AMI_matrix<T>(rowsp1, colsp1);
|
||||
AMI_matrix<T> *op2p = new AMI_matrix<T>(rowsp2, colsp2);
|
||||
|
||||
// Scan each matrix to pad it out with zeroes as needed.
|
||||
|
||||
{
|
||||
AMI_matrix_pad<T> smp1(op1.rows(), op1.cols(), mm_matrix_extent);
|
||||
AMI_matrix_pad<T> smp2(op2.rows(), op2.cols(), mm_matrix_extent);
|
||||
|
||||
ae = AMI_scan((AMI_STREAM<T> *)&op1, &smp1,
|
||||
(AMI_STREAM<T> *)op1p);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
ae = AMI_scan((AMI_STREAM<T> *)&op2, &smp2,
|
||||
(AMI_STREAM<T> *)op2p);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
// Permuted padded matrices.
|
||||
|
||||
AMI_matrix<T> *op1pp = new AMI_matrix<T>(rowsp1, colsp1);
|
||||
AMI_matrix<T> *op2pp = new AMI_matrix<T>(rowsp2, colsp2);
|
||||
|
||||
AMI_matrix<T> *respp = new AMI_matrix<T>(rowsp1, colsp2);
|
||||
|
||||
// Permute each padded matrix into block order. The blocks
|
||||
// are in row major order and the elements within the blocks
|
||||
// are in row major order.
|
||||
|
||||
{
|
||||
perm_matrix_into_blocks pmib1(rowsp1, colsp1, mm_matrix_extent);
|
||||
perm_matrix_into_blocks pmib2(rowsp2, colsp2, mm_matrix_extent);
|
||||
|
||||
ae = AMI_general_permute((AMI_STREAM<T> *)op1p,
|
||||
(AMI_STREAM<T> *)op1pp,
|
||||
(AMI_gen_perm_object *)&pmib1);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = AMI_general_permute((AMI_STREAM<T> *)op2p,
|
||||
(AMI_STREAM<T> *)op2pp,
|
||||
(AMI_gen_perm_object *)&pmib2);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
// We are done with the padded but unpermuted matrices.
|
||||
|
||||
delete op1p;
|
||||
delete op2p;
|
||||
|
||||
#ifdef INTERNAL_TIMING
|
||||
|
||||
cpu_timer cput_internal;
|
||||
|
||||
cput_internal.reset();
|
||||
cput_internal.start();
|
||||
|
||||
#endif
|
||||
|
||||
// Now run the standard matrix multiplication algorithm over
|
||||
// the blocks. To multiply two blocks, we read them into main
|
||||
// memory. The blocks of the result are accumulated one by
|
||||
// one in main memory and then written out.
|
||||
|
||||
{
|
||||
|
||||
//Sometimes the mm_matrix_extent value is such that
|
||||
//it is too large for the available amount of memory
|
||||
//to permit the allocation for the matrices below. I suspect
|
||||
//that there is a bug in the way mm_matrix_extent is assigned
|
||||
//a value; sz_avail needs to be correctly taken into account.
|
||||
//But the bug doesn't always take place. Need looking at.
|
||||
//--Rakesh on mm_matrix_extent.
|
||||
|
||||
matrix<T> mm_op1(mm_matrix_extent, mm_matrix_extent);
|
||||
matrix<T> mm_op2(mm_matrix_extent, mm_matrix_extent);
|
||||
matrix<T> mm_accum(mm_matrix_extent, mm_matrix_extent);
|
||||
|
||||
TPIE_OS_OFFSET ii,jj,kk;
|
||||
T *tmp_read;
|
||||
|
||||
respp->seek(0);
|
||||
|
||||
// ii loops over block rows of op1pp.
|
||||
|
||||
for (ii = 0; ii < rowsp1 / mm_matrix_extent; ii++ ) {
|
||||
|
||||
// jj loops over block cols of op2pp.
|
||||
|
||||
for (jj = 0; jj < colsp2 / mm_matrix_extent; jj++ ) {
|
||||
|
||||
// These are for looping over rows and cols of MM
|
||||
// matrices.
|
||||
TPIE_OS_SIZE_T ii1,jj1;
|
||||
|
||||
// Clear the temporary result.
|
||||
for (ii1 = 0; ii1 < mm_matrix_extent; ii1++ ) {
|
||||
for (jj1 = 0; jj1 < mm_matrix_extent; jj1++ ) {
|
||||
mm_accum[ii1][jj1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// kk loops over the cols of op1pp and rows of
|
||||
// op2pp at the same time.
|
||||
|
||||
tp_assert(rowsp2 == colsp1, "Matrix extent mismatch.");
|
||||
|
||||
for (kk = 0; kk < rowsp2 / mm_matrix_extent; kk++ ) {
|
||||
|
||||
// Read a block from op1pp.
|
||||
|
||||
op1pp->seek(ii * colsp1 * mm_matrix_extent +
|
||||
kk * mm_matrix_extent * mm_matrix_extent);
|
||||
|
||||
for (ii1 = 0; ii1 < mm_matrix_extent; ii1++ ) {
|
||||
for (jj1 = 0; jj1 < mm_matrix_extent; jj1++ ) {
|
||||
ae = op1pp->read_item(&tmp_read);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
mm_op1[ii1][jj1] = *tmp_read;
|
||||
}
|
||||
}
|
||||
|
||||
// Read a block from op2pp.
|
||||
|
||||
op2pp->seek(kk * colsp2 * mm_matrix_extent +
|
||||
jj * mm_matrix_extent * mm_matrix_extent);
|
||||
|
||||
for (ii1 = 0; ii1 < mm_matrix_extent; ii1++ ) {
|
||||
for (jj1 = 0; jj1 < mm_matrix_extent; jj1++ ) {
|
||||
ae = op2pp->read_item(&tmp_read);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
mm_op2[ii1][jj1] = *tmp_read;
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply in MM and add to the running sum.
|
||||
|
||||
#if QUICK_MATRIX_MULT
|
||||
quick_matrix_mult_add_in_place(mm_op1, mm_op2,
|
||||
mm_accum);
|
||||
#elif defined(AGGARWAL_MATRIX_MULT)
|
||||
aggarwal_matrix_mult_add_in_place(mm_op1, mm_op2,
|
||||
mm_accum);
|
||||
#else
|
||||
perform_mult_add_in_place((matrix_base<T> &)mm_op1,
|
||||
(matrix_base<T> &)mm_op2,
|
||||
(matrix_base<T> &)mm_accum);
|
||||
#endif
|
||||
}
|
||||
|
||||
// We now have the complete result for a block of
|
||||
// respp, so write it out.
|
||||
|
||||
for (ii1 = 0; ii1 < mm_matrix_extent; ii1++ ) {
|
||||
for (jj1 = 0; jj1 < mm_matrix_extent; jj1++ ) {
|
||||
ae = respp->write_item(mm_accum[ii1][jj1]);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INTERNAL_TIMING
|
||||
|
||||
cput_internal.stop();
|
||||
cout << cput_internal << ' ';
|
||||
|
||||
#endif
|
||||
|
||||
// We are done with the padded and permuted operators.
|
||||
|
||||
delete op1pp;
|
||||
delete op2pp;
|
||||
|
||||
// Permute the result from scan block order back into row
|
||||
// major order.
|
||||
|
||||
AMI_matrix<T> *resp = new AMI_matrix<T>(rowsp1, colsp2);
|
||||
|
||||
{
|
||||
perm_matrix_outof_blocks pmob(rowsp1, colsp1, mm_matrix_extent);
|
||||
|
||||
ae = AMI_general_permute((AMI_STREAM<T> *)respp,
|
||||
(AMI_STREAM<T> *)resp,
|
||||
(AMI_gen_perm_object *)&pmob);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
// We are done with the padded and permuted result.
|
||||
|
||||
delete respp;
|
||||
|
||||
// Scan to strip the padding from the output matrix.
|
||||
|
||||
{
|
||||
AMI_matrix_unpad<T> smup(op1.rows(), op2.cols(),
|
||||
mm_matrix_extent);
|
||||
|
||||
ae = AMI_scan((AMI_STREAM<T> *)resp, &smup,
|
||||
(AMI_STREAM<T> *)&res);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We are done with the padded but unpermuted result.
|
||||
|
||||
delete resp;
|
||||
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#endif // _AMI_MATRIX_H
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// File: ami_matrix_blocks.cpp
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/11/94
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(ami_matrix_blocks_cpp,"$Id: ami_matrix_blocks.cpp,v 1.6 2004/08/12 12:53:42 jan Exp $");
|
||||
#include "lib_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ami_err.h>
|
||||
#include <ami_gen_perm_object.h>
|
||||
#include <ami_matrix_blocks.h>
|
||||
|
||||
perm_matrix_into_blocks::perm_matrix_into_blocks(TPIE_OS_OFFSET rows,
|
||||
TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent) :
|
||||
r(rows),
|
||||
c(cols),
|
||||
be(block_extent)
|
||||
{
|
||||
}
|
||||
|
||||
perm_matrix_into_blocks::~perm_matrix_into_blocks()
|
||||
{
|
||||
}
|
||||
|
||||
AMI_err perm_matrix_into_blocks::initialize(TPIE_OS_OFFSET len)
|
||||
{
|
||||
return static_cast<TPIE_OS_OUTPUT_SIZE_T>( (r * c) == len) ? AMI_ERROR_NO_ERROR : AMI_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
TPIE_OS_OFFSET perm_matrix_into_blocks::destination(TPIE_OS_OFFSET source)
|
||||
{
|
||||
tp_assert(r % be == 0, "Rows not a multiple of block extent.");
|
||||
tp_assert(c % be == 0, "Cols not a multiple of block extent.");
|
||||
|
||||
// What row and column are the source in?
|
||||
|
||||
TPIE_OS_OFFSET src_row = source / c;
|
||||
TPIE_OS_OFFSET src_col = source % c;
|
||||
|
||||
// How many rows of blocks come before the one the source is in?
|
||||
|
||||
TPIE_OS_OFFSET src_brow = src_row / be;
|
||||
|
||||
// How many blocks in the row of blocks that the source is in come
|
||||
// before the block the source is in?
|
||||
|
||||
TPIE_OS_OFFSET src_bcol = src_col / be;
|
||||
|
||||
// Number of objects in block rows above.
|
||||
|
||||
TPIE_OS_OFFSET obj_b_above = src_brow * be * c;
|
||||
|
||||
// Number of objects in blocks in the same block row before it.
|
||||
|
||||
TPIE_OS_OFFSET obj_b_left = src_bcol * be * be;
|
||||
|
||||
// Position in block
|
||||
|
||||
TPIE_OS_OFFSET bpos = (src_row - be * src_brow) * be +
|
||||
(src_col - be * src_bcol);
|
||||
|
||||
return obj_b_above + obj_b_left + bpos;
|
||||
}
|
||||
|
||||
|
||||
perm_matrix_outof_blocks::perm_matrix_outof_blocks(TPIE_OS_OFFSET rows,
|
||||
TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent) :
|
||||
r(rows),
|
||||
c(cols),
|
||||
be(block_extent)
|
||||
{
|
||||
}
|
||||
|
||||
perm_matrix_outof_blocks::~perm_matrix_outof_blocks()
|
||||
{
|
||||
}
|
||||
|
||||
AMI_err perm_matrix_outof_blocks::initialize(TPIE_OS_OFFSET len)
|
||||
{
|
||||
return static_cast<TPIE_OS_OUTPUT_SIZE_T>( (r * c) == len) ? AMI_ERROR_NO_ERROR : AMI_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
TPIE_OS_OFFSET perm_matrix_outof_blocks::destination(TPIE_OS_OFFSET source)
|
||||
{
|
||||
tp_assert(r % be == 0, "Rows not a multiple of block extent.");
|
||||
tp_assert(c % be == 0, "Cols not a multiple of block extent.");
|
||||
|
||||
// How many full blocks come before source?
|
||||
|
||||
TPIE_OS_OFFSET src_blocks_before = source / (be * be);
|
||||
|
||||
// How many rows of blocks are above the block source is in?
|
||||
|
||||
TPIE_OS_OFFSET src_brow = src_blocks_before / (c / be);
|
||||
|
||||
// How many blocks in the current row are before the block src is in?
|
||||
|
||||
TPIE_OS_OFFSET src_bleft = src_blocks_before % (c / be);
|
||||
|
||||
// What is the position of source in its block?
|
||||
|
||||
TPIE_OS_OFFSET src_pos_in_block = source % (be * be);
|
||||
|
||||
// What is the row of the source in its block?
|
||||
|
||||
TPIE_OS_OFFSET src_row_in_block = src_pos_in_block / be;
|
||||
|
||||
// What is the col of the source in its block?
|
||||
|
||||
TPIE_OS_OFFSET src_col_in_block = src_pos_in_block % be;
|
||||
|
||||
// Number of items in block rows above src.
|
||||
|
||||
TPIE_OS_OFFSET items_brow_above = src_brow * c * be;
|
||||
|
||||
// Number of items in the current block row above src.
|
||||
|
||||
TPIE_OS_OFFSET items_curr_brow_above = src_row_in_block * c;
|
||||
|
||||
// Number of items in item row to left of source.
|
||||
|
||||
TPIE_OS_OFFSET items_left_in_row = (src_bleft * be) + src_col_in_block;
|
||||
|
||||
// Add up everything before it.
|
||||
|
||||
return items_brow_above + items_curr_brow_above + items_left_in_row;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_matrix_blocks.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/11/94
|
||||
//
|
||||
// $Id: ami_matrix_blocks.h,v 1.4 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_MATRIX_BLOCKS_H
|
||||
#define _AMI_MATRIX_BLOCKS_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get AMI_gen_perm_object.
|
||||
#include <ami_gen_perm_object.h>
|
||||
|
||||
class perm_matrix_into_blocks : public AMI_gen_perm_object {
|
||||
private:
|
||||
TPIE_OS_OFFSET r,c,be;
|
||||
public:
|
||||
perm_matrix_into_blocks(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent);
|
||||
virtual ~perm_matrix_into_blocks();
|
||||
AMI_err initialize(TPIE_OS_OFFSET len);
|
||||
TPIE_OS_OFFSET destination(TPIE_OS_OFFSET source);
|
||||
};
|
||||
|
||||
class perm_matrix_outof_blocks : public AMI_gen_perm_object {
|
||||
private:
|
||||
TPIE_OS_OFFSET r,c,be;
|
||||
public:
|
||||
perm_matrix_outof_blocks(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent);
|
||||
virtual ~perm_matrix_outof_blocks();
|
||||
AMI_err initialize(TPIE_OS_OFFSET len);
|
||||
TPIE_OS_OFFSET destination(TPIE_OS_OFFSET source);
|
||||
};
|
||||
|
||||
|
||||
#endif // _AMI_MATRIX_BLOCKS_H
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_matrix_fill.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/12/94
|
||||
//
|
||||
// $Id: ami_matrix_fill.h,v 1.7 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_MATRIX_FILL_H
|
||||
#define _AMI_MATRIX_FILL_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the AMI_scan_object definition.
|
||||
#include <ami_scan.h>
|
||||
|
||||
template<class T>
|
||||
class AMI_matrix_filler {
|
||||
public:
|
||||
virtual AMI_err initialize(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols) = 0;
|
||||
virtual T element(TPIE_OS_OFFSET row, TPIE_OS_OFFSET col) = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class AMI_matrix_fill_scan : AMI_scan_object {
|
||||
private:
|
||||
TPIE_OS_OFFSET r, c;
|
||||
TPIE_OS_OFFSET cur_row, cur_col;
|
||||
AMI_matrix_filler<T> *pemf;
|
||||
public:
|
||||
AMI_matrix_fill_scan(AMI_matrix_filler<T> *pem_filler,
|
||||
TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols) :
|
||||
r(rows), c(cols),
|
||||
pemf(pem_filler)
|
||||
{
|
||||
};
|
||||
AMI_err initialize(void)
|
||||
{
|
||||
cur_row = cur_col = 0;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
};
|
||||
AMI_err operate(T *out, AMI_SCAN_FLAG *sf)
|
||||
{
|
||||
if ((*sf = (cur_row < r))) {
|
||||
*out = pemf->element(cur_row,cur_col);
|
||||
if (!(cur_col = (cur_col+1) % c)) {
|
||||
cur_row++;
|
||||
}
|
||||
return AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_fill(AMI_matrix<T> *pem, AMI_matrix_filler<T> *pemf)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
ae = pemf->initialize(pem->rows(), pem->cols());
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
AMI_matrix_fill_scan<T> emfs(pemf, pem->rows(), pem->cols());
|
||||
|
||||
return AMI_scan(&emfs, (AMI_STREAM<T> *)pem);
|
||||
};
|
||||
|
||||
#endif // _AMI_MATRIX_FILL_H
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_matrix_pad.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/11/94
|
||||
//
|
||||
// $Id: ami_matrix_pad.h,v 1.8 2004/08/12 12:35:30 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_MATRIX_PAD_H
|
||||
#define _AMI_MATRIX_PAD_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get definition of AMI_scan_object class.
|
||||
#include <ami_scan.h>
|
||||
|
||||
// This is a scan management object designed to pad a rows by cols
|
||||
// matrix with zeroes so that is becomes an (i * block_extent) by (j *
|
||||
// block_extent) matrix where i and j are integers as small as
|
||||
// possible.
|
||||
|
||||
template<class T>
|
||||
class AMI_matrix_pad : AMI_scan_object {
|
||||
private:
|
||||
TPIE_OS_OFFSET cur_row, cur_col;
|
||||
TPIE_OS_OFFSET orig_rows, orig_cols;
|
||||
TPIE_OS_OFFSET final_rows, final_cols;
|
||||
public:
|
||||
AMI_matrix_pad(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent);
|
||||
virtual ~AMI_matrix_pad();
|
||||
AMI_err initialize(void);
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_matrix_pad<T>::AMI_matrix_pad(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent)
|
||||
|
||||
{
|
||||
orig_rows = rows;
|
||||
orig_cols = cols;
|
||||
final_rows = block_extent * (((orig_rows - 1) / block_extent) + 1);
|
||||
final_cols = block_extent * (((orig_cols - 1) / block_extent) + 1);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_matrix_pad<T>::~AMI_matrix_pad()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_pad<T>::initialize(void)
|
||||
{
|
||||
cur_col = cur_row = 0;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_pad<T>::operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
// If we are within the bounds of the original matrix, simply copy.
|
||||
if ((cur_col < orig_cols) && (cur_row < orig_rows)) {
|
||||
*out = in;
|
||||
*sfout = true;
|
||||
ae = AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
// Don't take the input.
|
||||
*sfin = false;
|
||||
// If we are not completely done then write padding.
|
||||
if ((*sfout = (cur_row < final_rows))) {
|
||||
*out = (T)0;
|
||||
ae = AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
tp_assert(cur_row == final_rows, "Too many rows.");
|
||||
ae = AMI_SCAN_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the column.
|
||||
cur_col = (cur_col + 1) % final_cols;
|
||||
|
||||
// Increment the row if needed.
|
||||
if (!cur_col) {
|
||||
cur_row++;
|
||||
}
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// This is a scan management object designed to unpad a rows by cols
|
||||
// matrix that was padded by a an object of type scan_matrix_pad.
|
||||
|
||||
template<class T>
|
||||
class AMI_matrix_unpad : AMI_scan_object {
|
||||
private:
|
||||
TPIE_OS_OFFSET cur_row, cur_col;
|
||||
TPIE_OS_OFFSET orig_rows, orig_cols;
|
||||
TPIE_OS_OFFSET final_rows, final_cols;
|
||||
public:
|
||||
AMI_matrix_unpad(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent);
|
||||
virtual ~AMI_matrix_unpad();
|
||||
AMI_err initialize(void);
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_matrix_unpad<T>::AMI_matrix_unpad(TPIE_OS_OFFSET rows, TPIE_OS_OFFSET cols,
|
||||
TPIE_OS_OFFSET block_extent)
|
||||
|
||||
{
|
||||
orig_rows = rows;
|
||||
orig_cols = cols;
|
||||
final_rows = block_extent * (((orig_rows - 1) / block_extent) + 1);
|
||||
final_cols = block_extent * (((orig_cols - 1) / block_extent) + 1);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_matrix_unpad<T>::~AMI_matrix_unpad()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_unpad<T>::initialize(void)
|
||||
{
|
||||
cur_col = cur_row = 0;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_matrix_unpad<T>::operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
// If we are within the bounds of the original matrix, simply copy.
|
||||
if ((cur_col < orig_cols) && (cur_row < orig_rows)) {
|
||||
*out = in;
|
||||
*sfout = true;
|
||||
ae = AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
// Don't write anything.
|
||||
*sfout = false;
|
||||
|
||||
// If we are not completely done then skip padding.
|
||||
if ((*sfin = (cur_row < final_rows))) {
|
||||
ae = AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
tp_assert(cur_row == final_rows, "Too many rows.");
|
||||
ae = AMI_SCAN_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the column.
|
||||
cur_col = (cur_col + 1) % final_cols;
|
||||
|
||||
// Increment the row if needed.
|
||||
if (!cur_col) {
|
||||
cur_row++;
|
||||
}
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
#endif // _AMI_MATRIX_PAD_H
|
||||
@@ -0,0 +1,813 @@
|
||||
//
|
||||
// File: ami_merge.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/31/94
|
||||
//
|
||||
// First cut at a merger. Obviously missing is code to verify that
|
||||
// lower level streams will use appropriate levels of buffering. This
|
||||
// will be more critical for parallel disk implementations.
|
||||
//
|
||||
// $Id: ami_merge.h,v 1.38 2005/07/07 20:43:36 adanner Exp $
|
||||
//
|
||||
#ifndef _AMI_MERGE_H
|
||||
#define _AMI_MERGE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// For log() and such as needed to compute tree heights.
|
||||
#include <math.h>
|
||||
|
||||
#include <ami_stream.h>
|
||||
|
||||
enum AMI_merge_output_type {
|
||||
AMI_MERGE_OUTPUT_OVERWRITE = 1,
|
||||
AMI_MERGE_OUTPUT_APPEND
|
||||
};
|
||||
|
||||
typedef int AMI_merge_flag;
|
||||
typedef int arity_t;
|
||||
|
||||
#define CONST const
|
||||
|
||||
|
||||
// CLASSES AND FUNCTIONS DEFINED IN THIS MODULE
|
||||
//------------------------------------------------------------
|
||||
|
||||
//A superclass for merge management objects
|
||||
template<class T> class AMI_generalized_merge_base;
|
||||
|
||||
|
||||
//merge <arity> streams using a merge management object and write
|
||||
//result into <outstream>; it is assumed that the available memory can
|
||||
//fit the <arity> streams, the output stream and also the space
|
||||
//required by the merge management object; AMI_generalized_merge() checks this and
|
||||
//then calls AMI_generalized_single_merge();
|
||||
template<class T, class M>
|
||||
AMI_err AMI_generalized_merge(AMI_STREAM<T> **instreams, arity_t arity,
|
||||
AMI_STREAM<T> *outstream, M *m_obj);
|
||||
|
||||
|
||||
// divide the input stream in substreams, merge each substream
|
||||
// recursively, and merge them together using AMI_generalized_single_merge()
|
||||
template<class T, class M>
|
||||
AMI_err AMI_generalized_partition_and_merge(AMI_STREAM<T> *instream,
|
||||
AMI_STREAM<T> *outstream, M *m_obj);
|
||||
|
||||
|
||||
//merge <arity> streams in memory using a merge management object and
|
||||
//write result into <outstream>;
|
||||
template<class T, class M>
|
||||
AMI_err AMI_generalized_single_merge(AMI_STREAM<T> **instreams, arity_t arity,
|
||||
AMI_STREAM<T> *outstream, M *m_obj);
|
||||
|
||||
|
||||
//read <instream> in memory and merge it using
|
||||
//m_obj->main_mem_operate(); if <instream> does not fit in main memory
|
||||
//return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
template<class T, class M>
|
||||
AMI_err AMI_main_mem_merge(AMI_STREAM<T> *instream,
|
||||
AMI_STREAM<T> *outstream, M *m_obj);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// A superclass for merge management objects
|
||||
//------------------------------------------------------------
|
||||
template<class T>
|
||||
class AMI_generalized_merge_base {
|
||||
public:
|
||||
|
||||
#if AMI_VIRTUAL_BASE
|
||||
virtual AMI_err initialize(arity_t arity,
|
||||
CONST T * CONST * in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index) = 0;
|
||||
virtual AMI_err operate(CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index,
|
||||
T *out) = 0;
|
||||
virtual AMI_err main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len) = 0;
|
||||
virtual TPIE_OS_SIZE_T space_usage_overhead(void) = 0;
|
||||
virtual TPIE_OS_SIZE_T space_usage_per_stream(void) = 0;
|
||||
#endif // AMI_VIRTUAL_BASE
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
//merge <arity> streams using a merge management object and write
|
||||
//result into <outstream>; it is assumed that the available memory can
|
||||
//fit the <arity> streams, the output stream and also the space
|
||||
//required by the merge management object; AMI_generalized_merge() checks this and
|
||||
//then calls AMI_generalized_single_merge();
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T, class M>
|
||||
AMI_err
|
||||
AMI_generalized_merge(AMI_STREAM<T> **instreams, arity_t arity,
|
||||
AMI_STREAM<T> *outstream, M *m_obj) {
|
||||
|
||||
TPIE_OS_SIZE_T sz_avail;
|
||||
TPIE_OS_OFFSET sz_stream, sz_needed = 0;
|
||||
|
||||
// How much main memory is available?
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// Iterate through the streams, finding out how much additional
|
||||
// memory each stream will need in the worst case (the streams are
|
||||
// in memory, but their memory usage could be smaller then the
|
||||
// maximum one; one scenario is when the streams have been loaded
|
||||
// from disk with no subsequent read_item/write_item operation, in
|
||||
// which case their current memory usage is just the header block);
|
||||
// count also the output stream
|
||||
for (unsigned int ii = 0; ii < arity + 1; ii++) {
|
||||
instreams[ii]->main_memory_usage(&sz_stream, MM_STREAM_USAGE_MAXIMUM);
|
||||
sz_needed += sz_stream;
|
||||
instreams[ii]->main_memory_usage(&sz_stream, MM_STREAM_USAGE_CURRENT);
|
||||
sz_needed -= sz_stream;
|
||||
}
|
||||
|
||||
//count the space used by the merge_management object (include
|
||||
//overhead added to a stream)
|
||||
sz_needed += m_obj->space_usage_overhead() +
|
||||
arity * m_obj->space_usage_per_stream();
|
||||
|
||||
//streams and m_obj must fit in memory!
|
||||
if (sz_needed >= (TPIE_OS_OFFSET)sz_avail) {
|
||||
TP_LOG_WARNING("Insuficent main memory to perform a merge.\n");
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
assert(sz_needed < sz_avail);
|
||||
|
||||
//merge streams in memory
|
||||
return AMI_generalized_single_merge(instreams, arity, outstream, m_obj);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
//merge <arity> streams in memory using a merge management object and
|
||||
//write result into <outstream>;
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T, class M>
|
||||
AMI_err
|
||||
AMI_generalized_single_merge(AMI_STREAM<T> **instreams, arity_t arity,
|
||||
AMI_STREAM<T> *outstream, M *m_obj) {
|
||||
|
||||
unsigned int ii;
|
||||
AMI_err ami_err;
|
||||
|
||||
// Create an array of pointers for the input.
|
||||
T* *in_objects = new T*[arity];
|
||||
|
||||
// Create an array of flags the merge object can use to ask for more
|
||||
// input from specific streams.
|
||||
AMI_merge_flag* taken_flags = new AMI_merge_flag[arity];
|
||||
|
||||
// An index to speed things up when the merge object takes only from
|
||||
// one index.
|
||||
int taken_index;
|
||||
|
||||
//Output of the merge object.
|
||||
T merge_out;
|
||||
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
unsigned int input_count = 0, output_count = 0;
|
||||
#endif
|
||||
|
||||
// Rewind and read the first item from every stream; count the
|
||||
// number of non-null items read
|
||||
for (ii = arity; ii--; ) {
|
||||
if ((ami_err = instreams[ii]->seek(0)) != AMI_ERROR_NO_ERROR) {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
if ((ami_err = instreams[ii]->read_item(&(in_objects[ii]))) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
//error on read
|
||||
if (ami_err == AMI_ERROR_END_OF_STREAM) {
|
||||
in_objects[ii] = NULL;
|
||||
} else {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
// Set the taken flags to 0 before we call intialize()
|
||||
taken_flags[ii] = 0;
|
||||
} else {
|
||||
//item read succesfully
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
input_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the merge object.
|
||||
if (((ami_err = m_obj->initialize(arity, in_objects, taken_flags,
|
||||
taken_index)) != AMI_ERROR_NO_ERROR) &&
|
||||
(ami_err != AMI_MERGE_READ_MULTIPLE)) {
|
||||
return AMI_ERROR_OBJECT_INITIALIZATION;
|
||||
}
|
||||
|
||||
|
||||
// Now simply call the merge object repeatedly until it claims to
|
||||
// be done or generates an error.
|
||||
while (1) {
|
||||
if (ami_err == AMI_MERGE_READ_MULTIPLE) {
|
||||
for (ii = arity; ii--; ) {
|
||||
if (taken_flags[ii]) {
|
||||
ami_err = instreams[ii]->read_item(&(in_objects[ii]));
|
||||
if (ami_err != AMI_ERROR_NO_ERROR) {
|
||||
if (ami_err == AMI_ERROR_END_OF_STREAM) {
|
||||
in_objects[ii] = NULL;
|
||||
} else {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
} else {
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
input_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Clear all flags before operate is called.
|
||||
taken_flags[ii] = 0;
|
||||
}
|
||||
} else {
|
||||
// The last call took at most one item.
|
||||
if (taken_index >= 0) {
|
||||
ami_err = instreams[taken_index]->
|
||||
read_item(&(in_objects[taken_index]));
|
||||
if (ami_err != AMI_ERROR_NO_ERROR) {
|
||||
if (ami_err == AMI_ERROR_END_OF_STREAM) {
|
||||
in_objects[taken_index] = NULL;
|
||||
} else {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
} else {
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
input_count++;
|
||||
#endif
|
||||
}
|
||||
taken_flags[taken_index] = 0;
|
||||
}
|
||||
}
|
||||
ami_err = m_obj->operate(in_objects, taken_flags, taken_index,
|
||||
&merge_out);
|
||||
if (ami_err == AMI_MERGE_DONE) {
|
||||
break;
|
||||
} else if (ami_err == AMI_MERGE_OUTPUT) {
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
output_count++;
|
||||
#endif
|
||||
if ((ami_err = outstream->write_item(merge_out)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
} else if ((ami_err != AMI_MERGE_CONTINUE) &&
|
||||
(ami_err != AMI_MERGE_READ_MULTIPLE)) {
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
return ami_err;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_PERFECT_MERGE
|
||||
tp_assert(input_count == output_count,
|
||||
"Merge done, input_count = " << input_count <<
|
||||
", output_count = " << output_count << '.');
|
||||
#endif
|
||||
|
||||
delete[] in_objects;
|
||||
delete[] taken_flags;
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
//read <instream> in memory and merge it using
|
||||
//m_obj->main_mem_operate(); if <instream> does not fit in main memory
|
||||
//return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T, class M>
|
||||
AMI_err AMI_main_mem_merge(AMI_STREAM<T> *instream,
|
||||
AMI_STREAM<T> *outstream, M *m_obj) {
|
||||
|
||||
AMI_err ae;
|
||||
TPIE_OS_OFFSET len;
|
||||
TPIE_OS_SIZE_T sz_avail;
|
||||
|
||||
// How much memory is available?
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
len = instream->stream_len();
|
||||
if ((len * sizeof(T)) <= (TPIE_OS_OFFSET)sz_avail) {
|
||||
|
||||
// If the whole input can fit in main memory just call
|
||||
// m_obj->main_mem_operate
|
||||
|
||||
ae = instream->seek(0);
|
||||
assert(ae == AMI_ERROR_NO_ERROR);
|
||||
|
||||
// This code is sloppy and has to be rewritten correctly for
|
||||
// parallel buffer allocation. It will not work with anything
|
||||
// other than a registration based memory manager.
|
||||
T *mm_stream;
|
||||
TPIE_OS_OFFSET len1;
|
||||
//allocate and read input stream in memory we know it fits, so we may cast.
|
||||
if ((mm_stream = new T[(TPIE_OS_SIZE_T)len]) == NULL) {
|
||||
return AMI_ERROR_MM_ERROR;
|
||||
};
|
||||
len1 = len;
|
||||
if ((ae = instream->read_array(mm_stream, &len1)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
tp_assert(len1 == len, "Did not read the right amount; "
|
||||
"Allocated space for " << len << ", read " << len1 << '.');
|
||||
|
||||
//just call m_obj->main_mem_operate. We know that len items fit into
|
||||
//main memory, so we may cast to TPIE_OS_SIZE_T
|
||||
if ((ae = m_obj->main_mem_operate(mm_stream, (TPIE_OS_SIZE_T)len)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("main_mem_operate failed");
|
||||
return ae;
|
||||
}
|
||||
|
||||
//write array back to stream
|
||||
if ((ae = outstream->write_array(mm_stream, (TPIE_OS_SIZE_T)len)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("write array failed");
|
||||
return ae;
|
||||
}
|
||||
|
||||
delete [] mm_stream;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
|
||||
} else {
|
||||
|
||||
// Something went wrong. We should not have called this
|
||||
// function, since we don't have enough main memory.
|
||||
TP_LOG_WARNING_ID("out of memory");
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
// divide the input stream in substreams, merge each substream
|
||||
// recursively, and merge them together using AMI_generalized_single_merge()
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T, class M>
|
||||
AMI_err AMI_generalized_partition_and_merge(AMI_STREAM<T> *instream,
|
||||
AMI_STREAM<T> *outstream, M *m_obj) {
|
||||
|
||||
AMI_err ae;
|
||||
TPIE_OS_OFFSET len;
|
||||
TPIE_OS_SIZE_T sz_avail, sz_stream;
|
||||
unsigned int ii;
|
||||
int jj;
|
||||
|
||||
//How much memory is available?
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// If the whole input can fit in main memory then just call
|
||||
// AMI_main_mem_merge() to deal with it by loading it once and
|
||||
// processing it.
|
||||
len = instream->stream_len();
|
||||
if ((len * sizeof(T)) <= (TPIE_OS_OFFSET)sz_avail) {
|
||||
return AMI_main_mem_merge(instream, outstream, m_obj);
|
||||
}
|
||||
//else {
|
||||
|
||||
|
||||
|
||||
// The number of substreams that can be merged together at once; i
|
||||
// this many substreams (at most) we are dividing the input stream
|
||||
arity_t merge_arity;
|
||||
|
||||
//nb of substreams the original input stream will be split into
|
||||
arity_t nb_orig_substr;
|
||||
|
||||
// length (nb obj of type T) of the original substreams of the input
|
||||
// stream. The last one may be shorter than this.
|
||||
TPIE_OS_OFFSET sz_orig_substr;
|
||||
|
||||
// The initial temporary stream, to which substreams of the
|
||||
// original input stream are written.
|
||||
AMI_STREAM<T> *initial_tmp_stream;
|
||||
|
||||
// A pointer to the buffer in main memory to read a memory load into.
|
||||
T *mm_stream;
|
||||
|
||||
|
||||
// Loop variables:
|
||||
|
||||
// The stream being read at the current level.
|
||||
AMI_STREAM<T> *current_input;
|
||||
|
||||
// The output stream for the current level if it is not outstream.
|
||||
AMI_STREAM<T> *intermediate_tmp_stream;
|
||||
|
||||
// The size of substreams of *current_input that are being
|
||||
// merged. The last one may be smaller. This value should be
|
||||
// sz_orig_substr * (merge_arity ** k) where k is the
|
||||
// number of iterations the loop has gone through.
|
||||
TPIE_OS_OFFSET current_substream_len;
|
||||
|
||||
// The exponenent used to verify that current_substream_len is
|
||||
// correct.
|
||||
unsigned int k;
|
||||
|
||||
TPIE_OS_OFFSET sub_start, sub_end;
|
||||
|
||||
|
||||
|
||||
// How many substreams will there be? The main memory
|
||||
// available to us is the total amount available, minus what
|
||||
// is needed for the input stream and the temporary stream.
|
||||
if ((ae = instream->main_memory_usage(&sz_stream, MM_STREAM_USAGE_MAXIMUM))
|
||||
!= AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
if (sz_avail <= 2 * sz_stream + sizeof(T)) {
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
sz_avail -= 2 * sz_stream;
|
||||
|
||||
|
||||
// number of elements that will fit in memory (M) -R
|
||||
sz_orig_substr = sz_avail / sizeof(T);
|
||||
|
||||
// Round the original substream length off to an integral number of
|
||||
// chunks. This is for systems like HP-UX that cannot map in
|
||||
// overlapping regions. It is also required for BTE's that are
|
||||
// capable of freeing chunks as they are read.
|
||||
{
|
||||
TPIE_OS_OFFSET sz_chunk_size = instream->chunk_size();
|
||||
|
||||
sz_orig_substr = sz_chunk_size *
|
||||
((sz_orig_substr + sz_chunk_size - 1) /sz_chunk_size);
|
||||
// WARNING sz_orig_substr now may not fit in memory!!! -R
|
||||
}
|
||||
|
||||
// number of memoryloads in input ceil(N/M) -R
|
||||
nb_orig_substr = (arity_t)((len + sz_orig_substr - 1) / sz_orig_substr);
|
||||
|
||||
// Account for the space that a merge object will use.
|
||||
{
|
||||
TPIE_OS_SIZE_T sz_avail_during_merge = sz_avail - m_obj->space_usage_overhead();
|
||||
TPIE_OS_SIZE_T sz_stream_during_merge = sz_stream +m_obj->space_usage_per_stream();
|
||||
|
||||
merge_arity = (arity_t)((sz_avail_during_merge +
|
||||
sz_stream_during_merge - 1) / sz_stream_during_merge);
|
||||
}
|
||||
|
||||
// Make sure that the AMI is willing to provide us with the number
|
||||
// of substreams we want. It may not be able to due to operating
|
||||
// system restrictions, such as on the number of regions that can be
|
||||
// mmap()ed in.
|
||||
{
|
||||
int ami_available_streams = instream->available_streams();
|
||||
|
||||
if (ami_available_streams != -1) {
|
||||
if (ami_available_streams <= 4) {
|
||||
return AMI_ERROR_INSUFFICIENT_AVAILABLE_STREAMS;
|
||||
}
|
||||
if (merge_arity > (arity_t)ami_available_streams - 2) {
|
||||
merge_arity = ami_available_streams - 2;
|
||||
TP_LOG_DEBUG_ID("Reduced merge arity due to AMI restrictions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
TP_LOG_DEBUG_ID("AMI_generalized_partition_and_merge(): merge arity = "<< merge_arity);
|
||||
if (merge_arity < 2) {
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
//#define MINIMIZE_INITIAL_SUBSTREAM_LENGTH
|
||||
#ifdef MINIMIZE_INITIAL_SUBSTREAM_LENGTH
|
||||
|
||||
// Make the substreams as small as possible without increasing the
|
||||
// height of the merge tree.
|
||||
{
|
||||
// The tree height is the ceiling of the log base merge_arity
|
||||
// of the number of original substreams.
|
||||
|
||||
double tree_height = log((double)nb_orig_substr)/ log((double)merge_arity);
|
||||
tp_assert(tree_height > 0, "Negative or zero tree height!");
|
||||
|
||||
tree_height = ceil(tree_height);
|
||||
|
||||
// See how many substreams we could possibly fit in the tree
|
||||
// without increasing the height.
|
||||
double max_original_substreams = pow((double)merge_arity, tree_height);
|
||||
tp_assert(max_original_substreams >= nb_orig_substr,
|
||||
"Number of permitted substreams was reduced.");
|
||||
|
||||
// How big will such substreams be?
|
||||
double new_sz_original_substream = ceil((double)len /
|
||||
max_original_substreams);
|
||||
tp_assert(new_sz_original_substream <= sz_orig_substr,
|
||||
"Size of original streams increased.");
|
||||
|
||||
sz_orig_substr = (size_t)new_sz_original_substream;
|
||||
TP_LOG_DEBUG_ID("Memory constraints set original substreams = " << nb_orig_substr);
|
||||
|
||||
nb_orig_substr = (len + sz_orig_substr - 1) / sz_orig_substr;
|
||||
TP_LOG_DEBUG_ID("Tree height constraints set original substreams = " << nb_orig_substr);
|
||||
}
|
||||
#endif // MINIMIZE_INITIAL_SUBSTREAM_LENGTH
|
||||
|
||||
|
||||
// Create a temporary stream, then iterate through the substreams,
|
||||
// processing each one and writing it to the corresponding substream
|
||||
// of the temporary stream.
|
||||
initial_tmp_stream = new AMI_STREAM<T>;
|
||||
mm_stream = new T[(TPIE_OS_SIZE_T)sz_orig_substr];
|
||||
tp_assert(mm_stream != NULL, "Misjudged available main memory.");
|
||||
if (mm_stream == NULL) {
|
||||
return AMI_ERROR_INSUFFICIENT_MAIN_MEMORY;
|
||||
}
|
||||
|
||||
instream->seek(0);
|
||||
assert(ae == AMI_ERROR_NO_ERROR);
|
||||
|
||||
tp_assert(nb_orig_substr * sz_orig_substr - len < sz_orig_substr,
|
||||
"Total substream length too long or too many.");
|
||||
tp_assert(len - (nb_orig_substr - 1) * sz_orig_substr <= sz_orig_substr,
|
||||
"Total substream length too short or too few.");
|
||||
|
||||
for (ii = 0; ii++ < nb_orig_substr; ) {
|
||||
|
||||
TPIE_OS_OFFSET mm_len;
|
||||
if (ii == nb_orig_substr) {
|
||||
mm_len = len % sz_orig_substr;
|
||||
// If it is an exact multiple, then the mod will come out 0,
|
||||
// which is wrong.
|
||||
if (!mm_len) {
|
||||
mm_len = sz_orig_substr;
|
||||
}
|
||||
} else {
|
||||
mm_len = sz_orig_substr;
|
||||
}
|
||||
#if DEBUG_ASSERTIONS
|
||||
TPIE_OS_OFFSET mm_len_bak = mm_len;
|
||||
#endif
|
||||
|
||||
// Read a memory load out of the input stream.
|
||||
ae = instream->read_array(mm_stream, &mm_len);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
tp_assert(mm_len == mm_len_bak,
|
||||
"Did not read the requested number of objects." <<
|
||||
"\n\tmm_len = " << mm_len <<
|
||||
"\n\tmm_len_bak = " << mm_len_bak << '.');
|
||||
|
||||
// Solve in main memory. We know it fits, so cast to TPIE_OS_SIZE_T
|
||||
m_obj->main_mem_operate(mm_stream, (TPIE_OS_SIZE_T)mm_len);
|
||||
|
||||
// Write the result out to the temporary stream.
|
||||
ae = initial_tmp_stream->write_array(mm_stream, mm_len);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
} //for
|
||||
delete [] mm_stream;
|
||||
|
||||
|
||||
// Make sure the total length of the temporary stream is the same as
|
||||
// the total length of the original input stream.
|
||||
tp_assert(instream->stream_len() == initial_tmp_stream->stream_len(),
|
||||
"Stream lengths do not match:" <<
|
||||
"\n\tinstream->stream_len() = " << instream->stream_len() <<
|
||||
"\n\tinitial_tmp_stream->stream_len() = " <<
|
||||
initial_tmp_stream->stream_len() << ".\n");
|
||||
|
||||
// Set up the loop invariants for the first iteration of hte main
|
||||
// loop.
|
||||
current_input = initial_tmp_stream;
|
||||
current_substream_len = sz_orig_substr;
|
||||
|
||||
// Pointers to the substreams that will be merged.
|
||||
AMI_STREAM<T>* *the_substreams = new AMI_STREAM<T>*[merge_arity];
|
||||
|
||||
//Monitoring prints.
|
||||
TP_LOG_DEBUG_ID("Number of runs from run formation is "
|
||||
<< nb_orig_substr);
|
||||
TP_LOG_DEBUG_ID("Merge arity is " << merge_arity);
|
||||
|
||||
|
||||
k = 0;
|
||||
// The main loop. At the outermost level we are looping over levels
|
||||
// of the merge tree. Typically this will be very small, e.g. 1-3.
|
||||
for( ; current_substream_len < (size_t)len;
|
||||
current_substream_len *= merge_arity) {
|
||||
|
||||
// The number of substreams to be processed at this level.
|
||||
arity_t substream_count;
|
||||
|
||||
// Set up to process a given level.
|
||||
tp_assert(len == current_input->stream_len(),
|
||||
"Current level stream not same length as input." <<
|
||||
"\n\tlen = " << len <<
|
||||
"\n\tcurrent_input->stream_len() = " <<
|
||||
current_input->stream_len() << ".\n");
|
||||
|
||||
// Do we have enough main memory to merge all the substreams on
|
||||
// the current level into the output stream? If so, then we will
|
||||
// do so, if not then we need an additional level of iteration to
|
||||
// process the substreams in groups.
|
||||
substream_count = (arity_t)((len + current_substream_len - 1) /
|
||||
current_substream_len);
|
||||
|
||||
if (substream_count <= merge_arity) {
|
||||
|
||||
TP_LOG_DEBUG_ID("Merging substreams directly to the output stream.");
|
||||
|
||||
// Create all the substreams
|
||||
for (sub_start = 0, ii = 0 ;
|
||||
ii < substream_count;
|
||||
sub_start += current_substream_len, ii++) {
|
||||
|
||||
sub_end = sub_start + current_substream_len - 1;
|
||||
if (sub_end >= len) {
|
||||
sub_end = len - 1;
|
||||
}
|
||||
current_input->new_substream(AMI_READ_STREAM, sub_start, sub_end,
|
||||
(AMI_stream_base<T> **)
|
||||
(the_substreams + ii));
|
||||
// The substreams are read-once.
|
||||
the_substreams[ii]->persist(PERSIST_READ_ONCE);
|
||||
}
|
||||
|
||||
tp_assert(((int) sub_start >= (int) len) &&
|
||||
((int) sub_start < (int) len + (int) current_substream_len),
|
||||
"Loop ended in wrong location.");
|
||||
|
||||
// Fool the OS into unmapping the current block of the input
|
||||
// stream so that blocks of the substreams can be mapped in
|
||||
// without overlapping it. This is needed for correct execution
|
||||
// on HP-UX.
|
||||
//this needs to be cleaned up..Laura
|
||||
current_input->seek(0);
|
||||
assert(ae == AMI_ERROR_NO_ERROR);
|
||||
|
||||
// Merge them into the output stream.
|
||||
ae = AMI_generalized_single_merge(the_substreams, substream_count, outstream, m_obj);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
// Delete the substreams.
|
||||
for (ii = 0; ii < substream_count; ii++) {
|
||||
delete the_substreams[ii];
|
||||
}
|
||||
// And the current input, which is an intermediate stream of
|
||||
// some kind.
|
||||
delete current_input;
|
||||
|
||||
} else {
|
||||
|
||||
//substream_count is > merge_arity
|
||||
TP_LOG_DEBUG_ID("Merging substreams to an intermediate stream.");
|
||||
|
||||
// Create the next intermediate stream.
|
||||
intermediate_tmp_stream = new AMI_STREAM<T>;
|
||||
|
||||
// Fool the OS into unmapping the current block of the input
|
||||
// stream so that blocks of the substreams can be mapped in
|
||||
// without overlapping it. This is needed for correct execution
|
||||
// on HU-UX.
|
||||
//this needs to be cleaned up..Laura
|
||||
current_input->seek(0);
|
||||
assert(ae == AMI_ERROR_NO_ERROR);
|
||||
|
||||
// Loop through the substreams of the current stream, merging as
|
||||
// many as we can at a time until all are done with.
|
||||
for (sub_start = 0, ii = 0, jj = 0;
|
||||
ii < substream_count;
|
||||
sub_start += current_substream_len, ii++, jj++) {
|
||||
|
||||
sub_end = sub_start + current_substream_len - 1;
|
||||
if (sub_end >= len) {
|
||||
sub_end = len - 1;
|
||||
}
|
||||
current_input->new_substream(AMI_READ_STREAM, sub_start, sub_end,
|
||||
(AMI_stream_base<T> **)
|
||||
(the_substreams + jj));
|
||||
// The substreams are read-once.
|
||||
the_substreams[jj]->persist(PERSIST_READ_ONCE);
|
||||
|
||||
// If we've got all we can handle or we've seen them all, then
|
||||
// merge them.
|
||||
if ((jj >= (int) merge_arity - 1) || (ii == substream_count - 1)) {
|
||||
|
||||
tp_assert(jj <= (int) merge_arity - 1,
|
||||
"Index got too large.");
|
||||
#if DEBUG_ASSERTIONS
|
||||
// Check the lengths before the merge.
|
||||
TPIE_OS_OFFSET sz_output, sz_output_after_merge;
|
||||
TPIE_OS_OFFSET sz_substream_total;
|
||||
|
||||
{
|
||||
unsigned int kk;
|
||||
|
||||
sz_output = intermediate_tmp_stream->stream_len();
|
||||
sz_substream_total = 0;
|
||||
|
||||
for (kk = jj+1; kk--; ) {
|
||||
sz_substream_total += the_substreams[kk]->stream_len();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// This should append to the stream, since
|
||||
// AMI_generalized_single_merge() does not rewind the output before
|
||||
// merging.
|
||||
ae = AMI_generalized_single_merge(the_substreams, jj+1,
|
||||
intermediate_tmp_stream, m_obj);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
// Verify the total lengths after the merge.
|
||||
sz_output_after_merge = intermediate_tmp_stream->stream_len();
|
||||
tp_assert(sz_output_after_merge - sz_output ==
|
||||
sz_substream_total,
|
||||
"Stream lengths do not add up: " <<
|
||||
sz_output_after_merge - sz_output <<
|
||||
" written when " <<
|
||||
sz_substream_total <<
|
||||
" were to have been read.");
|
||||
|
||||
#endif
|
||||
|
||||
// Delete the substreams. jj is currently the index of the
|
||||
// largest, so we want to bump it up before the idiomatic
|
||||
// loop.
|
||||
for (jj++; jj--; ) {
|
||||
delete the_substreams[jj];
|
||||
}
|
||||
|
||||
// Now jj should be -1 so that it gets bumped back up to 0
|
||||
// before the next iteration of the outer loop.
|
||||
tp_assert((jj == -1), "Index not reduced to -1.");
|
||||
|
||||
} // if
|
||||
} //for
|
||||
|
||||
// Get rid of the current input stream and use the next one.
|
||||
delete current_input;
|
||||
current_input = intermediate_tmp_stream;
|
||||
}
|
||||
|
||||
k++;
|
||||
|
||||
}
|
||||
|
||||
//Monitoring prints.
|
||||
TP_LOG_DEBUG_ID("Number of passes incl run formation is " << k+1);
|
||||
|
||||
delete [] the_substreams;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// File: ami_optimized_sort.h
|
||||
// $Id: ami_optimized_sort.h,v 1.4 2003/04/17 13:10:02 jan Exp $
|
||||
//
|
||||
// Optimized merge sorting.
|
||||
//
|
||||
#ifndef _AMI_SORT_OPTIMIZED_H
|
||||
#define _AMI_SORT_OPTIMIZED_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#ifndef AMI_STREAM_IMP_SINGLE
|
||||
# warning Including __FILE__ when AMI_STREAM_IMP_SINGLE undefined.
|
||||
#endif
|
||||
|
||||
#include <ami_merge.h>
|
||||
#include <ami_optimized_merge.h>
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T>
|
||||
AMI_err
|
||||
AMI_optimized_sort(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream) {
|
||||
|
||||
return AMI_partition_and_merge(instream, outstream);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
template<class T, class KEY>
|
||||
AMI_err
|
||||
AMI_optimized_sort(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream,
|
||||
int keyoffset, KEY dummykey) {
|
||||
|
||||
return AMI_partition_and_merge(instream, outstream, keyoffset, dummykey);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,440 @@
|
||||
// Copyright (C) 2002 Octavian Procopiuc
|
||||
//
|
||||
// File: ami_point.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// The AMI_point and AMI_record classes.
|
||||
//
|
||||
// $Id: ami_point.h,v 1.9 2005/01/21 16:55:29 tavi Exp $
|
||||
//
|
||||
|
||||
#ifndef AMI_POINT_H_
|
||||
#define AMI_POINT_H_
|
||||
|
||||
// For ostream.
|
||||
#include <iostream>
|
||||
|
||||
// This is a hack. It works for integer types only.
|
||||
template<class coord_t>
|
||||
class infinity_t {
|
||||
static coord_t minf;// = (1 << (8*sizeof(coord_t) - 1));
|
||||
static coord_t pinf;// = ~minf;
|
||||
public:
|
||||
int operator+() const { return pinf; }
|
||||
int operator-() const { return minf; }
|
||||
};
|
||||
|
||||
template<class coord_t>
|
||||
coord_t infinity_t<coord_t>::minf = (1 << (8*sizeof(coord_t) - 1));
|
||||
template<class coord_t>
|
||||
coord_t infinity_t<coord_t>::pinf = ~(1 << (8*sizeof(coord_t) - 1));
|
||||
|
||||
//int infinity_t<int>::minf = (1 << (8*sizeof(int) - 1));
|
||||
//int infinity_t<int>::pinf = ~(1 << (8*sizeof(int) - 1));
|
||||
|
||||
// The base class for AMI_point.
|
||||
template<class coord_t, size_t dim>
|
||||
class AMI_point_base {
|
||||
protected:
|
||||
coord_t coords_[dim];
|
||||
public:
|
||||
static infinity_t<coord_t> Inf;
|
||||
|
||||
// The default constructor.
|
||||
AMI_point_base() {}
|
||||
|
||||
// The array operators for accessing/setting the coordinates.
|
||||
coord_t& operator[](size_t i) { return coords_[i]; }
|
||||
const coord_t& operator[](size_t i) const { return coords_[i]; }
|
||||
|
||||
|
||||
// Operator < for window queries. It's actually more like <=.
|
||||
bool operator<(const AMI_point_base<coord_t, dim>& p) const {
|
||||
size_t i;
|
||||
for (i = 0; i < dim; i++)
|
||||
if (p[i] < coords_[i])
|
||||
break;
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
void set_min(const AMI_point_base<coord_t, dim>& p) {
|
||||
for (size_t j = 0; j < dim; j++)
|
||||
coords_[j] = min(coords_[j], p[j]);
|
||||
}
|
||||
|
||||
void set_max(const AMI_point_base<coord_t, dim>& p) {
|
||||
for (size_t j = 0; j < dim; j++)
|
||||
coords_[j] = max(coords_[j], p[j]);
|
||||
}
|
||||
|
||||
// Scalar product.
|
||||
coord_t operator*(const AMI_point_base<coord_t,dim>& p) const {
|
||||
coord_t ans = coords_[0]*p[0];
|
||||
for (size_t i = 1; i < dim; i++)
|
||||
ans += coords_[i]*p[i];
|
||||
return ans;
|
||||
}
|
||||
};
|
||||
|
||||
template<class coord_t, size_t dim>
|
||||
infinity_t<coord_t> AMI_point_base<coord_t, dim>::Inf = infinity_t<coord_t>();
|
||||
|
||||
|
||||
// The AMI_point class.
|
||||
template <class coord_t, size_t dim>
|
||||
class AMI_point: public AMI_point_base<coord_t, dim> {
|
||||
protected:
|
||||
using AMI_point_base<coord_t, dim>::coords_;
|
||||
|
||||
public:
|
||||
bool operator==(const AMI_point<coord_t, dim>& p) const {
|
||||
size_t i = 0;
|
||||
while (i < dim) {
|
||||
if (coords_[i] != p[i])
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
// The comparison class. For sorting on each of the dim dimensions.
|
||||
class cmp {
|
||||
// The dimension on which to compare. It should be less than dim.
|
||||
size_t d_;
|
||||
public:
|
||||
cmp(size_t d = 0): d_(d) {}
|
||||
|
||||
inline int compare(const AMI_point<coord_t,dim>& p1,
|
||||
const AMI_point<coord_t,dim>& p2) const {
|
||||
// Lexicographic order starting with dimension d_.
|
||||
if (p1[d_] < p2[d_])
|
||||
return -1;
|
||||
else if (p1[d_] > p2[d_])
|
||||
return 1;
|
||||
else
|
||||
return _compare(p1, p2);
|
||||
}
|
||||
|
||||
// This operator is used by STL sort().
|
||||
bool operator()(const AMI_point<coord_t, dim>& p1,
|
||||
const AMI_point<coord_t, dim>& p2) const {
|
||||
return (compare(p1, p2) == -1);
|
||||
}
|
||||
|
||||
private:
|
||||
int _compare(const AMI_point<coord_t,dim>& p1,
|
||||
const AMI_point<coord_t,dim>& p2) const {
|
||||
size_t j = 0;
|
||||
// Cycle once through all dimensions, starting with d_.
|
||||
while (j < dim && p1[(j+d_)%dim] == p2[(j+d_)%dim])
|
||||
j++;
|
||||
if (j == dim)
|
||||
return 0;
|
||||
else
|
||||
return (p1[(j+d_)%dim] < p2[(j+d_)%dim]) ? -1: 1;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<class coord_t, size_t dim>
|
||||
ostream& operator<<(ostream& s, const AMI_point<coord_t, dim>& p) {
|
||||
for (size_t i = 0; i < dim-1; i++)
|
||||
s << p[i] << " ";
|
||||
return s << p[dim-1];
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#else
|
||||
// Partial specialization of AMI_point for 2 dimensions.
|
||||
template <class coord_t>
|
||||
class AMI_point<coord_t, 2>: public AMI_point_base<coord_t, 2> {
|
||||
protected:
|
||||
using AMI_point_base<coord_t, 2>::coords_;
|
||||
|
||||
public:
|
||||
|
||||
AMI_point() {}
|
||||
AMI_point(coord_t _x, coord_t _y) { coords_[0] = _x; coords_[1] = _y; }
|
||||
coord_t x() const { return coords_[0]; }
|
||||
coord_t& x() { return coords_[0]; }
|
||||
coord_t y() const { return coords_[1]; }
|
||||
coord_t& y() { return coords_[1]; }
|
||||
|
||||
bool operator==(const AMI_point<coord_t, 2>& p) const {
|
||||
return (coords_[0] == p.coords_[0]) &&
|
||||
(coords_[1] == p.coords_[1]);
|
||||
}
|
||||
bool operator!=(const AMI_point<coord_t, 2>& p) const {
|
||||
return (coords_[0] != p.coords_[0]) ||
|
||||
(coords_[1] != p.coords_[1]);
|
||||
}
|
||||
bool less_x(const AMI_point<coord_t, 2>& b) const {
|
||||
return (coords_[0] < b.coords_[0]) ||
|
||||
((coords_[0] == b.coords_[0]) && (coords_[1] < b.coords_[1]));
|
||||
}
|
||||
bool less_y(const AMI_point<coord_t, 2>& b) const {
|
||||
return (coords_[1] < b.coords_[1]) ||
|
||||
((coords_[1] == b.coords_[1]) && (coords_[0] < b.coords_[0]));
|
||||
}
|
||||
struct less_X {
|
||||
bool operator()(const AMI_point<coord_t, 2>& a,
|
||||
const AMI_point<coord_t, 2>& b) const
|
||||
{ return (a[0] < b[0]) || ((a[0] == b[0]) && (a[1] < b[1])); }
|
||||
};
|
||||
|
||||
struct less_Y {
|
||||
bool operator()(const AMI_point<coord_t, 2>& a,
|
||||
const AMI_point<coord_t, 2>& b) const
|
||||
{ return (a[1] < b[1]) || ((a[1] == b[1]) && (a[0] < b[0])); }
|
||||
};
|
||||
|
||||
// The comparison class. For sorting on each of the dim dimensions.
|
||||
class cmp {
|
||||
// The dimension on which to compare. It should be less than 2.
|
||||
size_t d_;
|
||||
public:
|
||||
cmp(size_t d = 0): d_(d) {}
|
||||
|
||||
inline int compare(const AMI_point<coord_t, 2>& p1,
|
||||
const AMI_point<coord_t, 2>& p2) const {
|
||||
// Lexicographic order starting with dimension d_.
|
||||
if (p1[d_] < p2[d_])
|
||||
return -1;
|
||||
else if (p1[d_] > p2[d_])
|
||||
return 1;
|
||||
else if (p1[(d_+1)%2] < p2[(d_+1)%2])
|
||||
return -1;
|
||||
else if (p2[(d_+1)%2] < p1[(d_+1)%2])
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This operator is used by STL sort().
|
||||
bool operator()(const AMI_point<coord_t, 2>& p1,
|
||||
const AMI_point<coord_t, 2>& p2) const {
|
||||
return (compare(p1, p2) == -1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<class coord_t>
|
||||
ostream& operator<<(ostream& s, const AMI_point<coord_t, 2>& p) {
|
||||
return s << p[0] << " " << p[1];
|
||||
}
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
template<class coord_t, class data_t, size_t dim>
|
||||
class AMI_record_base {
|
||||
public:
|
||||
typedef AMI_point<coord_t, dim> point_t;
|
||||
|
||||
point_t key;
|
||||
data_t data;
|
||||
|
||||
// AMI_record() {}
|
||||
AMI_record_base(const point_t& p, data_t _data = data_t(0)):
|
||||
key(p), data(_data) {}
|
||||
AMI_record_base(data_t _data = data_t(0)): data(_data) {}
|
||||
|
||||
data_t& id() { return data; }
|
||||
const data_t& id() const { return data; }
|
||||
|
||||
bool operator==(const AMI_record_base<coord_t, data_t, dim>& r) const
|
||||
{ return key == r.key; }
|
||||
|
||||
// The array operators for accessing/setting the coordinates.
|
||||
coord_t& operator[](size_t i) { return key[i]; }
|
||||
const coord_t& operator[](size_t i) const { return key[i]; }
|
||||
|
||||
// Operator < for window queries. It's actually more like <=.
|
||||
bool operator<(const AMI_record_base<coord_t, data_t, dim>& p) const {
|
||||
size_t i;
|
||||
for (i = 0; i < dim; i++)
|
||||
if (p[i] < key[i])
|
||||
break;
|
||||
return (i == dim);
|
||||
}
|
||||
|
||||
|
||||
void set_min(const AMI_record_base<coord_t, data_t, dim>& p) {
|
||||
for (size_t j = 0; j < dim; j++)
|
||||
key[j] = min(key[j], p[j]);
|
||||
}
|
||||
|
||||
void set_max(const AMI_record_base<coord_t, data_t, dim>& p) {
|
||||
for (size_t j = 0; j < dim; j++)
|
||||
key[j] = max(key[j], p[j]);
|
||||
}
|
||||
|
||||
// Scalar product.
|
||||
coord_t operator*(const AMI_record_base<coord_t, data_t, dim>& p) const {
|
||||
coord_t ans = key[0] * p[0];
|
||||
for (size_t i = 1; i < dim; i++)
|
||||
ans += key[i] * p[i];
|
||||
return ans;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class coord_t, class data_t, size_t dim>
|
||||
class AMI_record: public AMI_record_base<coord_t, data_t, dim> {
|
||||
public:
|
||||
AMI_record(const typename AMI_record_base<coord_t, data_t, dim>::point_t& p, data_t b = data_t(0)):
|
||||
AMI_record_base<coord_t, data_t, dim>(p, b) {}
|
||||
AMI_record(data_t b = data_t(0)): AMI_record_base<coord_t, data_t, dim>(b) {}
|
||||
|
||||
// The comparison class. For sorting on each of the dim dimensions.
|
||||
class cmp {
|
||||
// The dimension on which to compare. It should be less than dim.
|
||||
size_t d_;
|
||||
public:
|
||||
cmp(size_t d = 0): d_(d) {}
|
||||
|
||||
inline int compare(const AMI_record<coord_t, data_t, dim>& p1,
|
||||
const AMI_record<coord_t, data_t, dim>& p2) const {
|
||||
// Lexicographic order starting with dimension d_.
|
||||
if (p1[d_] < p2[d_])
|
||||
return -1;
|
||||
else if (p2[d_] < p1[d_])
|
||||
return 1;
|
||||
else
|
||||
return _compare(p1, p2);
|
||||
}
|
||||
|
||||
// This operator is used by STL sort().
|
||||
bool operator()(const AMI_record<coord_t, data_t, dim>& p1,
|
||||
const AMI_record<coord_t, data_t, dim>& p2) const {
|
||||
return (compare(p1, p2) == -1);
|
||||
}
|
||||
|
||||
private:
|
||||
int _compare(const AMI_record<coord_t, data_t, dim>& p1,
|
||||
const AMI_record<coord_t, data_t, dim>& p2) const {
|
||||
size_t j = 0;
|
||||
// Cycle once through all dimensions, starting with d_.
|
||||
// TODO: change equality expression to an expression containing only <.
|
||||
while (j < dim && p1[(j+d_)%dim] == p2[(j+d_)%dim])
|
||||
j++;
|
||||
if (j == dim)
|
||||
return 0;
|
||||
else
|
||||
return (p1[(j+d_)%dim] < p2[(j+d_)%dim]) ? -1: 1;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template<class coord_t, class data_t, size_t dim>
|
||||
ostream& operator<<(ostream& s, const AMI_record<coord_t, data_t, dim>& p) {
|
||||
for (TPIE_OS_TIME_T i = 0; i < dim; i++)
|
||||
s << p[i] << " ";
|
||||
return s << (TPIE_OS_OFFSET)p.id();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#else
|
||||
// A record consists of a key (two-dimensional point) and a data
|
||||
// item. Used by the EPStree.
|
||||
template<class coord_t, class data_t>
|
||||
struct AMI_record<coord_t, data_t, 2>: public AMI_record_base<coord_t, data_t, 2> {
|
||||
public:
|
||||
AMI_record(const typename AMI_record_base<coord_t, data_t, 2>::point_t& p, data_t b = data_t(0)):
|
||||
AMI_record_base<coord_t, data_t, 2>(p, b) {}
|
||||
AMI_record(const coord_t& x, const coord_t& y, const data_t& b):
|
||||
AMI_record_base<coord_t, data_t, 2>(point_t(x, y), b) {}
|
||||
AMI_record(data_t b = data_t(0)): AMI_record_base<coord_t, data_t, 2>(b) {}
|
||||
|
||||
struct less_X_point {
|
||||
bool operator()(const AMI_record<coord_t, data_t, 2>& r,
|
||||
const typename AMI_record_base<coord_t, data_t, 2>::point_t& p) const {
|
||||
// return point_t::less_X()(r.key, p);
|
||||
return r.key.less_x(p);
|
||||
}
|
||||
};
|
||||
|
||||
struct less_X {
|
||||
bool operator()(const AMI_record<coord_t, data_t, 2>& r1,
|
||||
const AMI_record<coord_t, data_t, 2>& r2) const {
|
||||
// return point_t::less_X()(r1.key, r2.key);
|
||||
return r1.key.less_x(r2.key);
|
||||
}
|
||||
|
||||
int compare(const AMI_record<coord_t, data_t, 2>& r1,
|
||||
const AMI_record<coord_t, data_t, 2>& r2) const {
|
||||
if (r1.key.less_x(r2.key))
|
||||
return -1;
|
||||
else if (r2.key.less_x(r1.key))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct less_Y {
|
||||
bool operator()(const AMI_record<coord_t, data_t, 2>& r1,
|
||||
const AMI_record<coord_t, data_t, 2>& r2) const {
|
||||
// return point_t::less_Y()(r1.key, r2.key);
|
||||
return r1.key.less_y(r2.key);
|
||||
}
|
||||
|
||||
int compare(const AMI_record<coord_t, data_t, 2>& r1,
|
||||
const AMI_record<coord_t, data_t, 2>& r2) const {
|
||||
if (r1.key.less_y(r2.key))
|
||||
return -1;
|
||||
else if (r2.key.less_y(r1.key))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// The comparison class. For sorting on each of the dim dimensions.
|
||||
class cmp {
|
||||
// The dimension on which to compare. It should be less than 2.
|
||||
size_t d_;
|
||||
public:
|
||||
cmp(size_t d = 0): d_(d) {}
|
||||
|
||||
inline int compare(const AMI_record<coord_t, data_t, 2>& p1,
|
||||
const AMI_record<coord_t, data_t, 2>& p2) const {
|
||||
// Lexicographic order starting with dimension d_.
|
||||
if (p1[d_] < p2[d_])
|
||||
return -1;
|
||||
else if (p2[d_] < p1[d_])
|
||||
return 1;
|
||||
else if (p1[(d_+1)%2] < p2[(d_+1)%2])
|
||||
return -1;
|
||||
else if (p2[(d_+1)%2] < p1[(d_+1)%2])
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This operator is used by STL sort().
|
||||
bool operator()(const AMI_record<coord_t, data_t, 2>& p1,
|
||||
const AMI_record<coord_t, data_t, 2>& p2) const {
|
||||
return (compare(p1, p2) == -1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<class coord_t, class data_t>
|
||||
ostream& operator<<(ostream& s, const AMI_record<coord_t, data_t, 2>& p) {
|
||||
return s << p[0] << " " << p[1] << " " << p.id();
|
||||
}
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
// Function object to extract the key from a record.
|
||||
template<class coord_t, class data_t, size_t dim>
|
||||
class AMI_record_key {
|
||||
public:
|
||||
AMI_point<coord_t, dim> operator()(const AMI_record<coord_t, data_t, dim>& r) const
|
||||
{ return r.key; }
|
||||
};
|
||||
|
||||
#endif // AMI_POINT_H_
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2005 Andrew Danner
|
||||
//
|
||||
// File: ami_queue.h
|
||||
// Author: Andrew Danner <adanner@cs.duke.edu>
|
||||
// Created: 2/22/05
|
||||
//
|
||||
// $Id: ami_queue.h,v 1.1 2005/04/25 19:08:06 adanner Exp $
|
||||
//
|
||||
#ifndef _AMI_QUEUE_H
|
||||
#define _AMI_QUEUE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the AMI_STREAM definition.
|
||||
#include <ami_stream.h>
|
||||
#include <ami_stack.h>
|
||||
|
||||
// Basic Implementation of I/O Efficient FIFO queue.
|
||||
// Uses two stacks
|
||||
template<class T>
|
||||
class AMI_queue {
|
||||
|
||||
public:
|
||||
bool empty();
|
||||
TPIE_OS_OFFSET size(){return Qsize;}
|
||||
AMI_queue();
|
||||
AMI_queue(const char* basename);
|
||||
~AMI_queue(void);
|
||||
AMI_err enqueue(const T &t);
|
||||
AMI_err dequeue(T **t);
|
||||
void persist(persistence p);
|
||||
|
||||
private:
|
||||
AMI_stack<T>* enQstack;
|
||||
AMI_stack<T>* deQstack;
|
||||
TPIE_OS_OFFSET Qsize;
|
||||
};
|
||||
|
||||
//Constructor for Temporary Queue
|
||||
template<class T>
|
||||
AMI_queue<T>::AMI_queue() {
|
||||
enQstack = new AMI_stack<T>();
|
||||
deQstack = new AMI_stack<T>();
|
||||
enQstack->persist(PERSIST_DELETE);
|
||||
deQstack->persist(PERSIST_DELETE);
|
||||
Qsize=0;
|
||||
}
|
||||
|
||||
//Constructor for Queue with filename
|
||||
template<class T>
|
||||
AMI_queue<T>::AMI_queue(const char* basename)
|
||||
{
|
||||
char fname[BTE_STREAM_PATH_NAME_LEN];
|
||||
strncpy(fname, basename, BTE_STREAM_PATH_NAME_LEN-4);
|
||||
strcat(fname,".nq");
|
||||
enQstack = new AMI_stack<T>(fname);
|
||||
strncpy(fname, basename, BTE_STREAM_PATH_NAME_LEN-4);
|
||||
strcat(fname,".dq");
|
||||
deQstack = new AMI_stack<T>(fname);
|
||||
enQstack->persist(PERSIST_PERSISTENT);
|
||||
deQstack->persist(PERSIST_PERSISTENT);
|
||||
Qsize=enQstack->stream_len()+deQstack->stream_len();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_queue<T>::~AMI_queue(void)
|
||||
{
|
||||
delete enQstack;
|
||||
delete deQstack;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void AMI_queue<T>::persist(persistence p) {
|
||||
enQstack->persist(p);
|
||||
deQstack->persist(p);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_queue<T>::enqueue(const T &t)
|
||||
{
|
||||
//Elements are pushed onto an Enqueue stack
|
||||
AMI_err ae=enQstack->push(t);
|
||||
if(ae == AMI_ERROR_NO_ERROR){
|
||||
Qsize++;
|
||||
}
|
||||
return ae;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_queue<T>::dequeue(T **t)
|
||||
{
|
||||
AMI_err ae;
|
||||
T* tmp;
|
||||
//Elements popped from Dequeue stack
|
||||
if(deQstack->stream_len()>0){
|
||||
ae=deQstack->pop(t);
|
||||
if(ae == AMI_ERROR_NO_ERROR){
|
||||
Qsize--;
|
||||
}
|
||||
return ae;
|
||||
}
|
||||
else if(Qsize == 0){
|
||||
return AMI_ERROR_END_OF_STREAM;
|
||||
}
|
||||
else{
|
||||
//move elements from Enqueue stack to Dequeue stack
|
||||
while((ae=enQstack->pop(&tmp)) == AMI_ERROR_NO_ERROR){
|
||||
ae=deQstack->push(*tmp);
|
||||
if(ae != AMI_ERROR_NO_ERROR){ return ae; }
|
||||
}
|
||||
if(ae != AMI_ERROR_BTE_ERROR){
|
||||
return ae;
|
||||
}
|
||||
ae=deQstack->pop(t);
|
||||
if(ae == AMI_ERROR_NO_ERROR){
|
||||
Qsize--;
|
||||
}
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _AMI_QUEUE_H
|
||||
@@ -0,0 +1,359 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan.H
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Header Created: 5/25/94
|
||||
//
|
||||
// This file was created mechanically by make, as specified in Makefile.
|
||||
// There is no reason it should ever be edited by hand.
|
||||
//
|
||||
// The following Id string applies to the header used in the processs of
|
||||
// generating this file. The header, stored in ami_scan.H.head, may be
|
||||
// edited if necessary.
|
||||
//
|
||||
// $Id: ami_scan.H,v 1.1 2004/02/05 17:26:52 jan Exp $
|
||||
//
|
||||
//
|
||||
#ifndef _AMI_SCAN_H
|
||||
#define _AMI_SCAN_H
|
||||
|
||||
#include <ami_err.h>
|
||||
#include <ami_stream.h>
|
||||
|
||||
typedef int AMI_SCAN_FLAG;
|
||||
|
||||
// The base class for scan objects.
|
||||
class AMI_scan_object {
|
||||
public:
|
||||
virtual AMI_err initialize(void) = 0;
|
||||
};
|
||||
|
||||
// BEGIN MECHANICALLY GENERATED CODE.
|
||||
|
||||
|
||||
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan_mac.H
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/24/94
|
||||
//
|
||||
// $Id: ami_scan.H,v 1.1 2004/02/05 17:26:52 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_SCAN_MAC_H
|
||||
#define _AMI_SCAN_MAC_H
|
||||
|
||||
// Macros for defining parameters to AMI_scan()
|
||||
#define __SPARM_BASE(T,io,n) AMI_STREAM< T ## n > *io ## n
|
||||
#define __SPARM_1(T,io) __SPARM_BASE(T,io,1)
|
||||
#define __SPARM_2(T,io) __SPARM_1(T,io), __SPARM_BASE(T,io,2)
|
||||
#define __SPARM_3(T,io) __SPARM_2(T,io), __SPARM_BASE(T,io,3)
|
||||
#define __SPARM_4(T,io) __SPARM_3(T,io), __SPARM_BASE(T,io,4)
|
||||
|
||||
// Macros for defining types in a template for AMI_scan()
|
||||
#define __STEMP_BASE(T,n) class T ## n
|
||||
#define __STEMP_1(T) __STEMP_BASE(T,1)
|
||||
#define __STEMP_2(T) __STEMP_1(T), __STEMP_BASE(T,2)
|
||||
#define __STEMP_3(T) __STEMP_2(T), __STEMP_BASE(T,3)
|
||||
#define __STEMP_4(T) __STEMP_3(T), __STEMP_BASE(T,4)
|
||||
|
||||
// Temporary space used within AMI_scan
|
||||
#define __STS_BASE(T,t,n) T ## n t ## n
|
||||
#define __STSPACE_1(T,t) __STS_BASE(T,t,1)
|
||||
#define __STSPACE_2(T,t) __STSPACE_1(T,t) ; __STS_BASE(T,t,2)
|
||||
#define __STSPACE_3(T,t) __STSPACE_2(T,t) ; __STS_BASE(T,t,3)
|
||||
#define __STSPACE_4(T,t) __STSPACE_3(T,t) ; __STS_BASE(T,t,4)
|
||||
|
||||
// An array of flags.
|
||||
#define __FSPACE(f,n) AMI_SCAN_FLAG f[n]
|
||||
|
||||
|
||||
// Check stream validity.
|
||||
#define __CHK_BASE(T,n) { \
|
||||
if (T ## n == NULL || T ## n -> status() != AMI_STREAM_STATUS_VALID) {\
|
||||
return AMI_ERROR_GENERIC_ERROR; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define __CHKSTR_1(T) __CHK_BASE(T,1)
|
||||
#define __CHKSTR_2(T) __CHKSTR_1(T) __CHK_BASE(T,2)
|
||||
#define __CHKSTR_3(T) __CHKSTR_2(T) __CHK_BASE(T,3)
|
||||
#define __CHKSTR_4(T) __CHKSTR_3(T) __CHK_BASE(T,4)
|
||||
|
||||
|
||||
// Rewind the input streams prior to performing the scan.
|
||||
#define __REW_BASE(T,n) { \
|
||||
if ((_ami_err_ = T ## n -> seek(0)) != AMI_ERROR_NO_ERROR) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define __REWIND_1(T) __REW_BASE(T,1)
|
||||
#define __REWIND_2(T) __REWIND_1(T) __REW_BASE(T,2)
|
||||
#define __REWIND_3(T) __REWIND_2(T) __REW_BASE(T,3)
|
||||
#define __REWIND_4(T) __REWIND_3(T) __REW_BASE(T,4)
|
||||
|
||||
|
||||
// Set the input flags to true before entering the do loop so that the
|
||||
// initial values will be read.
|
||||
#define __SET_IF_BASE(f,n) f[n-1] = 1
|
||||
|
||||
#define __SET_IF_1(f) __SET_IF_BASE(f,1)
|
||||
#define __SET_IF_2(f) __SET_IF_1(f); __SET_IF_BASE(f,2)
|
||||
#define __SET_IF_3(f) __SET_IF_2(f); __SET_IF_BASE(f,3)
|
||||
#define __SET_IF_4(f) __SET_IF_3(f); __SET_IF_BASE(f,4)
|
||||
|
||||
// If the flag is set, then read inputs into temporary space. Set the
|
||||
// flag based on whether the read was succesful or not. If it was
|
||||
// unsuccessful for any reason other than EOS, then break out of the
|
||||
// scan loop. If the flag is not currently set, then either the scan
|
||||
// management object did not take the last input or the last time we
|
||||
// tried to read from this file we failed. If we read successfully
|
||||
// last time, then reset the flag.
|
||||
#define __STSR_BASE(t,ts,f,g,e,n) \
|
||||
if (f[n-1]) { \
|
||||
if (!(f[n-1] = g[n-1] = \
|
||||
((e = ts ## n->read_item(&t ## n)) == AMI_ERROR_NO_ERROR))) { \
|
||||
if (e != AMI_ERROR_END_OF_STREAM) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
f[n-1] = g[n-1]; \
|
||||
}
|
||||
|
||||
#define __STS_READ_1(t,ts,f,g,e) __STSR_BASE(t,ts,f,g,e,1)
|
||||
#define __STS_READ_2(t,ts,f,g,e) __STS_READ_1(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,2)
|
||||
#define __STS_READ_3(t,ts,f,g,e) __STS_READ_2(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,3)
|
||||
#define __STS_READ_4(t,ts,f,g,e) __STS_READ_3(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,4)
|
||||
|
||||
// Write outputs. Only write if the flag is set. If there is an
|
||||
// error during the write, then break out of the scan loop.
|
||||
#define __STSW_BASE(u,us,f,e,n) \
|
||||
if (f[n-1] && (e = us ## n -> write_item(u ## n)) != AMI_ERROR_NO_ERROR) { \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define __STS_WRITE_1(u,us,f,e) __STSW_BASE(u,us,f,e,1)
|
||||
#define __STS_WRITE_2(u,us,f,e) __STS_WRITE_1(u,us,f,e) __STSW_BASE(u,us,f,e,2)
|
||||
#define __STS_WRITE_3(u,us,f,e) __STS_WRITE_2(u,us,f,e) __STSW_BASE(u,us,f,e,3)
|
||||
#define __STS_WRITE_4(u,us,f,e) __STS_WRITE_3(u,us,f,e) __STSW_BASE(u,us,f,e,4)
|
||||
|
||||
|
||||
// Arguments to the operate() call
|
||||
#define __SCA_BASE(t,n) t ## n
|
||||
#define __SCALL_ARGS_1(t) __SCA_BASE(t,1)
|
||||
#define __SCALL_ARGS_2(t) __SCALL_ARGS_1(t), __SCA_BASE(t,2)
|
||||
#define __SCALL_ARGS_3(t) __SCALL_ARGS_2(t), __SCA_BASE(t,3)
|
||||
#define __SCALL_ARGS_4(t) __SCALL_ARGS_3(t), __SCA_BASE(t,4)
|
||||
|
||||
// Operate on the inputs to produce the outputs.
|
||||
#define __SCALL_BASE(t,nt,if,sop,u,nu,of) \
|
||||
sop->operate(__SCALL_ARGS_ ## nt (*t), if, __SCALL_ARGS_ ## nu (&u), of)
|
||||
|
||||
#define __SCALL_OP_1_1(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,1,of)
|
||||
#define __SCALL_OP_1_2(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,2,of)
|
||||
#define __SCALL_OP_1_3(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,3,of)
|
||||
#define __SCALL_OP_1_4(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_2_1(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,1,of)
|
||||
#define __SCALL_OP_2_2(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,2,of)
|
||||
#define __SCALL_OP_2_3(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,3,of)
|
||||
#define __SCALL_OP_2_4(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_3_1(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,1,of)
|
||||
#define __SCALL_OP_3_2(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,2,of)
|
||||
#define __SCALL_OP_3_3(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,3,of)
|
||||
#define __SCALL_OP_3_4(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_4_1(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,1,of)
|
||||
#define __SCALL_OP_4_2(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,2,of)
|
||||
#define __SCALL_OP_4_3(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,3,of)
|
||||
#define __SCALL_OP_4_4(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,4,of)
|
||||
|
||||
// Handle the no input case.
|
||||
#define __SCALL_BASE_O(sop,u,nu,of) \
|
||||
sop->operate(__SCALL_ARGS_ ## nu (&u), of)
|
||||
|
||||
#define __SCALL_OP_O_1(sop,u,of) __SCALL_BASE_O(sop,u,1,of)
|
||||
#define __SCALL_OP_O_2(sop,u,of) __SCALL_BASE_O(sop,u,2,of)
|
||||
#define __SCALL_OP_O_3(sop,u,of) __SCALL_BASE_O(sop,u,3,of)
|
||||
#define __SCALL_OP_O_4(sop,u,of) __SCALL_BASE_O(sop,u,4,of)
|
||||
|
||||
// Handle the no output case.
|
||||
#define __SCALL_BASE_I(t,nt,if,sop) \
|
||||
sop->operate(__SCALL_ARGS_ ## nt (*t), if)
|
||||
|
||||
#define __SCALL_OP_I_1(t,if,sop) __SCALL_BASE_I(t,1,if,sop)
|
||||
#define __SCALL_OP_I_2(t,if,sop) __SCALL_BASE_I(t,2,if,sop)
|
||||
#define __SCALL_OP_I_3(t,if,sop) __SCALL_BASE_I(t,3,if,sop)
|
||||
#define __SCALL_OP_I_4(t,if,sop) __SCALL_BASE_I(t,4,if,sop)
|
||||
|
||||
|
||||
// The template for the whole AMI_scan(), with inputs and outputs.
|
||||
#define __STEMPLATE(in_arity, out_arity) \
|
||||
template< __STEMP_ ## in_arity (T), class SC, __STEMP_ ## out_arity (U) > \
|
||||
AMI_err AMI_scan( __SPARM_ ## in_arity (T,_ts_), \
|
||||
SC *soper, __SPARM_ ## out_arity (U,_us_)) \
|
||||
{ \
|
||||
__STSPACE_ ## in_arity (T,*_t_); \
|
||||
__STSPACE_ ## out_arity (U,_u_); \
|
||||
\
|
||||
__FSPACE(_if_,in_arity); \
|
||||
__FSPACE(_lif_,in_arity); \
|
||||
__FSPACE(_of_,out_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## in_arity (_ts_) \
|
||||
__CHKSTR_ ## out_arity (_us_) \
|
||||
__REWIND_ ## in_arity (_ts_) \
|
||||
soper->initialize(); \
|
||||
\
|
||||
__SET_IF_ ## in_arity (_if_); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
__STS_READ_ ## in_arity (_t_,_ts_,_if_,_lif_,_ami_err_) \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_ ## in_arity ## _ ## \
|
||||
out_arity(_t_,_if_,soper,_u_,_of_); \
|
||||
\
|
||||
__STS_WRITE_ ## out_arity(_u_,_us_,_of_,_ami_err_) \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
// The template for the whole AMI_scan(), with no inputs. This is
|
||||
// based on __STEMPLATE_() and could be merged into one big macro at
|
||||
// the expense of having to define multiple versions of __STEMP_N()
|
||||
// and __SPARM_N() to handle the case N = 0.
|
||||
#define __STEMPLATE_O(out_arity) \
|
||||
template< class SC, __STEMP_ ## out_arity (U) > \
|
||||
AMI_err AMI_scan( SC *soper, __SPARM_ ## out_arity (U,_us_)) \
|
||||
{ \
|
||||
__STSPACE_ ## out_arity (U,_u_); \
|
||||
\
|
||||
__FSPACE(_of_,out_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## out_arity (_us_) \
|
||||
soper->initialize(); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_O_ ## out_arity(soper,_u_,_of_); \
|
||||
\
|
||||
__STS_WRITE_ ## out_arity(_u_,_us_,_of_,_ami_err_) \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
// The template for the whole AMI_scan(), with no outputs.
|
||||
#define __STEMPLATE_I(in_arity) \
|
||||
template< __STEMP_ ## in_arity (T), class SC > \
|
||||
AMI_err AMI_scan( __SPARM_ ## in_arity (T,_ts_), SC *soper) \
|
||||
{ \
|
||||
__STSPACE_ ## in_arity (T,*_t_); \
|
||||
\
|
||||
__FSPACE(_if_,in_arity); \
|
||||
__FSPACE(_lif_,in_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## in_arity (_ts_) \
|
||||
__REWIND_ ## in_arity (_ts_); \
|
||||
\
|
||||
soper->initialize(); \
|
||||
\
|
||||
__SET_IF_ ## in_arity (_if_); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
__STS_READ_ ## in_arity (_t_,_ts_,_if_,_lif_,_ami_err_) \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_I_ ## in_arity (_t_,_if_,soper); \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
|
||||
// Finally, the templates themsleves.
|
||||
|
||||
__STEMPLATE(1,1); __STEMPLATE(1,2); __STEMPLATE(1,3); __STEMPLATE(1,4);
|
||||
__STEMPLATE(2,1); __STEMPLATE(2,2); __STEMPLATE(2,3); __STEMPLATE(2,4);
|
||||
__STEMPLATE(3,1); __STEMPLATE(3,2); __STEMPLATE(3,3); __STEMPLATE(3,4);
|
||||
__STEMPLATE(4,1); __STEMPLATE(4,2); __STEMPLATE(4,3); __STEMPLATE(4,4);
|
||||
|
||||
__STEMPLATE_O(1); __STEMPLATE_O(2); __STEMPLATE_O(3); __STEMPLATE_O(4);
|
||||
|
||||
__STEMPLATE_I(1); __STEMPLATE_I(2); __STEMPLATE_I(3); __STEMPLATE_I(4);
|
||||
|
||||
#endif // _AMI_SCAN_MAC_H
|
||||
|
||||
// END MECHANICALLY GENERATED CODE.
|
||||
|
||||
// The following Id string applies to the tail used in the processs of
|
||||
// generating this file. The tail, stored in ami_scan.H.tail, may be
|
||||
// edited if necessary.
|
||||
//
|
||||
// $Id: ami_scan.H,v 1.1 2004/02/05 17:26:52 jan Exp $
|
||||
|
||||
// A class template for copying streams by scanning.
|
||||
template<class T>
|
||||
class AMI_identity_scan : public AMI_scan_object {
|
||||
public:
|
||||
AMI_err initialize(void) { return AMI_ERROR_NO_ERROR; }
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_identity_scan<T>::operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
if (*sfout = *sfin) {
|
||||
*out = in;
|
||||
return AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A copy function for streams
|
||||
template<class T>
|
||||
AMI_err AMI_copy_stream(AMI_stream_base<T> *t, AMI_stream_base<T> *s)
|
||||
{
|
||||
AMI_identity_scan<T> id;
|
||||
|
||||
return AMI_scan(t, &id, s);
|
||||
}
|
||||
|
||||
#endif // _AMI_SCAN_H
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Header Created: 5/25/94
|
||||
//
|
||||
// This file was created mechanically by make, as specified in Makefile.
|
||||
// There is no reason it should ever be edited by hand.
|
||||
//
|
||||
// The following Id string applies to the header used in the processs of
|
||||
// generating this file. The header, stored in ami_scan.h.head, may be
|
||||
// edited if necessary.
|
||||
//
|
||||
// $Id: ami_scan.h.head,v 1.5 2003/04/20 23:12:42 tavi Exp $
|
||||
//
|
||||
//
|
||||
#ifndef _AMI_SCAN_H
|
||||
#define _AMI_SCAN_H
|
||||
|
||||
#include <ami_err.h>
|
||||
#include <ami_stream.h>
|
||||
|
||||
typedef int AMI_SCAN_FLAG;
|
||||
|
||||
// The base class for scan objects.
|
||||
class AMI_scan_object {
|
||||
public:
|
||||
virtual AMI_err initialize(void) = 0;
|
||||
};
|
||||
|
||||
// BEGIN MECHANICALLY GENERATED CODE.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
// END MECHANICALLY GENERATED CODE.
|
||||
|
||||
// The following Id string applies to the tail used in the processs of
|
||||
// generating this file. The tail, stored in ami_scan.h.tail, may be
|
||||
// edited if necessary.
|
||||
//
|
||||
// $Id: ami_scan.h.tail,v 1.3 2002/01/14 16:02:43 tavi Exp $
|
||||
|
||||
// A class template for copying streams by scanning.
|
||||
template<class T>
|
||||
class AMI_identity_scan : public AMI_scan_object {
|
||||
public:
|
||||
AMI_err initialize(void) { return AMI_ERROR_NO_ERROR; }
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_identity_scan<T>::operate(const T &in, AMI_SCAN_FLAG *sfin,
|
||||
T *out, AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
if (*sfout = *sfin) {
|
||||
*out = in;
|
||||
return AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A copy function for streams
|
||||
template<class T>
|
||||
AMI_err AMI_copy_stream(AMI_stream_base<T> *t, AMI_stream_base<T> *s)
|
||||
{
|
||||
AMI_identity_scan<T> id;
|
||||
|
||||
return AMI_scan(t, &id, s);
|
||||
}
|
||||
|
||||
#endif // _AMI_SCAN_H
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan_mac.cpp
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/25/94
|
||||
//
|
||||
// This file exists only for the purpose of building ami_scan.h.
|
||||
// The Makefile will invoke the C preprocessor on it in order to
|
||||
// generate ami_scan.h, which is theactual header file that TPIE
|
||||
// programs will include.
|
||||
//
|
||||
// $Id: ami_scan_mac.cpp,v 1.1 1994/05/25 19:35:06 dev Exp $
|
||||
//
|
||||
|
||||
#include "ami_scan_mac.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan_mac.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/24/94
|
||||
//
|
||||
// $Id: ami_scan_mac.h,v 1.10 2003/04/25 00:06:56 tavi Exp $
|
||||
//
|
||||
#ifndef _AMI_SCAN_MAC_H
|
||||
#define _AMI_SCAN_MAC_H
|
||||
|
||||
// Macros for defining parameters to AMI_scan()
|
||||
#define __SPARM_BASE(T,io,n) AMI_STREAM< T ## n > *io ## n
|
||||
#define __SPARM_1(T,io) __SPARM_BASE(T,io,1)
|
||||
#define __SPARM_2(T,io) __SPARM_1(T,io), __SPARM_BASE(T,io,2)
|
||||
#define __SPARM_3(T,io) __SPARM_2(T,io), __SPARM_BASE(T,io,3)
|
||||
#define __SPARM_4(T,io) __SPARM_3(T,io), __SPARM_BASE(T,io,4)
|
||||
|
||||
// Macros for defining types in a template for AMI_scan()
|
||||
#define __STEMP_BASE(T,n) class T ## n
|
||||
#define __STEMP_1(T) __STEMP_BASE(T,1)
|
||||
#define __STEMP_2(T) __STEMP_1(T), __STEMP_BASE(T,2)
|
||||
#define __STEMP_3(T) __STEMP_2(T), __STEMP_BASE(T,3)
|
||||
#define __STEMP_4(T) __STEMP_3(T), __STEMP_BASE(T,4)
|
||||
|
||||
// Temporary space used within AMI_scan
|
||||
#define __STS_BASE(T,t,n) T ## n t ## n
|
||||
#define __STSPACE_1(T,t) __STS_BASE(T,t,1)
|
||||
#define __STSPACE_2(T,t) __STSPACE_1(T,t) ; __STS_BASE(T,t,2)
|
||||
#define __STSPACE_3(T,t) __STSPACE_2(T,t) ; __STS_BASE(T,t,3)
|
||||
#define __STSPACE_4(T,t) __STSPACE_3(T,t) ; __STS_BASE(T,t,4)
|
||||
|
||||
// An array of flags.
|
||||
#define __FSPACE(f,n) AMI_SCAN_FLAG f[n]
|
||||
|
||||
|
||||
// Check stream validity.
|
||||
#define __CHK_BASE(T,n) { \
|
||||
if (T ## n == NULL || T ## n -> status() != AMI_STREAM_STATUS_VALID) {\
|
||||
return AMI_ERROR_GENERIC_ERROR; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define __CHKSTR_1(T) __CHK_BASE(T,1)
|
||||
#define __CHKSTR_2(T) __CHKSTR_1(T) __CHK_BASE(T,2)
|
||||
#define __CHKSTR_3(T) __CHKSTR_2(T) __CHK_BASE(T,3)
|
||||
#define __CHKSTR_4(T) __CHKSTR_3(T) __CHK_BASE(T,4)
|
||||
|
||||
|
||||
// Rewind the input streams prior to performing the scan.
|
||||
#define __REW_BASE(T,n) { \
|
||||
if ((_ami_err_ = T ## n -> seek(0)) != AMI_ERROR_NO_ERROR) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define __REWIND_1(T) __REW_BASE(T,1)
|
||||
#define __REWIND_2(T) __REWIND_1(T) __REW_BASE(T,2)
|
||||
#define __REWIND_3(T) __REWIND_2(T) __REW_BASE(T,3)
|
||||
#define __REWIND_4(T) __REWIND_3(T) __REW_BASE(T,4)
|
||||
|
||||
|
||||
// Set the input flags to true before entering the do loop so that the
|
||||
// initial values will be read.
|
||||
#define __SET_IF_BASE(f,n) f[n-1] = 1
|
||||
|
||||
#define __SET_IF_1(f) __SET_IF_BASE(f,1)
|
||||
#define __SET_IF_2(f) __SET_IF_1(f); __SET_IF_BASE(f,2)
|
||||
#define __SET_IF_3(f) __SET_IF_2(f); __SET_IF_BASE(f,3)
|
||||
#define __SET_IF_4(f) __SET_IF_3(f); __SET_IF_BASE(f,4)
|
||||
|
||||
// If the flag is set, then read inputs into temporary space. Set the
|
||||
// flag based on whether the read was succesful or not. If it was
|
||||
// unsuccessful for any reason other than EOS, then break out of the
|
||||
// scan loop. If the flag is not currently set, then either the scan
|
||||
// management object did not take the last input or the last time we
|
||||
// tried to read from this file we failed. If we read successfully
|
||||
// last time, then reset the flag.
|
||||
#define __STSR_BASE(t,ts,f,g,e,n) \
|
||||
if (f[n-1]) { \
|
||||
if (!(f[n-1] = g[n-1] = \
|
||||
((e = ts ## n->read_item(&t ## n)) == AMI_ERROR_NO_ERROR))) { \
|
||||
if (e != AMI_ERROR_END_OF_STREAM) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
f[n-1] = g[n-1]; \
|
||||
}
|
||||
|
||||
#define __STS_READ_1(t,ts,f,g,e) __STSR_BASE(t,ts,f,g,e,1)
|
||||
#define __STS_READ_2(t,ts,f,g,e) __STS_READ_1(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,2)
|
||||
#define __STS_READ_3(t,ts,f,g,e) __STS_READ_2(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,3)
|
||||
#define __STS_READ_4(t,ts,f,g,e) __STS_READ_3(t,ts,f,g,e) \
|
||||
__STSR_BASE(t,ts,f,g,e,4)
|
||||
|
||||
// Write outputs. Only write if the flag is set. If there is an
|
||||
// error during the write, then break out of the scan loop.
|
||||
#define __STSW_BASE(u,us,f,e,n) \
|
||||
if (f[n-1] && (e = us ## n -> write_item(u ## n)) != AMI_ERROR_NO_ERROR) { \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define __STS_WRITE_1(u,us,f,e) __STSW_BASE(u,us,f,e,1)
|
||||
#define __STS_WRITE_2(u,us,f,e) __STS_WRITE_1(u,us,f,e) __STSW_BASE(u,us,f,e,2)
|
||||
#define __STS_WRITE_3(u,us,f,e) __STS_WRITE_2(u,us,f,e) __STSW_BASE(u,us,f,e,3)
|
||||
#define __STS_WRITE_4(u,us,f,e) __STS_WRITE_3(u,us,f,e) __STSW_BASE(u,us,f,e,4)
|
||||
|
||||
|
||||
// Arguments to the operate() call
|
||||
#define __SCA_BASE(t,n) t ## n
|
||||
#define __SCALL_ARGS_1(t) __SCA_BASE(t,1)
|
||||
#define __SCALL_ARGS_2(t) __SCALL_ARGS_1(t), __SCA_BASE(t,2)
|
||||
#define __SCALL_ARGS_3(t) __SCALL_ARGS_2(t), __SCA_BASE(t,3)
|
||||
#define __SCALL_ARGS_4(t) __SCALL_ARGS_3(t), __SCA_BASE(t,4)
|
||||
|
||||
// Operate on the inputs to produce the outputs.
|
||||
#define __SCALL_BASE(t,nt,if,sop,u,nu,of) \
|
||||
sop->operate(__SCALL_ARGS_ ## nt (*t), if, __SCALL_ARGS_ ## nu (&u), of)
|
||||
|
||||
#define __SCALL_OP_1_1(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,1,of)
|
||||
#define __SCALL_OP_1_2(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,2,of)
|
||||
#define __SCALL_OP_1_3(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,3,of)
|
||||
#define __SCALL_OP_1_4(t,if,sop,u,of) __SCALL_BASE(t,1,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_2_1(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,1,of)
|
||||
#define __SCALL_OP_2_2(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,2,of)
|
||||
#define __SCALL_OP_2_3(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,3,of)
|
||||
#define __SCALL_OP_2_4(t,if,sop,u,of) __SCALL_BASE(t,2,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_3_1(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,1,of)
|
||||
#define __SCALL_OP_3_2(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,2,of)
|
||||
#define __SCALL_OP_3_3(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,3,of)
|
||||
#define __SCALL_OP_3_4(t,if,sop,u,of) __SCALL_BASE(t,3,if,sop,u,4,of)
|
||||
|
||||
#define __SCALL_OP_4_1(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,1,of)
|
||||
#define __SCALL_OP_4_2(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,2,of)
|
||||
#define __SCALL_OP_4_3(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,3,of)
|
||||
#define __SCALL_OP_4_4(t,if,sop,u,of) __SCALL_BASE(t,4,if,sop,u,4,of)
|
||||
|
||||
// Handle the no input case.
|
||||
#define __SCALL_BASE_O(sop,u,nu,of) \
|
||||
sop->operate(__SCALL_ARGS_ ## nu (&u), of)
|
||||
|
||||
#define __SCALL_OP_O_1(sop,u,of) __SCALL_BASE_O(sop,u,1,of)
|
||||
#define __SCALL_OP_O_2(sop,u,of) __SCALL_BASE_O(sop,u,2,of)
|
||||
#define __SCALL_OP_O_3(sop,u,of) __SCALL_BASE_O(sop,u,3,of)
|
||||
#define __SCALL_OP_O_4(sop,u,of) __SCALL_BASE_O(sop,u,4,of)
|
||||
|
||||
// Handle the no output case.
|
||||
#define __SCALL_BASE_I(t,nt,if,sop) \
|
||||
sop->operate(__SCALL_ARGS_ ## nt (*t), if)
|
||||
|
||||
#define __SCALL_OP_I_1(t,if,sop) __SCALL_BASE_I(t,1,if,sop)
|
||||
#define __SCALL_OP_I_2(t,if,sop) __SCALL_BASE_I(t,2,if,sop)
|
||||
#define __SCALL_OP_I_3(t,if,sop) __SCALL_BASE_I(t,3,if,sop)
|
||||
#define __SCALL_OP_I_4(t,if,sop) __SCALL_BASE_I(t,4,if,sop)
|
||||
|
||||
|
||||
// The template for the whole AMI_scan(), with inputs and outputs.
|
||||
#define __STEMPLATE(in_arity, out_arity) \
|
||||
template< __STEMP_ ## in_arity (T), class SC, __STEMP_ ## out_arity (U) > \
|
||||
AMI_err AMI_scan( __SPARM_ ## in_arity (T,_ts_), \
|
||||
SC *soper, __SPARM_ ## out_arity (U,_us_)) \
|
||||
{ \
|
||||
__STSPACE_ ## in_arity (T,*_t_); \
|
||||
__STSPACE_ ## out_arity (U,_u_); \
|
||||
\
|
||||
__FSPACE(_if_,in_arity); \
|
||||
__FSPACE(_lif_,in_arity); \
|
||||
__FSPACE(_of_,out_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## in_arity (_ts_) \
|
||||
__CHKSTR_ ## out_arity (_us_) \
|
||||
__REWIND_ ## in_arity (_ts_) \
|
||||
soper->initialize(); \
|
||||
\
|
||||
__SET_IF_ ## in_arity (_if_); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
__STS_READ_ ## in_arity (_t_,_ts_,_if_,_lif_,_ami_err_) \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_ ## in_arity ## _ ## \
|
||||
out_arity(_t_,_if_,soper,_u_,_of_); \
|
||||
\
|
||||
__STS_WRITE_ ## out_arity(_u_,_us_,_of_,_ami_err_) \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
// The template for the whole AMI_scan(), with no inputs. This is
|
||||
// based on __STEMPLATE_() and could be merged into one big macro at
|
||||
// the expense of having to define multiple versions of __STEMP_N()
|
||||
// and __SPARM_N() to handle the case N = 0.
|
||||
#define __STEMPLATE_O(out_arity) \
|
||||
template< class SC, __STEMP_ ## out_arity (U) > \
|
||||
AMI_err AMI_scan( SC *soper, __SPARM_ ## out_arity (U,_us_)) \
|
||||
{ \
|
||||
__STSPACE_ ## out_arity (U,_u_); \
|
||||
\
|
||||
__FSPACE(_of_,out_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## out_arity (_us_) \
|
||||
soper->initialize(); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_O_ ## out_arity(soper,_u_,_of_); \
|
||||
\
|
||||
__STS_WRITE_ ## out_arity(_u_,_us_,_of_,_ami_err_) \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
// The template for the whole AMI_scan(), with no outputs.
|
||||
#define __STEMPLATE_I(in_arity) \
|
||||
template< __STEMP_ ## in_arity (T), class SC > \
|
||||
AMI_err AMI_scan( __SPARM_ ## in_arity (T,_ts_), SC *soper) \
|
||||
{ \
|
||||
__STSPACE_ ## in_arity (T,*_t_); \
|
||||
\
|
||||
__FSPACE(_if_,in_arity); \
|
||||
__FSPACE(_lif_,in_arity); \
|
||||
\
|
||||
AMI_err _op_err_, _ami_err_; \
|
||||
\
|
||||
__CHKSTR_ ## in_arity (_ts_) \
|
||||
__REWIND_ ## in_arity (_ts_); \
|
||||
\
|
||||
soper->initialize(); \
|
||||
\
|
||||
__SET_IF_ ## in_arity (_if_); \
|
||||
\
|
||||
do { \
|
||||
\
|
||||
__STS_READ_ ## in_arity (_t_,_ts_,_if_,_lif_,_ami_err_) \
|
||||
\
|
||||
_op_err_ = __SCALL_OP_I_ ## in_arity (_t_,_if_,soper); \
|
||||
\
|
||||
} while (_op_err_ == AMI_SCAN_CONTINUE); \
|
||||
\
|
||||
if ((_ami_err_ != AMI_ERROR_NO_ERROR) && \
|
||||
(_ami_err_ != AMI_ERROR_END_OF_STREAM)) { \
|
||||
return _ami_err_; \
|
||||
} \
|
||||
\
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
}
|
||||
|
||||
|
||||
// Finally, the templates themsleves.
|
||||
|
||||
__STEMPLATE(1,1); __STEMPLATE(1,2); __STEMPLATE(1,3); __STEMPLATE(1,4);
|
||||
__STEMPLATE(2,1); __STEMPLATE(2,2); __STEMPLATE(2,3); __STEMPLATE(2,4);
|
||||
__STEMPLATE(3,1); __STEMPLATE(3,2); __STEMPLATE(3,3); __STEMPLATE(3,4);
|
||||
__STEMPLATE(4,1); __STEMPLATE(4,2); __STEMPLATE(4,3); __STEMPLATE(4,4);
|
||||
|
||||
__STEMPLATE_O(1); __STEMPLATE_O(2); __STEMPLATE_O(3); __STEMPLATE_O(4);
|
||||
|
||||
__STEMPLATE_I(1); __STEMPLATE_I(2); __STEMPLATE_I(3); __STEMPLATE_I(4);
|
||||
|
||||
#endif // _AMI_SCAN_MAC_H
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: ami_scan_utils.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 8/31/94
|
||||
//
|
||||
// $Id: ami_scan_utils.h,v 1.10 2003/09/12 01:46:38 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_SCAN_UTILS_H
|
||||
#define _AMI_SCAN_UTILS_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// Get definitions for working with Unix and Windows.
|
||||
#include <portability.h>
|
||||
// Get the AMI_scan_object definition.
|
||||
#include <ami_scan.h>
|
||||
|
||||
// A scan object class template for reading the contents of an
|
||||
// ordinary C++ input stream into a TPIE stream. It works with
|
||||
// streams of any type for which an >> operator is defined for C++
|
||||
// stream input.
|
||||
|
||||
template<class T> class cxx_istream_scan : AMI_scan_object {
|
||||
private:
|
||||
istream *is;
|
||||
public:
|
||||
cxx_istream_scan(istream *instr = &cin);
|
||||
AMI_err initialize(void);
|
||||
AMI_err operate(T *out, AMI_SCAN_FLAG *sfout);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
cxx_istream_scan<T>::cxx_istream_scan(istream *instr) : is(instr)
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err cxx_istream_scan<T>::initialize(void)
|
||||
{
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err cxx_istream_scan<T>::operate(T *out, AMI_SCAN_FLAG *sfout)
|
||||
{
|
||||
if (*is >> *out) {
|
||||
*sfout = true;
|
||||
return AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
*sfout = false;
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// A scan object to print the contents of a TPIE stream to a C++
|
||||
// output stream. One item per line is written. It works with
|
||||
// streams of any type for which an << operator is defined for C++
|
||||
// stream output.
|
||||
|
||||
template<class T> class cxx_ostream_scan : AMI_scan_object {
|
||||
private:
|
||||
ostream *os;
|
||||
public:
|
||||
cxx_ostream_scan(ostream *outstr = &cout);
|
||||
AMI_err initialize(void);
|
||||
AMI_err operate(const T &in, AMI_SCAN_FLAG *sfin);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
cxx_ostream_scan<T>::cxx_ostream_scan(ostream *outstr) : os(outstr)
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err cxx_ostream_scan<T>::initialize(void)
|
||||
{
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_err cxx_ostream_scan<T>::operate(const T &in, AMI_SCAN_FLAG *sfin)
|
||||
{
|
||||
if (*sfin) {
|
||||
*os << in << '\n';
|
||||
return AMI_SCAN_CONTINUE;
|
||||
} else {
|
||||
return AMI_SCAN_DONE;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _AMI_SCAN_UTILS_H
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// File: ami_sort.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 6/10/94
|
||||
//
|
||||
// $Id: ami_sort.h,v 1.11 2003/09/27 07:00:48 tavi Exp $
|
||||
//
|
||||
#ifndef _AMI_SORT_H
|
||||
#define _AMI_SORT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#define CONST const
|
||||
|
||||
#include <ami_stream.h>
|
||||
|
||||
#ifdef AMI_STREAM_IMP_SINGLE
|
||||
#include <ami_sort_single.h>
|
||||
#include <ami_optimized_sort.h>
|
||||
#include <ami_sort_single_dh.h>
|
||||
#endif
|
||||
|
||||
#endif // _AMI_SORT_H
|
||||
@@ -0,0 +1,467 @@
|
||||
//
|
||||
// File: ami_sort_single.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 9/28/94
|
||||
//
|
||||
// $Id: ami_sort_single.h,v 1.22 2005/01/14 18:40:35 tavi Exp $
|
||||
//
|
||||
// Merge sorting for the AMI_STREAM_IMP_SINGLE implementation.
|
||||
//
|
||||
#ifndef _AMI_SORT_SINGLE_H
|
||||
#define _AMI_SORT_SINGLE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#ifndef AMI_STREAM_IMP_SINGLE
|
||||
# warning Including __FILE__ when AMI_STREAM_IMP_SINGLE undefined.
|
||||
#endif
|
||||
|
||||
// For use in core by main_mem_operate().
|
||||
#include <quicksort.h>
|
||||
#include <pqueue_heap.h>
|
||||
|
||||
#include <ami_merge.h>
|
||||
#include <ami_optimized_merge.h>
|
||||
|
||||
|
||||
// A class of merge objects for merge sorting objects of type T. We
|
||||
// will actually use one of three subclasses of this class which use
|
||||
// either a comparison function, a comparison object, or the binary
|
||||
// comparison operator <.
|
||||
|
||||
template <class T, class Q>
|
||||
class merge_sort_manager /*: public AMI_merge_base<T> */{
|
||||
private:
|
||||
bool use_operator;
|
||||
protected:
|
||||
Q *pq;
|
||||
arity_t input_arity;
|
||||
#if DEBUG_ASSERTIONS
|
||||
unsigned int input_count, output_count;
|
||||
#endif
|
||||
public:
|
||||
merge_sort_manager(void);
|
||||
virtual ~merge_sort_manager(void);
|
||||
inline AMI_err operate(CONST T * CONST *in, AMI_merge_flag *taken_flags,
|
||||
int &taken_index, T *out);
|
||||
TPIE_OS_SIZE_T space_usage_per_stream(void);
|
||||
};
|
||||
|
||||
|
||||
template<class T, class Q>
|
||||
merge_sort_manager<T,Q>::merge_sort_manager(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
merge_sort_manager<T,Q>::~merge_sort_manager(void)
|
||||
{
|
||||
if (pq != NULL) {
|
||||
delete pq;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T, class Q>
|
||||
TPIE_OS_SIZE_T merge_sort_manager<T,Q>::space_usage_per_stream(void)
|
||||
{
|
||||
return sizeof(arity_t) + sizeof(T);
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
AMI_err merge_sort_manager<T,Q>::operate(CONST T * CONST *in,
|
||||
AMI_merge_flag * /*taken_flags*/,
|
||||
int &taken_index,
|
||||
T *out)
|
||||
{
|
||||
bool pqret;
|
||||
|
||||
// If the queue is empty, we are done. There should be no more
|
||||
// inputs.
|
||||
if (!pq->num_elts()) {
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
arity_t ii;
|
||||
|
||||
for (ii = input_arity; ii--; ) {
|
||||
tp_assert(in[ii] == NULL, "Empty queue but more input.");
|
||||
}
|
||||
|
||||
tp_assert(input_count == output_count,
|
||||
"Merge done, input_count = " << input_count <<
|
||||
", output_count = " << output_count << '.');
|
||||
#endif
|
||||
|
||||
// Delete the queue, which may take up a lot of main memory.
|
||||
tp_assert(pq != NULL, "pq == NULL");
|
||||
delete pq;
|
||||
pq = NULL;
|
||||
|
||||
return AMI_MERGE_DONE;
|
||||
|
||||
} else {
|
||||
arity_t min_source;
|
||||
T min_t;
|
||||
|
||||
pqret = pq->extract_min(min_source,min_t);
|
||||
tp_assert(pqret, "pq->extract_min() failed.");
|
||||
*out = min_t;
|
||||
if (in[min_source] != NULL) {
|
||||
pqret = pq->insert(min_source,*in[min_source]);
|
||||
tp_assert(pqret, "pq->insert() failed.");
|
||||
taken_index = min_source;
|
||||
//taken_flags[min_source] = 1;
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count++;
|
||||
#endif
|
||||
} else {
|
||||
taken_index = -1;
|
||||
}
|
||||
#if DEBUG_ASSERTIONS
|
||||
output_count++;
|
||||
#endif
|
||||
return AMI_MERGE_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Operator based merge sort manager.
|
||||
|
||||
template <class T, class Q>
|
||||
class merge_sort_manager_op : public merge_sort_manager<T,Q> {
|
||||
private:
|
||||
Q *new_pqueue(arity_t arity);
|
||||
protected:
|
||||
using merge_sort_manager<T,Q>::pq;
|
||||
using merge_sort_manager<T,Q>::input_arity;
|
||||
#if DEBUG_ASSERTIONS
|
||||
using merge_sort_manager<T,Q>::input_count;
|
||||
using merge_sort_manager<T,Q>::output_count;
|
||||
#endif
|
||||
|
||||
public:
|
||||
merge_sort_manager_op(void);
|
||||
virtual ~merge_sort_manager_op(void);
|
||||
AMI_err main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len);
|
||||
TPIE_OS_SIZE_T space_usage_overhead(void);
|
||||
AMI_err initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index);
|
||||
};
|
||||
|
||||
template<class T,class Q>
|
||||
merge_sort_manager_op<T,Q>::merge_sort_manager_op(void)
|
||||
{
|
||||
pq = NULL;
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
Q *merge_sort_manager_op<T,Q>::new_pqueue(arity_t arity)
|
||||
{
|
||||
return pq = new Q (arity);
|
||||
}
|
||||
|
||||
template<class T,class Q>
|
||||
merge_sort_manager_op<T,Q>::~merge_sort_manager_op(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T,class Q>
|
||||
AMI_err merge_sort_manager_op<T,Q>::main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len)
|
||||
{
|
||||
quick_sort_op(mm_stream, len);
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T,class Q>
|
||||
TPIE_OS_SIZE_T merge_sort_manager_op<T,Q>::space_usage_overhead(void)
|
||||
{
|
||||
return sizeof(Q);
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
AMI_err merge_sort_manager_op<T,Q>::initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index)
|
||||
{
|
||||
arity_t ii;
|
||||
|
||||
input_arity = arity;
|
||||
|
||||
bool pqret;
|
||||
|
||||
tp_assert(arity > 0, "Input arity is 0.");
|
||||
|
||||
if (pq != NULL) {
|
||||
delete pq;
|
||||
pq = NULL;
|
||||
}
|
||||
new_pqueue(arity);
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count = output_count = 0;
|
||||
#endif
|
||||
for (ii = arity; ii--; ) {
|
||||
if (in[ii] != NULL) {
|
||||
taken_flags[ii] = 1;
|
||||
pqret = pq->insert(ii,*in[ii]);
|
||||
tp_assert(pqret, "pq->insert() failed.");
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count++;
|
||||
#endif
|
||||
} else {
|
||||
taken_flags[ii] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
taken_index = -1;
|
||||
return AMI_MERGE_READ_MULTIPLE;
|
||||
}
|
||||
|
||||
// Comparison object based merge sort manager.
|
||||
|
||||
template <class T, class Q, class CMPR>
|
||||
class merge_sort_manager_obj : public merge_sort_manager<T,Q> {
|
||||
private:
|
||||
CMPR *cmp_o;
|
||||
Q *new_pqueue(arity_t arity);
|
||||
protected:
|
||||
using merge_sort_manager<T,Q>::pq;
|
||||
using merge_sort_manager<T,Q>::input_arity;
|
||||
#if DEBUG_ASSERTIONS
|
||||
using merge_sort_manager<T,Q>::input_count;
|
||||
using merge_sort_manager<T,Q>::output_count;
|
||||
#endif
|
||||
|
||||
public:
|
||||
merge_sort_manager_obj(CMPR *cmp);
|
||||
virtual ~merge_sort_manager_obj(void);
|
||||
AMI_err main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len);
|
||||
TPIE_OS_SIZE_T space_usage_overhead(void);
|
||||
AMI_err initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index);
|
||||
};
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
merge_sort_manager_obj<T,Q,CMPR>::merge_sort_manager_obj(CMPR *cmp)
|
||||
{
|
||||
cmp_o = cmp;
|
||||
pq = NULL;
|
||||
}
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
Q *merge_sort_manager_obj<T,Q,CMPR>::new_pqueue(arity_t arity)
|
||||
{
|
||||
return pq = new Q (arity,cmp_o);
|
||||
}
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
merge_sort_manager_obj<T,Q,CMPR>::~merge_sort_manager_obj(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
AMI_err merge_sort_manager_obj<T,Q,CMPR>::main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len)
|
||||
{
|
||||
quick_sort_obj(mm_stream, len, cmp_o);
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
TPIE_OS_SIZE_T merge_sort_manager_obj<T,Q,CMPR>::space_usage_overhead(void)
|
||||
{
|
||||
return sizeof(Q);
|
||||
}
|
||||
|
||||
template<class T, class Q, class CMPR>
|
||||
AMI_err merge_sort_manager_obj<T,Q,CMPR>::initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index)
|
||||
{
|
||||
arity_t ii;
|
||||
|
||||
input_arity = arity;
|
||||
|
||||
bool pqret;
|
||||
|
||||
tp_assert(arity > 0, "Input arity is 0.");
|
||||
|
||||
if (pq != NULL) {
|
||||
delete pq;
|
||||
pq = NULL;
|
||||
}
|
||||
new_pqueue(arity);
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count = output_count = 0;
|
||||
#endif
|
||||
for (ii = arity; ii--; ) {
|
||||
if (in[ii] != NULL) {
|
||||
taken_flags[ii] = 1;
|
||||
pqret = pq->insert(ii,*in[ii]);
|
||||
tp_assert(pqret, "pq->insert() failed.");
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count++;
|
||||
#endif
|
||||
} else {
|
||||
taken_flags[ii] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
taken_index = -1;
|
||||
return AMI_MERGE_READ_MULTIPLE;
|
||||
}
|
||||
|
||||
|
||||
// Comparison function based merge sort manager.
|
||||
|
||||
template <class T, class Q>
|
||||
class merge_sort_manager_cmp : public merge_sort_manager<T,Q> {
|
||||
private:
|
||||
int (*cmp_f)(CONST T&, CONST T&);
|
||||
Q *new_pqueue(arity_t arity);
|
||||
protected:
|
||||
using merge_sort_manager<T,Q>::pq;
|
||||
using merge_sort_manager<T,Q>::input_arity;
|
||||
#if DEBUG_ASSERTIONS
|
||||
using merge_sort_manager<T,Q>::input_count;
|
||||
using merge_sort_manager<T,Q>::output_count;
|
||||
#endif
|
||||
|
||||
public:
|
||||
merge_sort_manager_cmp(int (*cmp)(CONST T&, CONST T&));
|
||||
virtual ~merge_sort_manager_cmp(void);
|
||||
AMI_err main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len);
|
||||
TPIE_OS_SIZE_T space_usage_overhead(void);
|
||||
AMI_err initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index);
|
||||
};
|
||||
|
||||
|
||||
template<class T,class Q>
|
||||
merge_sort_manager_cmp<T,Q>::merge_sort_manager_cmp(int (*cmp)(CONST T&,
|
||||
CONST T&))
|
||||
{
|
||||
cmp_f = cmp;
|
||||
pq = NULL;
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
Q *merge_sort_manager_cmp<T,Q>::new_pqueue(arity_t arity)
|
||||
{
|
||||
return pq = new Q (arity,cmp_f);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class Q>
|
||||
merge_sort_manager_cmp<T,Q>::~merge_sort_manager_cmp(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<class T,class Q>
|
||||
AMI_err merge_sort_manager_cmp<T,Q>::main_mem_operate(T* mm_stream, TPIE_OS_SIZE_T len)
|
||||
{
|
||||
quick_sort_cmp(mm_stream, len, cmp_f);
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T,class Q>
|
||||
TPIE_OS_SIZE_T merge_sort_manager_cmp<T,Q>::space_usage_overhead(void)
|
||||
{
|
||||
return sizeof(Q);
|
||||
}
|
||||
|
||||
template<class T, class Q>
|
||||
AMI_err merge_sort_manager_cmp<T,Q>::initialize(arity_t arity, CONST T * CONST *in,
|
||||
AMI_merge_flag *taken_flags,
|
||||
int &taken_index)
|
||||
{
|
||||
arity_t ii;
|
||||
|
||||
input_arity = arity;
|
||||
|
||||
bool pqret;
|
||||
|
||||
tp_assert(arity > 0, "Input arity is 0.");
|
||||
|
||||
if (pq != NULL) {
|
||||
delete pq;
|
||||
pq = NULL;
|
||||
}
|
||||
new_pqueue(arity);
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count = output_count = 0;
|
||||
#endif
|
||||
for (ii = arity; ii--; ) {
|
||||
if (in[ii] != NULL) {
|
||||
taken_flags[ii] = 1;
|
||||
pqret = pq->insert(ii,*in[ii]);
|
||||
tp_assert(pqret, "pq->insert() failed.");
|
||||
#if DEBUG_ASSERTIONS
|
||||
input_count++;
|
||||
#endif
|
||||
} else {
|
||||
taken_flags[ii] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
taken_index = -1;
|
||||
return AMI_MERGE_READ_MULTIPLE;
|
||||
}
|
||||
|
||||
|
||||
// *******************************************************************
|
||||
// * *
|
||||
// * The actual AMI_sort calls *
|
||||
// * *
|
||||
// *******************************************************************
|
||||
|
||||
// A version of AMI_sort that takes an input stream of elements of
|
||||
// type T, an output stream, and a user-specified comparison function
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sort_V1(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream,
|
||||
int (*cmp)(CONST T&, CONST T&))
|
||||
{
|
||||
merge_sort_manager_cmp<T,pqueue_heap_cmp<arity_t,T> > msm(cmp);
|
||||
|
||||
return AMI_generalized_partition_and_merge(instream, outstream,
|
||||
(merge_sort_manager_cmp<T, pqueue_heap_cmp<arity_t,T> > *)&msm);
|
||||
}
|
||||
|
||||
// A version of AMI_sort that takes an input streamof elements of type
|
||||
// T, and an output stream, and and uses the < operator to sort
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sort_V1(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream)
|
||||
{
|
||||
merge_sort_manager_op<T,pqueue_heap_op<arity_t,T> > msm;
|
||||
|
||||
return AMI_generalized_partition_and_merge(instream, outstream,
|
||||
(merge_sort_manager_op<T,pqueue_heap_op<arity_t,T> > *)&msm);
|
||||
}
|
||||
|
||||
// A version of AMI_sort that takes an input stream of elements of
|
||||
// type T, an output stream, and a user-specified comparison
|
||||
// object. The comparison object "cmp", of (user-defined) class
|
||||
// represented by CMPR, must have a member function called "compare"
|
||||
// which is used for sorting the input stream.
|
||||
|
||||
template<class T, class CMPR>
|
||||
AMI_err AMI_sort_V1(AMI_STREAM<T> *instream, AMI_STREAM<T> *outstream,
|
||||
CMPR *cmp)
|
||||
{
|
||||
merge_sort_manager_obj<T,pqueue_heap_obj<arity_t,T,CMPR>,CMPR > msm(cmp);
|
||||
|
||||
return AMI_generalized_partition_and_merge (instream, outstream,
|
||||
(merge_sort_manager_obj<T,pqueue_heap_obj<arity_t,T,CMPR>,CMPR> *)&msm);
|
||||
}
|
||||
|
||||
#endif // _AMI_SORT_SINGLE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,376 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: ami_sparse_matrix.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 3/2/95
|
||||
//
|
||||
// $Id: ami_sparse_matrix.h,v 1.14 2005/07/07 20:45:37 adanner Exp $
|
||||
//
|
||||
#ifndef AMI_SPARSE_MATRIX_H
|
||||
#define AMI_SPARSE_MATRIX_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// We need dense matrices to support some sparse/dense interactions.
|
||||
#include <ami_matrix.h>
|
||||
|
||||
// A spares matrix element is labeled with a row er and a column ec.
|
||||
// A sparse matrix is simply represented by a colletion of these.
|
||||
template <class T>
|
||||
class AMI_sm_elem {
|
||||
public:
|
||||
TPIE_OS_OFFSET er;
|
||||
TPIE_OS_OFFSET ec;
|
||||
T val;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
ostream &operator<<(ostream& s, const AMI_sm_elem<T> &a)
|
||||
{
|
||||
return s << a.er << ' ' << a.ec << ' ' << a.val;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
istream &operator>>(istream& s, AMI_sm_elem<T> &a)
|
||||
{
|
||||
return s >> a.er >> a.ec >> a.val;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
class AMI_sparse_matrix : public AMI_STREAM< AMI_sm_elem<T> > {
|
||||
private:
|
||||
// How many rows and columns.
|
||||
TPIE_OS_OFFSET r,c;
|
||||
public:
|
||||
AMI_sparse_matrix(TPIE_OS_OFFSET row, TPIE_OS_OFFSET col);
|
||||
~AMI_sparse_matrix(void);
|
||||
TPIE_OS_OFFSET rows();
|
||||
TPIE_OS_OFFSET cols();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
AMI_sparse_matrix<T>::AMI_sparse_matrix(TPIE_OS_OFFSET row, TPIE_OS_OFFSET col) :
|
||||
r(row), c(col), AMI_STREAM< AMI_sm_elem<T> >()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_sparse_matrix<T>::~AMI_sparse_matrix(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET AMI_sparse_matrix<T>::rows(void)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET AMI_sparse_matrix<T>::cols(void)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// A class of comparison object designed to facilitate sorting of
|
||||
// elements of the spase matrix into bands.
|
||||
//
|
||||
|
||||
template<class T>
|
||||
class sm_band_comparator
|
||||
{
|
||||
private:
|
||||
TPIE_OS_SIZE_T rpb;
|
||||
public:
|
||||
sm_band_comparator(TPIE_OS_SIZE_T rows_per_band) :
|
||||
rpb(rows_per_band) {};
|
||||
virtual ~sm_band_comparator(void) {};
|
||||
// If they are in the same band, compare columns, otherwise,
|
||||
// compare rows.
|
||||
int compare(const AMI_sm_elem<T> &t1, const AMI_sm_elem<T> &t2) {
|
||||
if ((t1.er / rpb) == (t2.er / rpb)) {
|
||||
return int(t1.ec) - int(t2.ec);
|
||||
} else {
|
||||
return int(t1.er) - int(t2.er);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A function to bandify a sparse matrix.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sparse_bandify(AMI_sparse_matrix<T> &sm,
|
||||
AMI_sparse_matrix<T> &bsm,
|
||||
TPIE_OS_SIZE_T rows_per_band)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
sm_band_comparator<T> cmp(rows_per_band);
|
||||
|
||||
ae = AMI_sort_V1((AMI_STREAM< AMI_sm_elem<T> > *)&sm,
|
||||
(AMI_STREAM< AMI_sm_elem<T> > *)&bsm,
|
||||
(sm_band_comparator<T> *)&cmp);
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Get all band information for the given matrix and the current
|
||||
// runtime environment.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sparse_band_info(AMI_sparse_matrix<T> &opm,
|
||||
TPIE_OS_SIZE_T &rows_per_band,
|
||||
TPIE_OS_OFFSET &total_bands)
|
||||
{
|
||||
TPIE_OS_SIZE_T sz_avail, single_stream_usage;
|
||||
|
||||
TPIE_OS_OFFSET rows = opm.rows();
|
||||
|
||||
AMI_err ae;
|
||||
|
||||
// Check available main memory.
|
||||
sz_avail = MM_manager.memory_available ();
|
||||
|
||||
// How much memory does a single stream need in the worst case?
|
||||
|
||||
if ((ae = opm.main_memory_usage(&single_stream_usage,
|
||||
MM_STREAM_USAGE_MAXIMUM)) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Figure out how many elements of the output can fit in main
|
||||
// memory at a time. This will determine the number of rows of
|
||||
// the sparse matrix that go into a band.
|
||||
|
||||
rows_per_band = (sz_avail - single_stream_usage * 5) / sizeof(T);
|
||||
|
||||
if (rows_per_band > rows) {
|
||||
rows_per_band = (TPIE_OS_SIZE_T)rows;
|
||||
}
|
||||
|
||||
total_bands = (rows + rows_per_band - 1) / rows_per_band;
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sparse_mult_scan_banded(AMI_sparse_matrix<T> &banded_opm,
|
||||
AMI_matrix<T> &opv, AMI_matrix<T> &res,
|
||||
TPIE_OS_OFFSET rows, TPIE_OS_OFFSET /*cols*/,
|
||||
TPIE_OS_SIZE_T rows_per_band)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
AMI_sm_elem<T> *sparse_current;
|
||||
T *vec_current;
|
||||
TPIE_OS_OFFSET vec_row;
|
||||
|
||||
banded_opm.seek(0);
|
||||
ae = banded_opm.read_item(&sparse_current);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
opv.seek(0);
|
||||
ae = opv.read_item(&vec_current);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
vec_row = 0;
|
||||
|
||||
res.seek(0);
|
||||
|
||||
TPIE_OS_OFFSET next_band_start = rows_per_band;
|
||||
|
||||
TPIE_OS_OFFSET ii;
|
||||
|
||||
TPIE_OS_OFFSET curr_band_start = 0;
|
||||
TPIE_OS_SIZE_T rows_in_current_band = rows_per_band;
|
||||
|
||||
bool sparse_done = false;
|
||||
|
||||
T *output_subvector = new T[rows_per_band];
|
||||
|
||||
for (ii = rows_per_band; ii--; ) {
|
||||
output_subvector[ii] = 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
//
|
||||
// Each time we enter this loop, we have the following invariants:
|
||||
//
|
||||
// vec_current = an element of the vector.
|
||||
//
|
||||
// vec_row = row vec_current came from.
|
||||
//
|
||||
// sparse_current = current element from the banded sparse mat.
|
||||
//
|
||||
// curr_band_start = row beginning current band.
|
||||
//
|
||||
// next_band_start = row beginning next band.
|
||||
//
|
||||
// rows_in_current_band = as name implies.
|
||||
//
|
||||
|
||||
if (sparse_done || (sparse_current->er >= next_band_start)) {
|
||||
|
||||
// If we are out of sparse elements or the sparse element
|
||||
// row is in the next band then we have to write the
|
||||
// current results, reset the output buffer, and rewind
|
||||
// the vector.
|
||||
|
||||
ae = res.write_array(output_subvector, rows_in_current_band);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
if (sparse_done) {
|
||||
// Write more zeores if necessary before breaking out
|
||||
// of the loop. We have to do this in some cases if
|
||||
// there are one or more empty bands at the bottom of
|
||||
// the sparse matrix. It is unlikely this sort of
|
||||
// thing would ever really happen, but we should be
|
||||
// careful anyway.
|
||||
T tmp = 0;
|
||||
for (ii = rows - next_band_start; ii--; ) {
|
||||
ae = res.write_item(tmp);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (ii = rows_in_current_band; ii--; ) {
|
||||
output_subvector[ii] = 0;
|
||||
}
|
||||
|
||||
opv.seek(0);
|
||||
|
||||
curr_band_start = next_band_start;
|
||||
|
||||
next_band_start += rows_per_band;
|
||||
|
||||
if (next_band_start > rows) {
|
||||
// The final band may not have exactly rows_per_band
|
||||
// rows due to roundoff. We make the appropropriate
|
||||
// adjustments here.
|
||||
rows_in_current_band = (TPIE_OS_SIZE_T)(rows - curr_band_start);
|
||||
next_band_start = rows;
|
||||
} else {
|
||||
rows_in_current_band = rows_per_band;
|
||||
}
|
||||
} else if (sparse_current->ec == vec_row) {
|
||||
|
||||
// If the column of the sparse matrix and the row of the
|
||||
// vector that the current inputs come from are the same,
|
||||
// then multiply them, add the result to the appropriate
|
||||
// output element, and advance past the sparse element.
|
||||
|
||||
output_subvector[sparse_current->er - curr_band_start] +=
|
||||
sparse_current->val * *vec_current;
|
||||
|
||||
ae = banded_opm.read_item(&sparse_current);
|
||||
if (ae == AMI_ERROR_END_OF_STREAM) {
|
||||
sparse_done = true;
|
||||
} else if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// If the sparse element column is past the current
|
||||
// row in the vector, then advance the vector.
|
||||
|
||||
tp_assert(sparse_current->ec > vec_row,
|
||||
"Sparse column fell behind current row.");
|
||||
|
||||
ae = opv.read_item(&vec_current);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
vec_row++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete [] output_subvector;
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Multiply a sparse (n,m)-matrix by a dense m-vector to get a dense
|
||||
// n-vector.
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_sparse_mult(AMI_sparse_matrix<T> &opm, AMI_matrix<T> &opv,
|
||||
AMI_matrix<T> &res)
|
||||
{
|
||||
TPIE_OS_SIZE_T rows_per_band;
|
||||
TPIE_OS_OFFSET total_bands;
|
||||
|
||||
TPIE_OS_OFFSET rows;
|
||||
TPIE_OS_OFFSET cols;
|
||||
|
||||
// size_t sz_avail, single_stream_usage;
|
||||
|
||||
AMI_err ae;
|
||||
|
||||
// Make sure the sizes of the matrix and vectors match up.
|
||||
|
||||
rows = opm.rows();
|
||||
cols = opm.cols();
|
||||
|
||||
if ((cols != opv.rows()) || (rows != res.rows()) ||
|
||||
(opv.cols() != 1) || (res.cols() != 1)) {
|
||||
return AMI_MATRIX_BOUNDS;
|
||||
}
|
||||
|
||||
// Get band information.
|
||||
|
||||
ae = AMI_sparse_band_info(opm, rows_per_band, total_bands);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Partition the sparse matrix into bands with the elements within
|
||||
// a band sorted by column. This is all done by a single sort
|
||||
// operation.
|
||||
//
|
||||
// Note that if our goal is to multiply a large number of
|
||||
// different vectors by a single matrix we should seperate this
|
||||
// step out into a preprocessing phacse so that the sort is only
|
||||
// done once.
|
||||
|
||||
AMI_sparse_matrix<T> banded_opm(rows, cols);
|
||||
|
||||
ae = AMI_sparse_bandify(opm, banded_opm, rows_per_band);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
// Scan the contents of the bands and the vector to produce output.
|
||||
|
||||
ae = AMI_sparse_mult_scan_banded(banded_opm, opv, res,
|
||||
rows, cols, rows_per_band);
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
#endif // _AMI_SPARSE_MATRIX_H
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_stack.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/15/94
|
||||
//
|
||||
// $Id: ami_stack.h,v 1.9 2005/01/21 16:52:39 tavi Exp $
|
||||
//
|
||||
#ifndef _AMI_STACK_H
|
||||
#define _AMI_STACK_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the AMI_STREAM definition.
|
||||
#include <ami_stream.h>
|
||||
|
||||
template<class T>
|
||||
class AMI_stack : public AMI_STREAM<T> {
|
||||
public:
|
||||
using AMI_STREAM<T>::seek;
|
||||
using AMI_STREAM<T>::truncate;
|
||||
using AMI_STREAM<T>::stream_len;
|
||||
|
||||
AMI_stack();
|
||||
AMI_stack(const char* path,
|
||||
AMI_stream_type type = AMI_READ_WRITE_STREAM);
|
||||
~AMI_stack(void);
|
||||
AMI_err push(const T &t);
|
||||
AMI_err pop(T **t);
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_stack<T>::AMI_stack() :
|
||||
AMI_STREAM<T>()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_stack<T>::AMI_stack(const char* path, AMI_stream_type type):
|
||||
AMI_STREAM<T>(path, type)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_stack<T>::~AMI_stack(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_stack<T>::push(const T &t)
|
||||
{
|
||||
AMI_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
ae = truncate((slen = stream_len())+1);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = seek(slen);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return write_item(t);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_stack<T>::pop(T **t)
|
||||
{
|
||||
AMI_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
slen = stream_len();
|
||||
|
||||
ae = seek(slen-1);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = read_item(t);
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return truncate(slen-1);
|
||||
}
|
||||
|
||||
#endif // _AMI_STACK_H
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// File: ami_stream.h (formerly part of ami.h and ami_imps.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
//
|
||||
// $Id: ami_stream.h,v 1.6 2003/05/08 22:30:48 tavi Exp $
|
||||
//
|
||||
#ifndef _AMI_STREAM_H
|
||||
#define _AMI_STREAM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#ifndef AMI_VIRTUAL_BASE
|
||||
# define AMI_VIRTUAL_BASE 0
|
||||
#endif
|
||||
|
||||
// include definition of VERSION macro
|
||||
#include <versions.h>
|
||||
|
||||
// Include the configuration header.
|
||||
#include <config.h>
|
||||
|
||||
// Get the base class, enums, etc...
|
||||
#include <ami_err.h>
|
||||
#include <ami_stream_base.h>
|
||||
|
||||
// Get the device description class
|
||||
#include <ami_device.h>
|
||||
|
||||
// Get an implementation definition
|
||||
|
||||
#if defined(AMI_IMP_SINGLE)
|
||||
TPIE_OS_UNIX_ONLY_WARNING_AMI_IMP_SINGLE
|
||||
#else
|
||||
# define AMI_STREAM_IMP_SINGLE
|
||||
#endif
|
||||
|
||||
#if defined(AMI_IMP_USER_DEFINED)
|
||||
# warning The AMI_IMP_USER_DEFINED flag is obsolete. \
|
||||
Please use AMI_STREAM_IMP_USER_DEFINED.
|
||||
# warning Implicitly defining AMI_STREAM_IMP_USER_DEFINED.
|
||||
# define AMI_STREAM_IMP_USER_DEFINED
|
||||
#endif
|
||||
|
||||
// The number of implementations to be defined.
|
||||
#define _AMI_STREAM_IMP_COUNT (defined(AMI_STREAM_IMP_USER_DEFINED) + \
|
||||
defined(AMI_STREAM_IMP_SINGLE))
|
||||
|
||||
// Multiple implementations are allowed to coexist, with some
|
||||
// restrictions. Declarations of streams must use explicit subclasses
|
||||
// of AMI_stream_base to specify what type of streams they are.
|
||||
|
||||
// If the including module did not explicitly ask for multiple
|
||||
// implementations but requested more than one implementation, issue a
|
||||
// warning.
|
||||
#ifndef AMI_STREAM_IMP_MULTI_IMP
|
||||
# if (_AMI_STREAM_IMP_COUNT > 1)
|
||||
# warning Multiple AMI_STREAM_IMP_* defined, \
|
||||
but AMI_STREAM_IMP_MULTI_IMP undefined.
|
||||
# warning Implicitly defining AMI_STREAM_IMP_MULTI_IMP.
|
||||
# define AMI_STREAM_IMP_MULTI_IMP
|
||||
# endif // (_AMI_STREAM_IMP_COUNT > 1)
|
||||
#endif // AMI_STREAM_IMP_MULTI_IMP
|
||||
|
||||
// If we have multiple implementations, set AMI_STREAM to be the base
|
||||
// class.
|
||||
#ifdef AMI_STREAM_IMP_MULTI_IMP
|
||||
# define AMI_STREAM AMI_stream_base
|
||||
# define AMI_stream AMI_stream_base
|
||||
#endif
|
||||
|
||||
// Now include the definitions of each implementation that will be
|
||||
// used.
|
||||
|
||||
// Make sure at least one implementation was chosen. If none was,
|
||||
// then choose one by default, but warn the user. [tavi] NO, don't
|
||||
// bother. Since the IMP_SINGLE is the only existing implementation,
|
||||
// just tacitly make it the default.
|
||||
#if (_AMI_STREAM_IMP_COUNT < 1)
|
||||
//# warning No implementation defined. Using AMI_STREAM_IMP_SINGLE by default.
|
||||
# define AMI_STREAM_IMP_SINGLE
|
||||
#endif // (_AMI_STREAM_IMP_COUNT < 1)
|
||||
|
||||
// User defined implementation.
|
||||
#if defined(AMI_STREAM_IMP_USER_DEFINED)
|
||||
// Do nothing. The user will provide a definition of AMI_STREAM.
|
||||
#endif // defined(AMI_STREAM_IMP_USER_DEFINED)
|
||||
|
||||
// Single BTE stream implementation.
|
||||
#if defined(AMI_STREAM_IMP_SINGLE)
|
||||
# include <ami_stream_single.h>
|
||||
// If this is the only implementation, then make it easier to get to.
|
||||
# ifndef AMI_STREAM_IMP_MULTI_IMP
|
||||
# define AMI_STREAM AMI_stream_single
|
||||
# define AMI_stream AMI_stream_single
|
||||
# endif // AMI_STREAM_IMP_MULTI_IMP
|
||||
#endif // defined(AMI_STREAM_IMP_SINGLE)
|
||||
|
||||
#endif // _AMI_STREAM_H
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: ami_stream_arith.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 12/10/94
|
||||
//
|
||||
// $Id: ami_stream_arith.h,v 1.6 2003/04/20 23:56:38 tavi Exp $
|
||||
//
|
||||
#ifndef _AMI_STREAM_ARITH_H
|
||||
#define _AMI_STREAM_ARITH_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the definition of the AMI_scan_object class.
|
||||
#include <ami_scan.h>
|
||||
|
||||
#define SCAN_OPERATOR_DECLARATION(NAME,OP) \
|
||||
\
|
||||
template<class T> class AMI_scan_ ## NAME : AMI_scan_object { \
|
||||
public: \
|
||||
AMI_err initialize(void); \
|
||||
AMI_err operate(const T &op1, const T &op2, AMI_SCAN_FLAG *sfin, \
|
||||
T *res, AMI_SCAN_FLAG *sfout); \
|
||||
}; \
|
||||
\
|
||||
template<class T> \
|
||||
AMI_err AMI_scan_ ## NAME<T>::initialize(void) \
|
||||
{ \
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template<class T> \
|
||||
AMI_err AMI_scan_ ## NAME<T>::operate(const T &op1, const T &op2, \
|
||||
AMI_SCAN_FLAG *sfin, \
|
||||
T *res, AMI_SCAN_FLAG *sfout) \
|
||||
{ \
|
||||
if ((*sfout = (sfin[0] && sfin[1]))) { \
|
||||
*res = op1 OP op2; \
|
||||
return AMI_SCAN_CONTINUE; \
|
||||
} else { \
|
||||
return AMI_SCAN_DONE; \
|
||||
} \
|
||||
}
|
||||
|
||||
SCAN_OPERATOR_DECLARATION(add,+)
|
||||
SCAN_OPERATOR_DECLARATION(sub,-)
|
||||
SCAN_OPERATOR_DECLARATION(mult,*)
|
||||
SCAN_OPERATOR_DECLARATION(div,/)
|
||||
|
||||
|
||||
#define SCAN_SCALAR_OPERATOR_DECLARATION(NAME,OP) \
|
||||
\
|
||||
template<class T> class AMI_scan_scalar_ ## NAME : AMI_scan_object { \
|
||||
private: \
|
||||
T scalar; \
|
||||
public: \
|
||||
AMI_scan_scalar_ ## NAME(const T &s); \
|
||||
virtual ~AMI_scan_scalar_ ## NAME(void); \
|
||||
AMI_err initialize(void); \
|
||||
AMI_err operate(const T &op, AMI_SCAN_FLAG *sfin, \
|
||||
T *res, AMI_SCAN_FLAG *sfout); \
|
||||
}; \
|
||||
\
|
||||
\
|
||||
template<class T> \
|
||||
AMI_scan_scalar_ ## NAME<T>:: \
|
||||
AMI_scan_scalar_ ## NAME(const T &s) : \
|
||||
scalar(s) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template<class T> \
|
||||
AMI_scan_scalar_ ## NAME<T>::~AMI_scan_scalar_ ## NAME() \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template<class T> \
|
||||
AMI_err AMI_scan_scalar_ ## NAME<T>::initialize(void) \
|
||||
{ \
|
||||
return AMI_ERROR_NO_ERROR; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
template<class T> \
|
||||
AMI_err AMI_scan_scalar_ ## NAME<T>::operate(const T &op, \
|
||||
AMI_SCAN_FLAG *sfin, \
|
||||
T *res, AMI_SCAN_FLAG *sfout) \
|
||||
{ \
|
||||
if ((*sfout = *sfin)) { \
|
||||
*res = op OP scalar; \
|
||||
return AMI_SCAN_CONTINUE; \
|
||||
} else { \
|
||||
return AMI_SCAN_DONE; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
SCAN_SCALAR_OPERATOR_DECLARATION(add,+)
|
||||
SCAN_SCALAR_OPERATOR_DECLARATION(sub,-)
|
||||
SCAN_SCALAR_OPERATOR_DECLARATION(mult,*)
|
||||
SCAN_SCALAR_OPERATOR_DECLARATION(div,/)
|
||||
|
||||
#endif // _AMI_STREAM_ARITH_H
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// File: ami_stream_base.h (formerly ami_base.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/19/94
|
||||
//
|
||||
// $Id: ami_stream_base.h,v 1.5 2004/08/17 16:47:58 jan Exp $
|
||||
//
|
||||
#ifndef _AMI_STREAM_BASE_H
|
||||
#define _AMI_STREAM_BASE_H
|
||||
|
||||
#define A_INLINE inline
|
||||
|
||||
#include <tpie_assert.h>
|
||||
#include <ami_err.h>
|
||||
#include <persist.h>
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// AMI stream types passed to constructors
|
||||
enum AMI_stream_type {
|
||||
AMI_READ_STREAM = 1, // Open existing stream for reading
|
||||
AMI_WRITE_STREAM, // Open for writing. Create if non-existent
|
||||
AMI_APPEND_STREAM, // Open for writing at end. Create if needed.
|
||||
AMI_READ_WRITE_STREAM // Open to read and write.
|
||||
};
|
||||
|
||||
// AMI stream status.
|
||||
enum AMI_stream_status {
|
||||
AMI_STREAM_STATUS_VALID = 0,
|
||||
AMI_STREAM_STATUS_INVALID = 1
|
||||
};
|
||||
|
||||
|
||||
// An abstract class template which implements a stream of objects
|
||||
// of type T within the AMI. This is the superclass of all actual
|
||||
// implementations of streams of T within the AMI (e.g. single device
|
||||
// streams, single CPU/many disk streams, and distributed streams).
|
||||
template<class T> class AMI_stream_base {
|
||||
protected:
|
||||
|
||||
AMI_stream_status status_;
|
||||
|
||||
public:
|
||||
|
||||
AMI_stream_base(void) { status_ = AMI_STREAM_STATUS_INVALID; }
|
||||
|
||||
// Inquire the status.
|
||||
AMI_stream_status status() const { return status_; }
|
||||
bool is_valid() const { return status_ == AMI_STREAM_STATUS_VALID; }
|
||||
bool operator!() const { return !is_valid(); }
|
||||
|
||||
// TODO: Does this need to be virtual?
|
||||
virtual ~AMI_stream_base(void) {}
|
||||
|
||||
#if AMI_VIRTUAL_BASE
|
||||
|
||||
// A virtual psuedo-constructor for substreams.
|
||||
virtual AMI_err new_substream(AMI_stream_type st,
|
||||
TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
AMI_stream_base<T> **sub_stream) = 0;
|
||||
|
||||
// Access methods.
|
||||
|
||||
virtual A_INLINE AMI_err write_item(const T &tin) = 0;
|
||||
virtual A_INLINE AMI_err read_item(T **tout) = 0;
|
||||
|
||||
virtual A_INLINE AMI_err read_array(T *mm_space, TPIE_OS_OFFSET *len) = 0;
|
||||
virtual A_INLINE AMI_err write_array(const T *mm_space, TPIE_OS_OFFSET len) = 0;
|
||||
|
||||
// Misc.
|
||||
virtual AMI_err main_memory_usage(size_t *usage,
|
||||
MM_stream_usage usage_type) = 0;
|
||||
|
||||
virtual TPIE_OS_OFFSET stream_len(void) = 0;
|
||||
|
||||
virtual AMI_err name(char **stream_name) = 0;
|
||||
|
||||
virtual AMI_err seek(TPIE_OS_OFFSET offset) = 0;
|
||||
|
||||
virtual AMI_err truncate(TPIE_OS_OFFSET offset) = 0;
|
||||
|
||||
virtual int available_streams(void) = 0;
|
||||
|
||||
virtual TPIE_OS_OFFSET chunk_size(void) = 0;
|
||||
|
||||
virtual void persist(persistence) = 0;
|
||||
|
||||
#endif // AMI_VIRTUAL_BASE
|
||||
};
|
||||
|
||||
#endif // _AMI_STREAM_BASE_H
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// File: ami_stream_single.cpp (formerly ami_single.cpp)
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 8/24/93
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(ami_single_cpp,"$Id: ami_stream_single.cpp,v 1.4 2004/08/12 12:53:42 jan Exp $");
|
||||
|
||||
#include "lib_config.h"
|
||||
|
||||
// Don't bother defining any BTE implementation, since this is library
|
||||
// code for the AMI.
|
||||
#define BTE_STREAM_IMP_USER_DEFINED
|
||||
#define BTE_STREAM BTE_stream_base
|
||||
#define AMI_STREAM_IMP_SINGLE
|
||||
#include <ami_stream.h>
|
||||
|
||||
// The default device description for AMI single streams.
|
||||
AMI_device AMI_stream_single_base::default_device;
|
||||
|
||||
// The device index of the most recently created stream.
|
||||
unsigned int AMI_stream_single_base::device_index;
|
||||
|
||||
// Initializer
|
||||
|
||||
unsigned int AMI_stream_single_base_device_initializer::count;
|
||||
|
||||
AMI_stream_single_base_device_initializer::
|
||||
AMI_stream_single_base_device_initializer(void)
|
||||
{
|
||||
AMI_err ae;
|
||||
|
||||
if (!count++) {
|
||||
// Try to initialize from the environment.
|
||||
ae = AMI_stream_single_base::
|
||||
default_device.read_environment(AMI_SINGLE_DEVICE_ENV);
|
||||
|
||||
if (ae == AMI_ERROR_NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to initialize from TMP_DIR
|
||||
ae = AMI_stream_single_base::
|
||||
default_device.read_environment(TMPDIR_ENV);
|
||||
|
||||
if (ae == AMI_ERROR_NO_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to initialize to a default path
|
||||
ae = AMI_stream_single_base::
|
||||
default_device.set_to_path(TMP_DIR "|" TMP_DIR);
|
||||
|
||||
if (ae != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("Unable to initialize the default device description for AMI single streams.");
|
||||
}
|
||||
|
||||
TP_LOG_DEBUG_ID("Default device description for AMI single streams:");
|
||||
TP_LOG_DEBUG_ID(AMI_stream_single_base::default_device);
|
||||
|
||||
// Set the last device index used to the last device index, so
|
||||
// that the first stream will wrap around to go on device 0.
|
||||
AMI_stream_single_base::device_index =
|
||||
AMI_stream_single_base::default_device.arity() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
AMI_stream_single_base_device_initializer::
|
||||
~AMI_stream_single_base_device_initializer(void)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
//
|
||||
// File: ami_stream_single.h (formerly ami_single.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/19/94
|
||||
//
|
||||
// $Id: ami_stream_single.h,v 1.13 2005/07/07 20:43:06 adanner Exp $
|
||||
//
|
||||
// AMI entry points implemented on top of a single BTE. This is useful
|
||||
// for single CPU, single disk machines.
|
||||
//
|
||||
#ifndef _AMI_STREAM_SINGLE_H
|
||||
#define _AMI_STREAM_SINGLE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// [tavi] for UINT_MAX
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Use tempnam() instead of mktemp().
|
||||
// no - tempnam uses environment in way we dont like
|
||||
#include <stdio.h>
|
||||
|
||||
// For free()
|
||||
#include <stdlib.h>
|
||||
|
||||
// To make assertions.
|
||||
#include <tpie_assert.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Get an appropriate BTE. Flags may have been set to determine
|
||||
// exactly what BTE implementaion will be used, but that should be of
|
||||
// little concern to us. bte_stream.h and recursively included files
|
||||
// will worry about parsing the appropriate flags and getting us an
|
||||
// implementation.
|
||||
#include <bte_stream.h>
|
||||
|
||||
// Get the AMI_stream_base class.
|
||||
#include <ami_stream_base.h>
|
||||
|
||||
// Get the base memory manager. Normally the BTE will have already
|
||||
// gotten this, but in library code where we have no BTE defined, it
|
||||
// may not.
|
||||
#include <mm_base.h>
|
||||
|
||||
#include <ami_device.h>
|
||||
#include <tpie_tempnam.h>
|
||||
|
||||
// An initializer class to set the default device for the
|
||||
// AMI_stream_single_base class.
|
||||
class AMI_stream_single_base_device_initializer {
|
||||
private:
|
||||
static unsigned int count;
|
||||
public:
|
||||
AMI_stream_single_base_device_initializer(void);
|
||||
~AMI_stream_single_base_device_initializer(void);
|
||||
};
|
||||
|
||||
// A base class for AMI single streams that is used to hold the
|
||||
// default device description for AMI single streams regardless of the
|
||||
// particular type of object in the stream.
|
||||
|
||||
class AMI_stream_single_base {
|
||||
friend AMI_stream_single_base_device_initializer::
|
||||
AMI_stream_single_base_device_initializer(void);
|
||||
public:
|
||||
// The default device description for AMI streams.
|
||||
static AMI_device default_device;
|
||||
|
||||
// The index into the device list for the next stream.
|
||||
static unsigned int device_index;
|
||||
|
||||
static const tpie_stats_stream& gstats()
|
||||
{ return BTE_stream_base_generic::gstats(); }
|
||||
};
|
||||
|
||||
|
||||
// This is a trick to make sure that at least one initializer is declared.
|
||||
// The constructor for this initializer will make sure that the default
|
||||
// device is set up properly.
|
||||
static AMI_stream_single_base_device_initializer one_ssbd_initializer_per_source_file;
|
||||
|
||||
// The single stream class.
|
||||
|
||||
template<class T> class AMI_stream_single : public AMI_stream_base<T>,
|
||||
public AMI_stream_single_base {
|
||||
private:
|
||||
using AMI_stream_base<T>::status_;
|
||||
|
||||
// Point to a base stream, since the particular type of BTE
|
||||
// stream we are using may vary.
|
||||
BTE_STREAM<T> *btes;
|
||||
|
||||
int r_only;
|
||||
|
||||
// Non-zero if we should destroy the bte stream when we the
|
||||
// AMI stream is destroyed.
|
||||
int destruct_bte;
|
||||
|
||||
public:
|
||||
|
||||
// Read and write elements.
|
||||
A_INLINE AMI_err read_item(T **elt);
|
||||
A_INLINE AMI_err write_item(const T &elt);
|
||||
|
||||
A_INLINE AMI_err read_array(T *mm_space, TPIE_OS_OFFSET *len);
|
||||
A_INLINE AMI_err write_array(const T *mm_space, TPIE_OS_OFFSET len);
|
||||
|
||||
// We have a variety of constructors for different uses.
|
||||
|
||||
// A temporary AMI_stream using the default BTE stream type and
|
||||
// a temporary space on the disk or in some file system.
|
||||
AMI_stream_single(unsigned int device = UINT_MAX);
|
||||
|
||||
// An AMI stream based on a specific path name.
|
||||
AMI_stream_single(const char *path_name,
|
||||
AMI_stream_type st = AMI_READ_WRITE_STREAM);
|
||||
|
||||
// An AMI stream based on a specific existing BTE stream. Note
|
||||
// that in this case the BTE stream will not be detroyed when the
|
||||
// destructor is called.
|
||||
AMI_stream_single(BTE_STREAM<T> *bs);
|
||||
|
||||
// A psuedo-constructor for substreams.
|
||||
AMI_err new_substream(AMI_stream_type st, TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
AMI_stream_base<T> **sub_stream);
|
||||
|
||||
// Return the number of items in the stream.
|
||||
TPIE_OS_OFFSET stream_len(void) const { return btes->stream_len(); }
|
||||
|
||||
// Return the path name of this stream in newly allocated space.
|
||||
AMI_err name(char **stream_name);
|
||||
|
||||
// Move to a specific position in the stream.
|
||||
AMI_err seek(TPIE_OS_OFFSET offset);
|
||||
|
||||
// Return the current position in the stream.
|
||||
TPIE_OS_OFFSET tell() const { return btes->tell(); }
|
||||
|
||||
// Truncate
|
||||
AMI_err truncate(TPIE_OS_OFFSET offset);
|
||||
|
||||
// Query memory usage
|
||||
AMI_err main_memory_usage(TPIE_OS_SIZE_T *usage,
|
||||
MM_stream_usage usage_type);
|
||||
|
||||
// Destructor
|
||||
~AMI_stream_single(void);
|
||||
|
||||
const tpie_stats_stream& stats() const { return btes->stats(); }
|
||||
|
||||
int available_streams(void);
|
||||
|
||||
TPIE_OS_OFFSET chunk_size(void) const { return btes->chunk_size(); }
|
||||
|
||||
void persist(persistence p);
|
||||
|
||||
persistence persist() const { return btes->persist(); }
|
||||
|
||||
char *sprint();
|
||||
};
|
||||
|
||||
|
||||
// Create a temporary AMI stream on one of the devices in the default
|
||||
// device description. Persistence is PERSIST_DELETE by default. We
|
||||
// are given the index of the string describing the desired device.
|
||||
template<class T>
|
||||
AMI_stream_single<T>::AMI_stream_single(unsigned int device) {
|
||||
|
||||
// [tavi] Hack to fix an error that appears in gcc 2.8.1
|
||||
if (device == UINT_MAX) {
|
||||
device = (device_index = ((device_index + 1) % default_device.arity()));
|
||||
}
|
||||
|
||||
r_only = 0;
|
||||
destruct_bte = 1;
|
||||
|
||||
// Get a unique name.
|
||||
char *path = tpie_tempnam("AMI", default_device[device]);
|
||||
|
||||
TP_LOG_DEBUG_ID("Temporary stream in file: ");
|
||||
TP_LOG_DEBUG_ID(path);
|
||||
|
||||
// Create the BTE stream.
|
||||
btes = new BTE_STREAM<T>(path, BTE_WRITE_STREAM);
|
||||
|
||||
// (Short circuit evaluation...)
|
||||
if (btes == NULL || btes->status() == BTE_STREAM_STATUS_INVALID) {
|
||||
TP_LOG_FATAL_ID("BTE returned invalid or NULL stream.");
|
||||
status_ = AMI_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
btes->persist(PERSIST_DELETE);
|
||||
|
||||
if (seek(0) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("seek(0) returned error.");
|
||||
status_ = AMI_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
status_ = AMI_STREAM_STATUS_VALID;
|
||||
};
|
||||
|
||||
|
||||
// A stream created with this constructor will persist on disk at the
|
||||
// location specified by the path name.
|
||||
template<class T>
|
||||
AMI_stream_single<T>::AMI_stream_single(const char *path_name,
|
||||
AMI_stream_type st) {
|
||||
|
||||
// Decide BTE stream type
|
||||
BTE_stream_type bst;
|
||||
switch (st) {
|
||||
case AMI_READ_STREAM:
|
||||
bst = BTE_READ_STREAM;
|
||||
break;
|
||||
case AMI_APPEND_STREAM:
|
||||
bst = BTE_APPEND_STREAM;
|
||||
break;
|
||||
case AMI_WRITE_STREAM:
|
||||
case AMI_READ_WRITE_STREAM:
|
||||
bst = BTE_WRITE_STREAM; //BTE_WRITE_STREAM means both read and
|
||||
//write; this is inconsistent and should be modified..
|
||||
break;
|
||||
default:
|
||||
TP_LOG_WARNING_ID("Unknown stream type passed to constructor;");
|
||||
TP_LOG_WARNING_ID("Defaulting to AMI_READ_WRITE_STREAM.");
|
||||
bst = BTE_WRITE_STREAM;
|
||||
break;
|
||||
}
|
||||
|
||||
r_only = ((st == AMI_READ_STREAM)? 1 : 0);
|
||||
destruct_bte = 1;
|
||||
|
||||
// Create the BTE stream.
|
||||
btes = new BTE_STREAM<T>(path_name, bst);
|
||||
// (Short circuit evaluation...)
|
||||
if (btes == NULL || btes->status() == BTE_STREAM_STATUS_INVALID) {
|
||||
TP_LOG_FATAL_ID("BTE returned invalid or NULL stream.");
|
||||
status_ = AMI_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
btes->persist(PERSIST_PERSISTENT);
|
||||
|
||||
// If an APPEND stream, the BTE constructor seeks to its end;
|
||||
if (st != AMI_APPEND_STREAM) {
|
||||
if (seek(0) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("seek(0) returned error.");
|
||||
status_ = AMI_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
status_ = AMI_STREAM_STATUS_VALID;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_stream_single<T>::AMI_stream_single(BTE_STREAM<T> *bs) {
|
||||
|
||||
destruct_bte = 0;
|
||||
|
||||
btes = bs;
|
||||
if (btes == NULL || btes->status() == BTE_STREAM_STATUS_INVALID) {
|
||||
TP_LOG_FATAL_ID("BTE returned invalid or NULL stream.");
|
||||
status_ = AMI_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
r_only = bs->read_only();
|
||||
status_ = AMI_STREAM_STATUS_VALID;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_stream_single<T>::new_substream(AMI_stream_type st,
|
||||
TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
AMI_stream_base<T> **sub_stream)
|
||||
{
|
||||
AMI_err ae = AMI_ERROR_NO_ERROR;
|
||||
// Check permissions. Only READ and WRITE are allowed, and only READ is
|
||||
// allowed if r_only is set.
|
||||
if ((st != AMI_READ_STREAM) && ((st != AMI_WRITE_STREAM) || r_only)) {
|
||||
*sub_stream = NULL;
|
||||
TP_LOG_DEBUG_ID("permission denied");
|
||||
return AMI_ERROR_PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
BTE_stream_base<T> *bte_ss;
|
||||
|
||||
if (btes->new_substream(((st == AMI_READ_STREAM) ? BTE_READ_STREAM :
|
||||
BTE_WRITE_STREAM),
|
||||
sub_begin, sub_end,
|
||||
&bte_ss) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_DEBUG_ID("new_substream failed");
|
||||
*sub_stream = NULL;
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
|
||||
AMI_stream_single<T> *ami_ss;
|
||||
|
||||
// This is a potentially dangerous downcast. It is being done for
|
||||
// the sake of efficiency, so that calls to the BTE can be
|
||||
// inlined. If multiple implementations of BTE streams are
|
||||
// present it could be very dangerous.
|
||||
|
||||
// this is to avoid compiler warnings
|
||||
// hack! XXX
|
||||
#if(0)
|
||||
BTE_STREAM<T> *bte_ss_b=0;
|
||||
assert(sizeof(BTE_STREAM<T>*) == sizeof(BTE_stream_base<T>*));
|
||||
memcpy(bte_ss_b, bte_ss, sizeof(BTE_STREAM<T>*));
|
||||
ami_ss = new AMI_stream_single<T>(bte_ss_b);
|
||||
#endif
|
||||
ami_ss = new AMI_stream_single<T>((BTE_STREAM<T>*)bte_ss);
|
||||
|
||||
ami_ss->destruct_bte = 1;
|
||||
ae = ami_ss->seek(0);
|
||||
assert(ae == AMI_ERROR_NO_ERROR); // sanity check
|
||||
|
||||
*sub_stream = (AMI_stream_base<T> *)ami_ss;
|
||||
|
||||
return ae;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
AMI_err AMI_stream_single<T>::name(char **stream_name)
|
||||
{
|
||||
BTE_err be = btes->name(stream_name);
|
||||
if (be != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("bte error");
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
} else {
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Move to a specific offset.
|
||||
template<class T>
|
||||
AMI_err AMI_stream_single<T>::seek(TPIE_OS_OFFSET offset)
|
||||
{
|
||||
if (btes->seek(offset) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("bte error");
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Truncate
|
||||
template<class T>
|
||||
AMI_err AMI_stream_single<T>::truncate(TPIE_OS_OFFSET offset)
|
||||
{
|
||||
if (btes->truncate(offset) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("bte error");
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Query memory usage
|
||||
template<class T>
|
||||
AMI_err AMI_stream_single<T>::main_memory_usage(TPIE_OS_SIZE_T *usage,
|
||||
MM_stream_usage usage_type)
|
||||
{
|
||||
if (btes->main_memory_usage(usage, usage_type) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("bte error");
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
|
||||
switch (usage_type) {
|
||||
case MM_STREAM_USAGE_OVERHEAD:
|
||||
case MM_STREAM_USAGE_CURRENT:
|
||||
case MM_STREAM_USAGE_MAXIMUM:
|
||||
case MM_STREAM_USAGE_SUBSTREAM:
|
||||
*usage += sizeof(*this);
|
||||
break;
|
||||
case MM_STREAM_USAGE_BUFFER:
|
||||
break;
|
||||
default:
|
||||
tp_assert(0, "Unknown MM_stream_usage type added.");
|
||||
break;
|
||||
}
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
AMI_stream_single<T>::~AMI_stream_single(void)
|
||||
{
|
||||
if (destruct_bte) {
|
||||
delete btes;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
A_INLINE AMI_err AMI_stream_single<T>::read_item(T **elt)
|
||||
{
|
||||
BTE_err bte_err;
|
||||
AMI_err ae;
|
||||
|
||||
bte_err = btes->read_item(elt);
|
||||
switch(bte_err) {
|
||||
case BTE_ERROR_NO_ERROR:
|
||||
ae = AMI_ERROR_NO_ERROR;
|
||||
break;
|
||||
case BTE_ERROR_END_OF_STREAM:
|
||||
TP_LOG_DEBUG_ID("eos in read_item");
|
||||
ae = AMI_ERROR_END_OF_STREAM;
|
||||
break;
|
||||
default:
|
||||
TP_LOG_DEBUG_ID("bte error in read_item");
|
||||
ae = AMI_ERROR_BTE_ERROR;
|
||||
break;
|
||||
}
|
||||
return ae;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
A_INLINE AMI_err AMI_stream_single<T>::write_item(const T &elt)
|
||||
{
|
||||
if (btes->write_item(elt) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("bte error");
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
A_INLINE AMI_err AMI_stream_single<T>::read_array(T *mm_space, TPIE_OS_OFFSET *len)
|
||||
{
|
||||
BTE_err be;
|
||||
T *read;
|
||||
TPIE_OS_OFFSET ii;
|
||||
|
||||
// How long is it.
|
||||
TPIE_OS_OFFSET str_len = *len;
|
||||
|
||||
// Read them all.
|
||||
for (ii = str_len; ii--; ) {
|
||||
if ((be = btes->read_item(&read)) != BTE_ERROR_NO_ERROR) {
|
||||
if (be == BTE_ERROR_END_OF_STREAM) {
|
||||
return AMI_ERROR_END_OF_STREAM;
|
||||
} else {
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
}
|
||||
*mm_space++ = *read;
|
||||
}
|
||||
|
||||
*len = str_len;
|
||||
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
A_INLINE AMI_err AMI_stream_single<T>::write_array(const T *mm_space, TPIE_OS_OFFSET len)
|
||||
{
|
||||
BTE_err be;
|
||||
TPIE_OS_OFFSET ii;
|
||||
|
||||
for (ii = len; ii--; ) {
|
||||
if ((be = btes->write_item(*mm_space++)) != BTE_ERROR_NO_ERROR) {
|
||||
if (be == BTE_ERROR_END_OF_STREAM) {
|
||||
return AMI_ERROR_END_OF_STREAM;
|
||||
} else {
|
||||
return AMI_ERROR_BTE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int AMI_stream_single<T>::available_streams(void)
|
||||
{
|
||||
return btes->available_streams();
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void AMI_stream_single<T>::persist(persistence p)
|
||||
{
|
||||
btes->persist(p);
|
||||
}
|
||||
|
||||
// sprint()
|
||||
// Return a string describing the stream
|
||||
//
|
||||
// This function gives easy access to the file name, length.
|
||||
// It is not reentrant, but this should not be too much of a problem
|
||||
// if you are careful.
|
||||
template<class T>
|
||||
char *AMI_stream_single<T>::sprint()
|
||||
{
|
||||
static char buf[BUFSIZ];
|
||||
char *s;
|
||||
name(&s);
|
||||
sprintf(buf, "[AMI_STREAM %s %ld]", s, (long)stream_len());
|
||||
delete s;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif // _AMI_STREAM_SINGLE_H
|
||||
@@ -0,0 +1,212 @@
|
||||
// DK Summer 05 TODO:
|
||||
// get rid of dh extension, convert to ami_merge
|
||||
// perhaps grab merge calls from ami_sort_single_dh
|
||||
// check mem usage thoroughly
|
||||
// get rid of varArrays where not needed
|
||||
// change "substream" to "run" where appropriate
|
||||
// get rid of User defined BTE junk
|
||||
// Document better
|
||||
|
||||
// File: apm_dh.h
|
||||
|
||||
#ifndef _APM_DH_H
|
||||
#define _APM_DH_H
|
||||
// **************************************************************************
|
||||
// * *
|
||||
// * This include file contains the routine *
|
||||
// * AMI_single_merge *
|
||||
// * used in several of TPIE's merge variants *
|
||||
// * *
|
||||
// **************************************************************************
|
||||
// $Id: apm_dh.h,v 1.18 2005/08/24 19:32:38 adanner Exp $
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Includes needed from TPIE
|
||||
#include <ami_stream.h>
|
||||
#include <tpie_tempnam.h>
|
||||
#include <mergeheap_dh.h> //For templated heaps
|
||||
#include <quicksort.h> //For templated qsort_items
|
||||
|
||||
typedef int arity_t;
|
||||
|
||||
// **************************************************************************
|
||||
// * *
|
||||
// * A M I _ s i n g l e _ m e r g e _ d h *
|
||||
// * *
|
||||
// * This is a common merge routine for all of the AMI_merge, AMI_ptr_merge *
|
||||
// * and AMI_key_merge entry points. It is also used by the sort entry *
|
||||
// * points AMI_sort, AMI_ptr_sort and AMI_key_sort and by the routine *
|
||||
// * AMI_partition_and_merge. Differences are encapsulated within the *
|
||||
// * merge heap object 'MergeHeap'. It is assumed that MergeHeap.allocate *
|
||||
// * was called before entering AMI_single_merge_dh. *
|
||||
// * *
|
||||
// **************************************************************************
|
||||
|
||||
template < class T, class M >
|
||||
AMI_err
|
||||
AMI_single_merge_dh (AMI_STREAM < T > **inStreams, arity_t arity,
|
||||
AMI_STREAM < T > *outStream, M MergeHeap,
|
||||
TPIE_OS_OFFSET cutoff=-1 )
|
||||
{
|
||||
|
||||
TPIE_OS_SIZE_T i;
|
||||
AMI_err ami_err;
|
||||
|
||||
TPIE_OS_OFFSET* nread = new TPIE_OS_OFFSET[arity];
|
||||
|
||||
//Pointers to current leading elements of streams
|
||||
T** in_objects = new T*[arity];
|
||||
|
||||
// **************************************************************
|
||||
// * Read first element from stream. Do not rewind! We may read *
|
||||
// * more elements from the same stream later. *
|
||||
// **************************************************************
|
||||
|
||||
for (i = 0; i < arity; i++) {
|
||||
|
||||
if ((ami_err = inStreams[i]->read_item (&(in_objects[i]))) !=
|
||||
AMI_ERROR_NO_ERROR) {
|
||||
if (ami_err == AMI_ERROR_END_OF_STREAM) {
|
||||
in_objects[i] = NULL;
|
||||
} else {
|
||||
delete[] in_objects;
|
||||
return ami_err;
|
||||
}
|
||||
} else {
|
||||
MergeHeap.insert( in_objects[i], i );
|
||||
}
|
||||
nread[i]=1;
|
||||
}
|
||||
|
||||
// *********************************************************
|
||||
// * Build a heap from the smallest items of each stream *
|
||||
// *********************************************************
|
||||
|
||||
MergeHeap.initialize ( );
|
||||
|
||||
// *********************************************************
|
||||
// * Perform the merge until the inputs are exhausted. *
|
||||
// *********************************************************
|
||||
while (MergeHeap.sizeofheap() > 0) {
|
||||
|
||||
i = MergeHeap.get_min_run_id ();
|
||||
|
||||
if ((ami_err = outStream->write_item (*in_objects[i]))
|
||||
!= AMI_ERROR_NO_ERROR) {
|
||||
delete[] in_objects;
|
||||
return ami_err;
|
||||
}
|
||||
|
||||
//Check if we read as many elements as we are allowed to
|
||||
if( (cutoff != -1) && (nread[i]>=cutoff)){
|
||||
ami_err=AMI_ERROR_END_OF_STREAM;
|
||||
}
|
||||
else {
|
||||
if ((ami_err = inStreams[i]->read_item (&(in_objects[i])))
|
||||
!= AMI_ERROR_NO_ERROR) {
|
||||
if (ami_err != AMI_ERROR_END_OF_STREAM) {
|
||||
delete[] in_objects;
|
||||
return ami_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ami_err == AMI_ERROR_END_OF_STREAM) {
|
||||
MergeHeap.delete_min_and_insert ((T *) NULL);
|
||||
} else {
|
||||
nread[i]++;
|
||||
MergeHeap.delete_min_and_insert (in_objects[i]);
|
||||
}
|
||||
}//while
|
||||
|
||||
//cleanup
|
||||
delete [] in_objects;
|
||||
delete [] nread;
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* *
|
||||
* The actual AMI_merge calls *
|
||||
* *
|
||||
* These are the AMI_merge entry points for merging without the *
|
||||
* 'merge_management_object' used by AMI_generalized_merge. *
|
||||
* These routines perform the special case of merging when the *
|
||||
* the required output is the original records interleaved *
|
||||
* according to a comparison operator or function. *
|
||||
*******************************************************************/
|
||||
|
||||
/*
|
||||
Merging with a heap that contains the records to be merged: CMPR is
|
||||
the class of the comparison object, and must contain the method
|
||||
'compare' which is called from within the merge.
|
||||
|
||||
TODO:
|
||||
1) check that memory management is done right
|
||||
2) add comparison operator and comparison function versions
|
||||
3) watch out for conflicts with AMI_merge versions in
|
||||
*/
|
||||
|
||||
template < class T, class CMPR >
|
||||
AMI_err AMI_merge (AMI_STREAM < T > **inStreams, arity_t arity,
|
||||
AMI_STREAM < T > *outStream, CMPR *cmp)
|
||||
{
|
||||
// make a merge heap which uses the user's comparison object
|
||||
// and initialize it
|
||||
merge_heap_dh_obj<T,CMPR> mrgheap (cmp);
|
||||
mrgheap.allocate (arity);
|
||||
//Rewind all the input streams
|
||||
for(int i=0; i<arity; i++){ inStreams[i]->seek(0); }
|
||||
return AMI_single_merge_dh ( inStreams, arity, outStream, mrgheap);
|
||||
}
|
||||
|
||||
// Merging with a heap that keeps a pointer to the records rather than
|
||||
// the records themselves: CMPR is the class of the comparison object,
|
||||
// and must contain the method 'compare' which is called from within
|
||||
// the merge.
|
||||
|
||||
// TODO:
|
||||
// 1) check that memory management is done right
|
||||
|
||||
template < class T, class CMPR >
|
||||
AMI_err AMI_ptr_merge (AMI_STREAM < T > **inStreams, arity_t arity,
|
||||
AMI_STREAM < T > *outStream, CMPR *cmp)
|
||||
{
|
||||
// make a merge heap of pointers which uses the user's comparison
|
||||
// object and initialize it
|
||||
merge_heap_pdh_obj<T,CMPR> mrgheap (cmp);
|
||||
mrgheap.allocate (arity);
|
||||
//Rewind all the input streams
|
||||
for(int i=0; i<arity; i++){ inStreams[i]->seek(0); }
|
||||
|
||||
return AMI_single_merge_dh ( inStreams, arity, outStream, mrgheap);
|
||||
}
|
||||
|
||||
// Merging with a heap that contains copies of the keys from the
|
||||
// records being merged, rather than the records themselves:
|
||||
|
||||
// The comparison object "cmp", of (user-defined) class represented by
|
||||
// CMPR, must have a member function called "compare" which is used
|
||||
// for merging the input streams, and a member function called "copy"
|
||||
// which is used for copying the key (of type KEY) from a record of
|
||||
// type T (the type to be sorted).
|
||||
|
||||
// TODO:
|
||||
// 1) check that memory management is done right
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
AMI_err AMI_key_merge (AMI_STREAM < T > **inStreams, arity_t arity,
|
||||
AMI_STREAM < T > *outStream, CMPR *cmp)
|
||||
{
|
||||
// make a key merge heap which uses the user's comparison object
|
||||
// and initialize it
|
||||
merge_heap_dh_kobj<T,KEY,CMPR> mrgheap (cmp);
|
||||
mrgheap.allocate (arity);
|
||||
//Rewind all the input streams
|
||||
for(int i=0; i<arity; i++){ inStreams[i]->seek(0); }
|
||||
|
||||
return AMI_single_merge_dh ( inStreams, arity, outStream, mrgheap);
|
||||
}
|
||||
|
||||
#endif //_APM_DH_H
|
||||
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// File: b_vector.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// Definition of the b_vector class.
|
||||
//
|
||||
// $Id: b_vector.h,v 1.7 2003/04/17 14:40:34 jan Exp $
|
||||
//
|
||||
|
||||
#ifndef _B_VECTOR_H
|
||||
#define _B_VECTOR_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
template<class T>
|
||||
class b_vector {
|
||||
protected:
|
||||
T* p_;
|
||||
size_t capacity_;
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_type;
|
||||
typedef value_type* iterator;
|
||||
typedef const value_type* const_iterator;
|
||||
|
||||
b_vector(T* p, size_t cap): p_(p), capacity_(cap) {}
|
||||
|
||||
iterator begin() { return p_; }
|
||||
const_iterator begin() const { return p_; }
|
||||
iterator end() { return p_ + capacity_; }
|
||||
const_iterator end() const { return p_ + capacity_; }
|
||||
|
||||
// Get a reference to the i'th element.
|
||||
T& operator[](size_t i) { return *(p_ + i); }
|
||||
// Get a const reference to the i'th element.
|
||||
const T& operator[](size_t i) const { return *(p_ + i); }
|
||||
|
||||
size_t capacity() const { return capacity_; }
|
||||
|
||||
// Copy length elements from the source vector, starting with
|
||||
// element s_start, to this block, starting with element start.
|
||||
// Return the number of elements copied. Source can be *this.
|
||||
size_t copy(size_t start, size_t length,
|
||||
const b_vector<T>& source, size_t s_start = 0);
|
||||
|
||||
// Copy from an array of elements.
|
||||
size_t copy(size_t start, size_t length, const T* source);
|
||||
|
||||
// Insert item t in position pos; all items from position pos onward
|
||||
// are shifted one position higher; the last item is lost.
|
||||
void insert(const T& t, size_t pos);
|
||||
|
||||
// Erase the item in position pos and shift all items from position
|
||||
// pos+1 onward one position lower; the last item becomes identical
|
||||
// with the next to last item.
|
||||
void erase(size_t pos);
|
||||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
///////// **b_vector** /////////
|
||||
////////////////////////////////
|
||||
|
||||
//// *b_vector::copy* ////
|
||||
template<class T>
|
||||
size_t b_vector<T>::copy(size_t start, size_t length,
|
||||
const b_vector<T>& source, size_t s_start) {
|
||||
|
||||
// copy_length will store the actual number of items that can be copied.
|
||||
size_t copy_length = length;
|
||||
|
||||
if (start < capacity_ && s_start < source.capacity()) {
|
||||
// Check how much of length we can copy.
|
||||
copy_length = (copy_length > capacity_ - start) ?
|
||||
capacity_ - start: copy_length;
|
||||
copy_length = (copy_length > source.capacity() - s_start) ?
|
||||
source.capacity() - s_start: copy_length;
|
||||
|
||||
memmove(&(*this)[start], &source[s_start], copy_length * sizeof(T));
|
||||
} else {
|
||||
// start is too big. No copying.
|
||||
copy_length = 0;
|
||||
}
|
||||
|
||||
return copy_length;
|
||||
}
|
||||
|
||||
//// *b_vector::copy* ////
|
||||
template<class T>
|
||||
size_t b_vector<T>::copy(size_t start, size_t length, const T* source) {
|
||||
|
||||
size_t copy_length = length;
|
||||
|
||||
if (start < capacity_) {
|
||||
// Check how much of length we can copy.
|
||||
copy_length = (copy_length > capacity_ - start) ?
|
||||
capacity_ - start: copy_length;
|
||||
|
||||
memmove(&(*this)[start], source, copy_length * sizeof(T));
|
||||
} else
|
||||
copy_length = 0;
|
||||
|
||||
return copy_length;
|
||||
}
|
||||
|
||||
//// *b_vector::insert* ////
|
||||
template<class T>
|
||||
void b_vector<T>::insert(const T& t, size_t pos) {
|
||||
copy(pos + 1, capacity_ - pos - 1, *this, pos);
|
||||
copy(pos, 1, &t);
|
||||
}
|
||||
|
||||
//// *b_vector::erase* ////
|
||||
template<class T>
|
||||
void b_vector<T>::erase(size_t pos) {
|
||||
copy(pos, capacity_ - pos - 1, *this, pos + 1);
|
||||
}
|
||||
|
||||
#endif // _B_VECTOR_H
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: bit.cpp
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 11/4/94
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(bit_cpp,"$Id: bit.cpp,v 1.5 2003/09/12 18:46:44 jan Exp $");
|
||||
|
||||
#include <bit.h>
|
||||
|
||||
bit::bit(void)
|
||||
{
|
||||
}
|
||||
|
||||
bit::bit(bool b)
|
||||
{
|
||||
data = (b == true);
|
||||
}
|
||||
|
||||
bit::bit(int i)
|
||||
{
|
||||
data = (i != 0);
|
||||
}
|
||||
|
||||
bit::bit(long int i)
|
||||
{
|
||||
data = (i != 0);
|
||||
}
|
||||
|
||||
bit::operator bool(void)
|
||||
{
|
||||
return (data != 0);
|
||||
}
|
||||
|
||||
bit::operator int(void)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
bit::operator long int(void)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
bit::~bit(void)
|
||||
{
|
||||
}
|
||||
|
||||
bit bit::operator+=(bit rhs)
|
||||
{
|
||||
return *this = *this + rhs;
|
||||
}
|
||||
|
||||
bit bit::operator*=(bit rhs)
|
||||
{
|
||||
return *this = *this + rhs;
|
||||
}
|
||||
|
||||
bit operator+(bit op1, bit op2)
|
||||
{
|
||||
return bit(op1.data ^ op2.data);
|
||||
}
|
||||
|
||||
|
||||
bit operator*(bit op1, bit op2)
|
||||
{
|
||||
return bit(op1.data & op2.data);
|
||||
}
|
||||
|
||||
|
||||
ostream &operator<<(ostream &s, bit b)
|
||||
{
|
||||
return s << int(b.data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: bit.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 11/4/94
|
||||
//
|
||||
// $Id: bit.h,v 1.5 2003/09/12 01:46:38 jan Exp $
|
||||
//
|
||||
#ifndef _BIT_H
|
||||
#define _BIT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// A bit with two operarators, addition (= XOR) and multiplication (=
|
||||
// AND).
|
||||
class bit {
|
||||
private:
|
||||
char data;
|
||||
public:
|
||||
bit(void);
|
||||
bit(bool);
|
||||
bit(int);
|
||||
bit(long int);
|
||||
~bit(void);
|
||||
|
||||
operator bool(void);
|
||||
operator int(void);
|
||||
operator long int(void);
|
||||
|
||||
bit operator+=(bit rhs);
|
||||
bit operator*=(bit rhs);
|
||||
|
||||
friend bit operator+(bit op1, bit op2);
|
||||
friend bit operator*(bit op1, bit op2);
|
||||
|
||||
friend ostream &operator<<(ostream &s, bit b);
|
||||
};
|
||||
|
||||
#endif // _BIT_H
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: bit_matrix.cpp
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/9/95
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(bit_matrix_cpp,"$Id: bit_matrix.cpp,v 1.15 2005/01/14 18:42:24 tavi Exp $");
|
||||
|
||||
#include <bit_matrix.h>
|
||||
|
||||
bit_matrix::bit_matrix(TPIE_OS_SIZE_T arows, TPIE_OS_SIZE_T acols) :
|
||||
matrix<bit>(arows, acols)
|
||||
{
|
||||
}
|
||||
|
||||
bit_matrix::bit_matrix(matrix<bit> &mb) :
|
||||
matrix<bit>(mb)
|
||||
{
|
||||
}
|
||||
|
||||
bit_matrix::~bit_matrix(void)
|
||||
{
|
||||
}
|
||||
|
||||
bit_matrix bit_matrix::operator=(const bit_matrix &rhs) {
|
||||
return this->matrix<bit>::operator=((matrix<bit> &)rhs);
|
||||
}
|
||||
|
||||
bit_matrix & bit_matrix::operator=(const TPIE_OS_OFFSET &rhs)
|
||||
{
|
||||
TPIE_OS_SIZE_T rows = this->rows();
|
||||
TPIE_OS_SIZE_T ii;
|
||||
|
||||
if (this->cols() != 1) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<bit>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (ii = 0; ii < rows; ii++) {
|
||||
(*this)[ii][0] = (long int)(rhs & (1 << ii)) >> ii;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bit_matrix::operator TPIE_OS_OFFSET(void)
|
||||
{
|
||||
TPIE_OS_OFFSET res;
|
||||
|
||||
TPIE_OS_SIZE_T rows = this->rows();
|
||||
TPIE_OS_SIZE_T ii;
|
||||
|
||||
if (this->cols() != 1) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<bit>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (res = 0, ii = 0; ii < rows; ii++) {
|
||||
res |= (long int)((*this)[ii][0]) << ii;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bit_matrix operator+(const bit_matrix &op1, const bit_matrix &op2)
|
||||
{
|
||||
matrix<bit> sum = ((matrix<bit> &)op1) + ((matrix<bit> &)op2);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
bit_matrix operator*(const bit_matrix &op1, const bit_matrix &op2)
|
||||
{
|
||||
matrix<bit> prod = ((matrix<bit> &)op1) * ((matrix<bit> &)op2);
|
||||
|
||||
return prod;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &s, bit_matrix &bm)
|
||||
{
|
||||
return s << (matrix<bit> &)bm;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: bit_matrix.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 11/4/94
|
||||
//
|
||||
// $Id: bit_matrix.h,v 1.14 2005/01/14 18:35:00 tavi Exp $
|
||||
//
|
||||
#ifndef _BIT_MATRIX_H
|
||||
#define _BIT_MATRIX_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <bit.h>
|
||||
#include <matrix.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
// typedef matrix<bit> bit_matrix_0;
|
||||
|
||||
class bit_matrix : public matrix<bit> {
|
||||
public:
|
||||
using matrix<bit>::rows;
|
||||
using matrix<bit>::cols;
|
||||
|
||||
bit_matrix(matrix<bit> &mb);
|
||||
bit_matrix(TPIE_OS_SIZE_T rows, TPIE_OS_SIZE_T cols);
|
||||
virtual ~bit_matrix(void);
|
||||
|
||||
bit_matrix operator=(const bit_matrix &rhs);
|
||||
|
||||
// We can assign from an offset, which is typically a source
|
||||
// address for a BMMC permutation.
|
||||
bit_matrix &operator=(const TPIE_OS_OFFSET &rhs);
|
||||
|
||||
operator TPIE_OS_OFFSET(void);
|
||||
|
||||
friend bit_matrix operator+(const bit_matrix &op1, const bit_matrix &op2);
|
||||
friend bit_matrix operator*(const bit_matrix &op1, const bit_matrix &op2);
|
||||
};
|
||||
|
||||
bit_matrix operator+(const bit_matrix &op1, const bit_matrix &op2);
|
||||
bit_matrix operator*(const bit_matrix &op1, const bit_matrix &op2);
|
||||
|
||||
ostream &operator<<(ostream &s, bit_matrix &bm);
|
||||
|
||||
#endif // _BIT_MATRIX_H
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// File: bte_coll.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: bte_coll.h,v 1.4 2003/04/29 05:29:42 tavi Exp $
|
||||
//
|
||||
// Front end for the BTE collection classes.
|
||||
//
|
||||
|
||||
#ifndef _BTE_COLL_H
|
||||
#define _BTE_COLL_H
|
||||
|
||||
// Get the base class and various definitions.
|
||||
#include <bte_coll_base.h>
|
||||
|
||||
// The MMAP implementation.
|
||||
#include <bte_coll_mmap.h>
|
||||
|
||||
// The UFS implementation.
|
||||
#include <bte_coll_ufs.h>
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
|
||||
#if defined(BTE_COLLECTION_IMP_MMB)
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_BTE_COLLECTION_IMP_MMB_UNIX_ONLY
|
||||
# define BTE_COLLECTION_IMP_MMAP
|
||||
#endif
|
||||
|
||||
#define _BTE_COLL_IMP_COUNT (defined(BTE_COLLECTION_IMP_UFS) + \
|
||||
defined(BTE_COLLECTION_IMP_MMAP) + \
|
||||
defined(BTE_COLLECTION_IMP_USER_DEFINED))
|
||||
|
||||
// Multiple implem. are included, but we have to choose a default one.
|
||||
#if (_BTE_COLL_IMP_COUNT > 1)
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_MULTIPLE_BTE_COLLECTION_IMP_DEFINED
|
||||
# define BTE_COLLECTION_IMP_MMAP
|
||||
#elif (_BTE_COLL_IMP_COUNT == 0)
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_NO_DEFAULT_BTE_COLLECTION
|
||||
# define BTE_COLLECTION_IMP_MMAP
|
||||
#endif
|
||||
|
||||
#define BTE_COLLECTION_MMAP BTE_collection_mmap<TPIE_BLOCK_ID_TYPE>
|
||||
#define BTE_COLLECTION_UFS BTE_collection_ufs<TPIE_BLOCK_ID_TYPE>
|
||||
|
||||
#if defined(BTE_COLLECTION_IMP_MMAP)
|
||||
# define BTE_COLLECTION BTE_COLLECTION_MMAP
|
||||
#elif defined(BTE_COLLECTION_IMP_UFS)
|
||||
# define BTE_COLLECTION BTE_COLLECTION_UFS
|
||||
#elif defined(BTE_COLLECTION_IMP_USER_DEFINED)
|
||||
// Do not define BTE_COLLECTION. The user will define it.
|
||||
#endif
|
||||
|
||||
#endif // _BTE_COLL_H
|
||||
@@ -0,0 +1,624 @@
|
||||
// Copyright (c) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: bte_coll_base.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// (using some code by Rakesh Barve)
|
||||
//
|
||||
// $Id: bte_coll_base.h,v 1.27 2004/08/17 16:48:06 jan Exp $
|
||||
//
|
||||
// BTE_collection_base class and various basic definitions.
|
||||
|
||||
|
||||
#ifndef _BTE_COLL_BASE_H
|
||||
#define _BTE_COLL_BASE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Include the registration based memory manager.
|
||||
#define MM_IMP_REGISTER
|
||||
#include <mm.h>
|
||||
|
||||
// For persist.
|
||||
#include <persist.h>
|
||||
// For BTE_stack_ufs
|
||||
#include <bte_stack_ufs.h>
|
||||
// For BTE_err.
|
||||
#include <bte_err.h>
|
||||
// For class tpie_stats_collection.
|
||||
#include <tpie_stats_coll.h>
|
||||
|
||||
// BTE_COLLECTION types passed to constructors.
|
||||
enum BTE_collection_type {
|
||||
BTE_READ_COLLECTION = 1, // Open existing stream read only.
|
||||
BTE_WRITE_COLLECTION, // Open for read/write. Create if non-existent.
|
||||
BTE_WRITE_NEW_COLLECTION // Open for read/write a new collection,
|
||||
// even if a nonempty file with that name exists.
|
||||
};
|
||||
|
||||
// BTE collection status.
|
||||
enum BTE_collection_status {
|
||||
BTE_COLLECTION_STATUS_VALID = 0,
|
||||
BTE_COLLECTION_STATUS_INVALID = 1
|
||||
};
|
||||
|
||||
|
||||
// Maximum length of the file names.
|
||||
#define BTE_COLLECTION_PATH_NAME_LEN 128
|
||||
|
||||
// Number of bytes in the header's user_data_ field.
|
||||
#define BTE_COLLECTION_USER_DATA_LEN 512
|
||||
|
||||
// The magic number of the files storing blocks.
|
||||
// (in network byteorder, it spells "TPBC": TPie Block Collection)
|
||||
#define BTE_COLLECTION_HEADER_MAGIC_NUMBER 0x54504243
|
||||
|
||||
// Default file name suffixes
|
||||
#define BTE_COLLECTION_BLK_SUFFIX ".blk"
|
||||
#define BTE_COLLECTION_STK_SUFFIX ".stk"
|
||||
|
||||
// Setting this to 1 causes the use of ftruncate(2) for extending
|
||||
// files, which, in conjunction with mmap(2), results in more
|
||||
// fragmented files and, consequently, slower I/O. See mmap(2) on
|
||||
// FreeBSD for an explanation. When set to 0, lseek(2) and write(2)
|
||||
// are used to extend the files. This should be set to 1 for WIN32
|
||||
// (see portability.h)
|
||||
#ifndef BTE_COLLECTION_USE_FTRUNCATE
|
||||
#define BTE_COLLECTION_USE_FTRUNCATE 0
|
||||
#endif
|
||||
|
||||
|
||||
// The in-memory representation of the BTE_COLLECTION header.
|
||||
// This data structure is read from/written to the first
|
||||
// (physical) page of the blocks file.
|
||||
|
||||
class BTE_collection_header {
|
||||
public:
|
||||
|
||||
// Unique header identifier. Set to BTE_COLLECTION_HEADER_MAGIC_NUMBER
|
||||
unsigned int magic_number;
|
||||
// Should be 1 for current version.
|
||||
unsigned int version;
|
||||
// The type of BTE_COLLECTION that created this header. Setting this
|
||||
// field is optional and is mostly for information purposes and
|
||||
// similarity with stream header. The current implementations all
|
||||
// use the same file format; it's not important to differentiate
|
||||
// among them, since they can all read each other's collections. If
|
||||
// used, it should be set to a non-zero value (zero is reserved for
|
||||
// the base class).
|
||||
unsigned int type;
|
||||
// The number of bytes in this structure.
|
||||
TPIE_OS_SIZE_T header_length;
|
||||
// The number of blocks consumed by this collection, plus 1.
|
||||
TPIE_OS_OFFSET total_blocks;
|
||||
// The highest bid any block of this block collection has, PLUS 1
|
||||
// (always <= total_blocks).
|
||||
TPIE_OS_OFFSET last_block;
|
||||
// The number of valid blocks in this block collection.
|
||||
TPIE_OS_OFFSET used_blocks;
|
||||
// The size of a physical block on the device this stream resides.
|
||||
TPIE_OS_SIZE_T os_block_size;
|
||||
// Size in bytes of each logical block.
|
||||
TPIE_OS_SIZE_T block_size;
|
||||
// Some data to be filled by the user of the collection.
|
||||
char user_data[BTE_COLLECTION_USER_DATA_LEN];
|
||||
|
||||
// Default constructor.
|
||||
BTE_collection_header():
|
||||
magic_number(BTE_COLLECTION_HEADER_MAGIC_NUMBER),
|
||||
version(1),
|
||||
type(0),
|
||||
header_length(sizeof(BTE_collection_header)),
|
||||
total_blocks(1),
|
||||
last_block(1),
|
||||
used_blocks(0) {
|
||||
os_block_size = TPIE_OS_BLOCKSIZE();
|
||||
}
|
||||
};
|
||||
|
||||
// A base class for all implementations of block collection classes.
|
||||
template <class BIDT>
|
||||
class BTE_collection_base {
|
||||
protected:
|
||||
|
||||
// Various parameters (will be stored into the file header block).
|
||||
BTE_collection_header header_;
|
||||
|
||||
// A stack of TPIE_OS_OFFSET's.
|
||||
BTE_stack_ufs<BIDT> *freeblock_stack_;
|
||||
|
||||
// File descriptor for the file backing the block collection.
|
||||
TPIE_OS_FILE_DESCRIPTOR bcc_fd_;
|
||||
|
||||
char base_file_name_[BTE_COLLECTION_PATH_NAME_LEN];
|
||||
|
||||
TPIE_OS_SIZE_T os_block_size_;
|
||||
|
||||
// Persistency flag. Set during construction and using the persist()
|
||||
// method.
|
||||
persistence per_;
|
||||
|
||||
// Status of the collection. Set during construction.
|
||||
BTE_collection_status status_;
|
||||
|
||||
// Read-only flag. Set during construction.
|
||||
bool read_only_;
|
||||
|
||||
// Number of blocks from this collection that are currently in memory
|
||||
TPIE_OS_SIZE_T in_memory_blocks_;
|
||||
|
||||
// File pointer position. A value of -1 signals unknown position.
|
||||
TPIE_OS_OFFSET file_pointer;
|
||||
|
||||
// Statistics for this object.
|
||||
tpie_stats_collection stats_;
|
||||
|
||||
// Global collection statistics.
|
||||
static tpie_stats_collection gstats_;
|
||||
|
||||
private:
|
||||
// Helper functions. We don't want them inherited.
|
||||
|
||||
// Initialization common to all constructors.
|
||||
void shared_init(BTE_collection_type type, size_t logical_block_factor, TPIE_OS_MAPPING_FLAG mapping);
|
||||
|
||||
// Read header from disk.
|
||||
BTE_err read_header(char *bcc_name);
|
||||
|
||||
// Write header to disk.
|
||||
BTE_err write_header(char* bcc_name);
|
||||
|
||||
void remove_stack_file();
|
||||
|
||||
protected:
|
||||
|
||||
// Needs to be inlined!
|
||||
BTE_err register_memory_allocation(TPIE_OS_SIZE_T sz) {
|
||||
if (MM_manager.register_allocation(sz) != MM_ERROR_NO_ERROR) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Memory manager error in allocation.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Needs to be inlined!
|
||||
BTE_err register_memory_deallocation(TPIE_OS_SIZE_T sz) {
|
||||
if (MM_manager.register_deallocation(sz) != MM_ERROR_NO_ERROR) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Memory manager error in deallocation.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
TPIE_OS_OFFSET bid_to_file_offset(BIDT bid) const
|
||||
{ return header_.os_block_size + header_.block_size * (bid-1); }
|
||||
|
||||
void create_stack();
|
||||
|
||||
// Common code for all new_block implementations. Inlined.
|
||||
BTE_err new_block_getid(BIDT& bid) {
|
||||
// We try getting a free bid from the stack first. If there aren't
|
||||
// any there, we will try to get one after last_block; if there are
|
||||
// no blocks past last_block, we will ftruncate() some more blocks
|
||||
// to the tail of the BCC and then get a free bid.
|
||||
BIDT *lbn;
|
||||
BTE_err err;
|
||||
if (header_.used_blocks < header_.last_block - 1) {
|
||||
tp_assert(freeblock_stack_ != NULL,
|
||||
"BTE_collection_ufs internal error: NULL stack pointer");
|
||||
// TODO: this is a costly operation. improve!
|
||||
TPIE_OS_OFFSET slen = freeblock_stack_->stream_len();
|
||||
tp_assert(slen > 0, "BTE_collection_ufs internal error: empty stack");
|
||||
if ((err = freeblock_stack_->pop(&lbn)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
bid = *lbn;
|
||||
} else {
|
||||
tp_assert(header_.last_block <= header_.total_blocks,
|
||||
"BTE_collection_ufs internal error: last_block>total_blocks");
|
||||
if (header_.last_block == header_.total_blocks) {
|
||||
// Increase the capacity for storing blocks in the stream by
|
||||
// 16 (only by 2 the first time around to be gentle with very
|
||||
// small coll's).
|
||||
if (header_.total_blocks == 1)
|
||||
header_.total_blocks += 2;
|
||||
else if (header_.total_blocks <= 161)
|
||||
header_.total_blocks += 8;
|
||||
else
|
||||
header_.total_blocks += 64;
|
||||
|
||||
|
||||
#if BTE_COLLECTION_USE_FTRUNCATE
|
||||
if (TPIE_OS_FTRUNCATE(bcc_fd_, bid_to_file_offset(header_.total_blocks))) {
|
||||
TP_LOG_FATAL_ID("Failed to truncate to the new end of file.");
|
||||
//LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
#else
|
||||
char* tbuf = new char[header_.os_block_size];
|
||||
TPIE_OS_OFFSET curr_off;
|
||||
|
||||
if ((curr_off = TPIE_OS_LSEEK(bcc_fd_, 0, TPIE_OS_FLAG_SEEK_END)) == (TPIE_OS_OFFSET)(-1)) {
|
||||
TP_LOG_FATAL_ID("Failed to seek to the end of file.");
|
||||
//LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
while (curr_off < bid_to_file_offset(header_.total_blocks)) {
|
||||
TPIE_OS_WRITE(bcc_fd_, tbuf, header_.os_block_size);
|
||||
curr_off += header_.os_block_size;
|
||||
}
|
||||
delete [] tbuf;
|
||||
file_pointer = curr_off;
|
||||
#endif
|
||||
|
||||
}
|
||||
bid = header_.last_block++;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Common code for all delete_block implementations. Inlined.
|
||||
BTE_err delete_block_shared(BIDT bid) {
|
||||
if (bid == header_.last_block - 1)
|
||||
header_.last_block--;
|
||||
else {
|
||||
if (freeblock_stack_ == NULL)
|
||||
create_stack();
|
||||
//tp_assert(freeblock_stack_ != NULL,
|
||||
// "BTE_collection_ufs internal error: NULL stack pointer");
|
||||
return freeblock_stack_->push(bid);
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef BIDT block_id_t;
|
||||
|
||||
BTE_collection_base(const char *base_name, BTE_collection_type ct,
|
||||
size_t logical_block_factor, TPIE_OS_MAPPING_FLAG mapping = TPIE_OS_FLAG_USE_MAPPING_FALSE);
|
||||
|
||||
// Return the total number of used blocks.
|
||||
TPIE_OS_OFFSET size() const { return header_.used_blocks; }
|
||||
|
||||
// Return the total number of blocks consumed by the block collection.
|
||||
TPIE_OS_OFFSET file_size() const { return header_.total_blocks - 1; }
|
||||
|
||||
// Return the logical block size in bytes.
|
||||
TPIE_OS_SIZE_T block_size() const { return header_.block_size; }
|
||||
|
||||
// Return the logical block factor.
|
||||
TPIE_OS_SIZE_T block_factor() const
|
||||
{ return header_.block_size / header_.os_block_size; }
|
||||
|
||||
// Return the status of the collection.
|
||||
BTE_collection_status status() const { return status_; }
|
||||
|
||||
// Set the persistence flag.
|
||||
void persist(persistence p) { per_ = p; }
|
||||
|
||||
// Inquire the persistence status.
|
||||
persistence persist() const { return per_; }
|
||||
|
||||
const char *base_file_name() const { return base_file_name_; }
|
||||
|
||||
void *user_data() { return (void *) header_.user_data; }
|
||||
|
||||
// Local statistics (for this object).
|
||||
const tpie_stats_collection& stats() const { return stats_; }
|
||||
|
||||
// Global statistics (for all collections).
|
||||
static const tpie_stats_collection& gstats() { return gstats_; }
|
||||
|
||||
// Destructor.
|
||||
~BTE_collection_base();
|
||||
|
||||
#if defined(__sun__)
|
||||
static bool direct_io;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
tpie_stats_collection BTE_collection_base<BIDT>::gstats_;
|
||||
|
||||
template<class BIDT>
|
||||
void BTE_collection_base<BIDT>::create_stack() {
|
||||
// Fill in the stack file name.
|
||||
char stack_name[BTE_COLLECTION_PATH_NAME_LEN];
|
||||
strncpy((char *) stack_name, base_file_name_, BTE_COLLECTION_PATH_NAME_LEN - 4);
|
||||
strcat((char *) stack_name, BTE_COLLECTION_STK_SUFFIX);
|
||||
|
||||
// Construct the pre-existing freeblock_stack.
|
||||
freeblock_stack_ = new BTE_stack_ufs<BIDT>((char *) stack_name,
|
||||
read_only_? BTE_READ_STREAM: BTE_WRITE_STREAM);
|
||||
|
||||
}
|
||||
|
||||
template<class BIDT>
|
||||
void BTE_collection_base<BIDT>::remove_stack_file() {
|
||||
// Fill in the stack file name.
|
||||
char stack_name[BTE_COLLECTION_PATH_NAME_LEN];
|
||||
strncpy((char *) stack_name, base_file_name_, BTE_COLLECTION_PATH_NAME_LEN - 4);
|
||||
strcat((char *) stack_name, BTE_COLLECTION_STK_SUFFIX);
|
||||
|
||||
TPIE_OS_UNLINK(stack_name);
|
||||
}
|
||||
|
||||
template<class BIDT>
|
||||
BTE_collection_base<BIDT>::BTE_collection_base(const char *base_name,
|
||||
BTE_collection_type type, size_t logical_block_factor, TPIE_OS_MAPPING_FLAG mapping):
|
||||
header_(), freeblock_stack_(NULL) {
|
||||
|
||||
if (base_name == NULL) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("NULL file name passed to constructor");
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy((char*) base_file_name_, base_name, BTE_COLLECTION_PATH_NAME_LEN - 4);
|
||||
|
||||
// A collection with a given name is not deleted upon destruction.
|
||||
per_ = PERSIST_PERSISTENT;
|
||||
|
||||
shared_init(type, logical_block_factor, mapping);
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
void BTE_collection_base<BIDT>::shared_init(BTE_collection_type type,
|
||||
TPIE_OS_SIZE_T logical_block_factor, TPIE_OS_MAPPING_FLAG mapping) {
|
||||
read_only_ = (type == BTE_READ_COLLECTION);
|
||||
status_ = BTE_COLLECTION_STATUS_VALID;
|
||||
in_memory_blocks_ = 0;
|
||||
file_pointer = -1;
|
||||
os_block_size_ = TPIE_OS_BLOCKSIZE();
|
||||
|
||||
// Fill in the blocks file name.
|
||||
char bcc_name[BTE_COLLECTION_PATH_NAME_LEN];
|
||||
strncpy((char *) bcc_name, base_file_name_, BTE_COLLECTION_PATH_NAME_LEN - 4);
|
||||
strcat((char *) bcc_name, BTE_COLLECTION_BLK_SUFFIX);
|
||||
|
||||
if (read_only_) {
|
||||
|
||||
if (!TPIE_OS_IS_VALID_FILE_DESCRIPTOR(bcc_fd_ = TPIE_OS_OPEN_ORDONLY(bcc_name, mapping))) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("open() failed to open read-only file: ");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_header(bcc_name) != BTE_ERROR_NO_ERROR) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether we need a stack.
|
||||
if (header_.used_blocks < header_.last_block - 1) {
|
||||
create_stack();
|
||||
if (freeblock_stack_->status() == BTE_STREAM_STATUS_INVALID) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
freeblock_stack_ = NULL;
|
||||
|
||||
} else { // Writeable bcc.
|
||||
|
||||
// If a new collection, remove any existing files with the same names.
|
||||
if (type == BTE_WRITE_NEW_COLLECTION) {
|
||||
TPIE_OS_UNLINK(bcc_name);
|
||||
remove_stack_file();
|
||||
}
|
||||
|
||||
// Open the file for writing. First we will try to open
|
||||
// it with the O_EXCL flag set. This will fail if the file
|
||||
// already exists. If this is the case, we will call open()
|
||||
// again without it and read in the header block.
|
||||
if (!TPIE_OS_IS_VALID_FILE_DESCRIPTOR(bcc_fd_ = TPIE_OS_OPEN_OEXCL(bcc_name,mapping))) {
|
||||
|
||||
// Try again, hoping the file already exists.
|
||||
if (!TPIE_OS_IS_VALID_FILE_DESCRIPTOR(bcc_fd_ = TPIE_OS_OPEN_ORDWR(bcc_name,mapping))) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("open() failed to open file:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_header(bcc_name) != BTE_ERROR_NO_ERROR) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether we need a stack.
|
||||
if (header_.used_blocks < header_.last_block - 1) {
|
||||
create_stack();
|
||||
if (freeblock_stack_->status() == BTE_STREAM_STATUS_INVALID) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
freeblock_stack_ = NULL;
|
||||
|
||||
} else { // The file was just created.
|
||||
|
||||
tp_assert(header_.magic_number == BTE_COLLECTION_HEADER_MAGIC_NUMBER, "Header magic number mismatch.");
|
||||
tp_assert(header_.os_block_size == os_block_size_, "Header os_block_size mismatch.");
|
||||
|
||||
header_.block_size = logical_block_factor * header_.os_block_size;
|
||||
|
||||
if (write_header(bcc_name) != BTE_ERROR_NO_ERROR) {
|
||||
status_ = BTE_COLLECTION_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
// No stack (yet). Will be created by delete if needed.
|
||||
freeblock_stack_ = NULL;
|
||||
|
||||
gstats_.record(COLLECTION_CREATE);
|
||||
stats_.record(COLLECTION_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
if (direct_io)
|
||||
directio(bcc_fd_, DIRECTIO_ON);
|
||||
else
|
||||
directio(bcc_fd_, DIRECTIO_OFF);
|
||||
#endif
|
||||
|
||||
gstats_.record(COLLECTION_OPEN);
|
||||
stats_.record(COLLECTION_OPEN);
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
template<class BIDT>
|
||||
bool BTE_collection_base<BIDT>::direct_io = false;
|
||||
#endif
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_base<BIDT>::read_header(char* bcc_name) {
|
||||
|
||||
char * tmp_buffer = new char[os_block_size_];
|
||||
|
||||
if (TPIE_OS_LSEEK(bcc_fd_, 0, TPIE_OS_FLAG_SEEK_SET) != 0) {
|
||||
TP_LOG_FATAL_ID("Failed to lseek in file:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
if (TPIE_OS_READ(bcc_fd_, (char *)tmp_buffer, os_block_size_) != (int)os_block_size_) {
|
||||
TP_LOG_FATAL_ID("Failed to read() in file:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
file_pointer = os_block_size_;
|
||||
|
||||
memcpy((void *) &header_, (const void *) tmp_buffer,
|
||||
sizeof(BTE_collection_header));
|
||||
delete [] tmp_buffer;
|
||||
|
||||
// Do some error checking on the header, such as to make sure that
|
||||
// it has the correct header version, block size etc.
|
||||
if (header_.magic_number != BTE_COLLECTION_HEADER_MAGIC_NUMBER ||
|
||||
header_.os_block_size != os_block_size_) {
|
||||
TP_LOG_FATAL_ID("Invalid header in file: ");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return BTE_ERROR_BAD_HEADER;
|
||||
}
|
||||
|
||||
TPIE_OS_OFFSET lseek_retval;
|
||||
// Some more error checking.
|
||||
if ((lseek_retval = TPIE_OS_LSEEK(bcc_fd_, 0, TPIE_OS_FLAG_SEEK_END)) != bid_to_file_offset(header_.total_blocks)) {
|
||||
TP_LOG_FATAL_ID("File length mismatch for:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
TP_LOG_FATAL("\tReturn value of seek (to end): ");
|
||||
TP_LOG_FATAL(lseek_retval);
|
||||
TP_LOG_FATAL("\n\tReturn value of bid_to_file_offset(header_.total_blocks): ");
|
||||
TP_LOG_FATAL(bid_to_file_offset(header_.total_blocks));
|
||||
TP_LOG_FATAL("\n\theader_.total_blocks: ");
|
||||
TP_LOG_FATAL(header_.total_blocks);
|
||||
TP_LOG_FATAL("\n");
|
||||
return BTE_ERROR_BAD_HEADER;
|
||||
}
|
||||
|
||||
file_pointer = lseek_retval;
|
||||
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_base<BIDT>::write_header(char *bcc_name) {
|
||||
|
||||
char * tmp_buffer = new char[os_block_size_];
|
||||
memcpy((void *) tmp_buffer, (const void *) &header_,
|
||||
sizeof(BTE_collection_header));
|
||||
|
||||
if (TPIE_OS_LSEEK(bcc_fd_, 0, TPIE_OS_FLAG_SEEK_SET) != 0) {
|
||||
TP_LOG_FATAL_ID("Failed to lseek() in file:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
if (TPIE_OS_WRITE(bcc_fd_, tmp_buffer, os_block_size_) != (int)os_block_size_) {
|
||||
TP_LOG_FATAL_ID("Failed to write() in file:");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
file_pointer = os_block_size_;
|
||||
|
||||
// TP_LOG_APP_DEBUG_ID("header_.total_blocks: ");
|
||||
// TP_LOG_APP_DEBUG_ID(header_.total_blocks);
|
||||
|
||||
delete [] tmp_buffer;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_collection_base<BIDT>::~BTE_collection_base() {
|
||||
|
||||
char bcc_name[BTE_COLLECTION_PATH_NAME_LEN];
|
||||
strncpy((char *) bcc_name, base_file_name_,
|
||||
BTE_COLLECTION_PATH_NAME_LEN - 4);
|
||||
strcat((char *) bcc_name, BTE_COLLECTION_BLK_SUFFIX);
|
||||
|
||||
// No block should be in memory at the time of destruction.
|
||||
if (in_memory_blocks_) {
|
||||
TP_LOG_WARNING_ID("In memory blocks when closing collection in:");
|
||||
TP_LOG_WARNING_ID(base_file_name_);
|
||||
}
|
||||
|
||||
#if defined(__sun__)
|
||||
if (direct_io)
|
||||
directio(bcc_fd_, DIRECTIO_OFF);
|
||||
#endif
|
||||
|
||||
// Write the header.
|
||||
if (!read_only_)
|
||||
write_header(bcc_name);
|
||||
|
||||
// Delete the stack.
|
||||
if (freeblock_stack_ != NULL) {
|
||||
freeblock_stack_->persist(per_);
|
||||
delete freeblock_stack_;
|
||||
}
|
||||
|
||||
// Close the blocks file.
|
||||
if (TPIE_OS_CLOSE(bcc_fd_)) {
|
||||
TP_LOG_FATAL_ID("Failed to close() ");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return;
|
||||
}
|
||||
|
||||
// If necessary, remove the blocks file.
|
||||
if (per_ == PERSIST_DELETE) {
|
||||
if (read_only_) {
|
||||
TP_LOG_WARNING_ID("Read-only collection is PERSIST_DELETE");
|
||||
TP_LOG_WARNING_ID(bcc_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TPIE_OS_UNLINK(bcc_name)) {
|
||||
TP_LOG_FATAL_ID("Failed to unlink() ");
|
||||
TP_LOG_FATAL_ID(bcc_name);
|
||||
return;
|
||||
} else {
|
||||
gstats_.record(COLLECTION_DELETE);
|
||||
stats_.record(COLLECTION_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
gstats_.record(COLLECTION_CLOSE);
|
||||
stats_.record(COLLECTION_CLOSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //_BTE_COLL_BASE_H
|
||||
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// File: bte_coll_mmap.h (formerly bte_coll_mmb.h)
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: bte_coll_mmap.h,v 1.12 2005/01/14 18:58:32 tavi Exp $
|
||||
//
|
||||
// BTE_collection_mmap class definition.
|
||||
//
|
||||
#ifndef _BTE_COLL_MMAP_H
|
||||
#define _BTE_COLL_MMAP_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the base class.
|
||||
#include <bte_coll_base.h>
|
||||
|
||||
// For header's type field (77 == 'M').
|
||||
#define BTE_COLLECTION_MMAP_ID 77
|
||||
|
||||
// Define write behavior, if not already defined by the user.
|
||||
// Allowed values:
|
||||
// 0 (synchronous writes)
|
||||
// 1 (asynchronous writes using MS_ASYNC - see msync(2))
|
||||
// 2 (asynchronous bulk writes) [default]
|
||||
#ifndef BTE_COLLECTION_MMAP_LAZY_WRITE
|
||||
# define BTE_COLLECTION_MMAP_LAZY_WRITE 2
|
||||
#endif
|
||||
|
||||
template<class BIDT = TPIE_BLOCK_ID_TYPE>
|
||||
class BTE_collection_mmap: public BTE_collection_base<BIDT> {
|
||||
protected:
|
||||
using BTE_collection_base<BIDT>::header_;
|
||||
using BTE_collection_base<BIDT>::freeblock_stack_;
|
||||
using BTE_collection_base<BIDT>::bcc_fd_;
|
||||
using BTE_collection_base<BIDT>::per_;
|
||||
using BTE_collection_base<BIDT>::os_block_size_;
|
||||
using BTE_collection_base<BIDT>::base_file_name_;
|
||||
using BTE_collection_base<BIDT>::status_;
|
||||
using BTE_collection_base<BIDT>::read_only_;
|
||||
using BTE_collection_base<BIDT>::in_memory_blocks_;
|
||||
using BTE_collection_base<BIDT>::file_pointer;
|
||||
using BTE_collection_base<BIDT>::stats_;
|
||||
using BTE_collection_base<BIDT>::gstats_;
|
||||
using BTE_collection_base<BIDT>::register_memory_allocation;
|
||||
using BTE_collection_base<BIDT>::register_memory_deallocation;
|
||||
using BTE_collection_base<BIDT>::bid_to_file_offset;
|
||||
using BTE_collection_base<BIDT>::create_stack;
|
||||
using BTE_collection_base<BIDT>::new_block_getid;
|
||||
using BTE_collection_base<BIDT>::delete_block_shared;
|
||||
|
||||
|
||||
public:
|
||||
// Constructor. Read and verify the header of the
|
||||
// collection. Implemented in the base class.
|
||||
BTE_collection_mmap(const char *base_file_name,
|
||||
BTE_collection_type type = BTE_WRITE_COLLECTION,
|
||||
size_t logical_block_factor = 1):
|
||||
BTE_collection_base<BIDT>(base_file_name, type, logical_block_factor, TPIE_OS_FLAG_USE_MAPPING_TRUE) {
|
||||
header_.type = BTE_COLLECTION_MMAP_ID;
|
||||
}
|
||||
|
||||
// Allocate a new block in block collection and then map that block
|
||||
// into memory, allocating and returning an appropriately
|
||||
// initialized Block. Main memory usage increases.
|
||||
BTE_err new_block(BIDT &bid, void * &place) {
|
||||
BTE_err err;
|
||||
// Get a block id.
|
||||
if ((err = new_block_getid(bid)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
// We have a bid, so we can call the get_block routine.
|
||||
if ((err = get_block_internals(bid, place)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
header_.used_blocks++;
|
||||
stats_.record(BLOCK_NEW);
|
||||
gstats_.record(BLOCK_NEW);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Delete a previously created, currently mapped-in BLOCK. This causes the
|
||||
// number of free blocks in the collection to increase by 1, the bid is
|
||||
// entered into the stdio_stack. NOTE that it is the onus of the user of
|
||||
// this class to ensure that the bid of this placeholder is correct. No
|
||||
// check is made if the bid is an invalid or previously unallocated bid,
|
||||
// which will introduce erroneous entries in the stdio_stack of free
|
||||
// blocks. Main memory usage goes down.
|
||||
BTE_err delete_block(BIDT bid, void * place) {
|
||||
BTE_err err;
|
||||
if ((err = put_block_internals(bid, place, 1)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
if ((err = delete_block_shared(bid)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
header_.used_blocks--;
|
||||
stats_.record(BLOCK_DELETE);
|
||||
gstats_.record(BLOCK_DELETE);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Map in the block with the indicated bid and allocate and initialize a
|
||||
// corresponding placeholder. NOTE once more that it is the user's onus
|
||||
// to ensure that the bid requested corresponds to a valid block and so
|
||||
// on; no checks made here to ensure that that is indeed the case. Main
|
||||
// memory usage increases.
|
||||
BTE_err get_block(BIDT bid, void * &place) {
|
||||
BTE_err err;
|
||||
if ((err = get_block_internals(bid, place)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
stats_.record(BLOCK_GET);
|
||||
gstats_.record(BLOCK_GET);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Unmap a currently mapped in block. NOTE once more that it is the user's
|
||||
// onus to ensure that the bid is correct and so on; no checks made here
|
||||
// to ensure that that is indeed the case. Main memory usage decreases.
|
||||
BTE_err put_block(BIDT bid, void * place, char dirty = 1) {
|
||||
BTE_err err;
|
||||
if ((err = put_block_internals(bid, place, dirty)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
stats_.record(BLOCK_PUT);
|
||||
gstats_.record(BLOCK_PUT);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Synchronize the in-memory block with the on-disk block.
|
||||
BTE_err sync_block(BIDT bid, void* place, char dirty = 1);
|
||||
|
||||
protected:
|
||||
BTE_err get_block_internals(BIDT bid, void *&place);
|
||||
BTE_err put_block_internals(BIDT bid, void* place, char dirty);
|
||||
};
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_mmap<BIDT>::get_block_internals(BIDT bid, void * &place) {
|
||||
|
||||
place = TPIE_OS_MMAP(NULL, header_.block_size,
|
||||
read_only_ ? TPIE_OS_FLAG_PROT_READ :
|
||||
TPIE_OS_FLAG_PROT_READ | TPIE_OS_FLAG_PROT_WRITE,
|
||||
#ifdef SYSTYPE_BSD
|
||||
MAP_FILE | MAP_VARIABLE | MAP_NOSYNC |
|
||||
#endif
|
||||
TPIE_OS_FLAG_MAP_SHARED, bcc_fd_, bid_to_file_offset(bid));
|
||||
|
||||
if (place == (void *)(-1)) {
|
||||
TP_LOG_FATAL_ID("mmap() failed to map in a block from file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
// madvise(place, header_.block_size, MADV_RANDOM);
|
||||
|
||||
// Register the memory allocation since mmapped memory is
|
||||
// not accounted for otherwise.
|
||||
register_memory_allocation(header_.block_size);
|
||||
|
||||
in_memory_blocks_++;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_mmap<BIDT>::put_block_internals(BIDT bid, void* place, char dirty) {
|
||||
|
||||
// The dirty parameter is not used in this implemetation.
|
||||
|
||||
if ((bid <= 0) || (bid >= header_.last_block)) {
|
||||
TP_LOG_FATAL_ID("Incorrect bid in placeholder.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
#if (BTE_COLLECTION_MMAP_LAZY_WRITE < 2)
|
||||
if (!read_only_) {
|
||||
if (TPIE_OS_MSYNC((char*)place, header_.block_size,
|
||||
# if (BTE_COLLECTION_MMAP_LAZY_WRITE == 1)
|
||||
TPIE_OS_FLAG_MS_ASYNC
|
||||
# else
|
||||
TPIE_OS_FLAG_MS_SYNC
|
||||
# endif
|
||||
) == -1) {
|
||||
TP_LOG_FATAL_ID("Failed to msync() block to file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (TPIE_OS_MUNMAP((char*)place, header_.block_size) == -1) {
|
||||
TP_LOG_FATAL_ID("Failed to unmap() block of file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
register_memory_deallocation(header_.block_size);
|
||||
|
||||
in_memory_blocks_--;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_mmap<BIDT>::sync_block(BIDT bid, void* place, char dirty) {
|
||||
|
||||
if ((bid <= 0) || (bid >= header_.last_block)) {
|
||||
TP_LOG_FATAL_ID("Incorrect bid in placeholder.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (!read_only_) {
|
||||
if (TPIE_OS_MSYNC((char*)place, header_.block_size, TPIE_OS_FLAG_MS_SYNC)) {
|
||||
TP_LOG_FATAL_ID("Failed to msync() block to file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
stats_.record(BLOCK_SYNC);
|
||||
gstats_.record(BLOCK_SYNC);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#endif //_BTE_COLL_MMAP_H
|
||||
@@ -0,0 +1,299 @@
|
||||
//
|
||||
// File: bte_coll_ufs.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: bte_coll_ufs.h,v 1.12 2005/01/14 18:58:32 tavi Exp $
|
||||
//
|
||||
// BTE_collection_ufs class definition.
|
||||
//
|
||||
#ifndef _BTE_COLL_UFS_H
|
||||
#define _BTE_COLL_UFS_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
// Get the base class.
|
||||
#include <bte_coll_base.h>
|
||||
|
||||
// For header's type field (85 == 'U').
|
||||
#define BTE_COLLECTION_UFS_ID 85
|
||||
|
||||
template<class BIDT = TPIE_BLOCK_ID_TYPE>
|
||||
class BTE_collection_ufs: public BTE_collection_base<BIDT> {
|
||||
protected:
|
||||
using BTE_collection_base<BIDT>::header_;
|
||||
using BTE_collection_base<BIDT>::freeblock_stack_;
|
||||
using BTE_collection_base<BIDT>::bcc_fd_;
|
||||
using BTE_collection_base<BIDT>::per_;
|
||||
using BTE_collection_base<BIDT>::os_block_size_;
|
||||
using BTE_collection_base<BIDT>::base_file_name_;
|
||||
using BTE_collection_base<BIDT>::status_;
|
||||
using BTE_collection_base<BIDT>::read_only_;
|
||||
using BTE_collection_base<BIDT>::in_memory_blocks_;
|
||||
using BTE_collection_base<BIDT>::file_pointer;
|
||||
using BTE_collection_base<BIDT>::stats_;
|
||||
using BTE_collection_base<BIDT>::gstats_;
|
||||
using BTE_collection_base<BIDT>::register_memory_allocation;
|
||||
using BTE_collection_base<BIDT>::register_memory_deallocation;
|
||||
using BTE_collection_base<BIDT>::bid_to_file_offset;
|
||||
using BTE_collection_base<BIDT>::create_stack;
|
||||
using BTE_collection_base<BIDT>::new_block_getid;
|
||||
using BTE_collection_base<BIDT>::delete_block_shared;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors.
|
||||
BTE_collection_ufs(const char *base_file_name,
|
||||
BTE_collection_type type = BTE_WRITE_COLLECTION,
|
||||
size_t logical_block_factor = 1):
|
||||
BTE_collection_base<BIDT>(base_file_name, type, logical_block_factor) {
|
||||
header_.type = BTE_COLLECTION_UFS_ID;
|
||||
}
|
||||
|
||||
// Allocate a new block in block collection and then read that block into
|
||||
// memory, allocating and returning an appropriately initialized
|
||||
// Block. Main memory usage increases.
|
||||
BTE_err new_block(BIDT &bid, void * &place) {
|
||||
BTE_err err;
|
||||
// Get a block id.
|
||||
if ((err = new_block_getid(bid)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
// We have a bid, so we can call the get_block routine.
|
||||
if ((err = new_block_internals(bid, place)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
header_.used_blocks++;
|
||||
stats_.record(BLOCK_NEW);
|
||||
gstats_.record(BLOCK_NEW);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Delete a previously created, currently in-memory BLOCK. This causes
|
||||
// the number of free blocks in the collection to increase by 1, the bid
|
||||
// is entered into the stdio_stack. NOTE that it is the onus of the user
|
||||
// of this class to ensure that the bid of this placeholder is
|
||||
// correct. No check is made if the bid is an invalid or previously
|
||||
// unallocated bid, which will introduce erroneous entries in the
|
||||
// stdio_stack of free blocks. Main memory usage goes down.
|
||||
BTE_err delete_block(BIDT bid, void * place) {
|
||||
BTE_err err;
|
||||
if ((err = put_block_internals(bid, place, 1)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
if ((err = delete_block_shared(bid)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
header_.used_blocks--;
|
||||
stats_.record(BLOCK_DELETE);
|
||||
gstats_.record(BLOCK_DELETE);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Read the block with the indicated bid and allocate and initialize a
|
||||
// corresponding placeholder. NOTE once more that it is the user's onus
|
||||
// to ensure that the bid requested corresponds to a valid block and so
|
||||
// on; no checks made here to ensure that that is indeed the case. Main
|
||||
// memory usage increases.
|
||||
BTE_err get_block(BIDT bid, void * &place) {
|
||||
BTE_err err;
|
||||
if ((err = get_block_internals(bid, place)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
stats_.record(BLOCK_GET);
|
||||
gstats_.record(BLOCK_GET);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Write a currently in-memory block. NOTE once more that it is the
|
||||
// user's onus to ensure that the bid is correct and so on; no checks
|
||||
// made here to ensure that that is indeed the case. Main memory usage
|
||||
// decreases.
|
||||
BTE_err put_block(BIDT bid, void * place, char dirty = 1) {
|
||||
BTE_err err;
|
||||
if ((err = put_block_internals(bid, place, dirty)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
stats_.record(BLOCK_PUT);
|
||||
gstats_.record(BLOCK_PUT);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Synchronize the in-memory block with the on-disk block.
|
||||
BTE_err sync_block(BIDT bid, void* place, char dirty = 1);
|
||||
|
||||
protected:
|
||||
|
||||
BTE_err new_block_internals(BIDT bid, void *&place);
|
||||
// BTE_err new_block_getid_specific(BIDT& bid);
|
||||
BTE_err get_block_internals(BIDT bid, void *&place);
|
||||
BTE_err put_block_internals(BIDT bid, void* place, char dirty);
|
||||
};
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_ufs<BIDT>::new_block_internals(BIDT bid, void* &place) {
|
||||
if ((place = new char[header_.block_size]) == NULL) {
|
||||
TP_LOG_FATAL_ID("new() failed to alloc space for a block from file.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
in_memory_blocks_++;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_ufs<BIDT>::new_block_getid_specific(BIDT& bid) {
|
||||
BIDT *lbn;
|
||||
BTE_err err;
|
||||
if (header_.used_blocks < header_.last_block - 1) {
|
||||
|
||||
tp_assert(freeblock_stack_ != NULL,
|
||||
"BTE_collection_ufs internal error: NULL stack pointer");
|
||||
|
||||
size_t slen = freeblock_stack_->stream_len();
|
||||
tp_assert(slen > 0, "BTE_collection_ufs internal error: empty stack");
|
||||
if ((err = freeblock_stack_->pop(&lbn)) != BTE_ERROR_NO_ERROR)
|
||||
return err;
|
||||
bid = *lbn;
|
||||
|
||||
} else {
|
||||
|
||||
tp_assert(header_.last_block <= header_.total_blocks,
|
||||
"BTE_collection_ufs internal error: last_block>total_blocks");
|
||||
|
||||
if (header_.last_block == header_.total_blocks) {
|
||||
// Increase the capacity for storing blocks in the stream by
|
||||
// 16 (only by 1 the first time around to be gentle with very
|
||||
// small coll's).
|
||||
if (header_.total_blocks == 1)
|
||||
header_.total_blocks += 2;
|
||||
else if (header_.total_blocks <= 161)
|
||||
header_.total_blocks += 8;
|
||||
else
|
||||
header_.total_blocks += 64;
|
||||
#define USE_FTRUNCATE_FOR_UFS 1
|
||||
#if USE_FTRUNCATE_FOR_UFS
|
||||
if (TPIE_OS_FTRUNCATE(bcc_fd_, bid_to_file_offset(header_.total_blocks))) {
|
||||
TP_LOG_FATAL_ID("Failed to ftruncate() to the new end of file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
#else
|
||||
TPIE_OS_OFFSET curr_off;
|
||||
char* tbuf = new char[header_.os_block_size];
|
||||
if ((curr_off = TPIE_OS_LSEEK(bcc_fd_, 0, TPIE_OS_FLAG_SEEK_END)) == (TPIE_OS_OFFSET)-1) {
|
||||
TP_LOG_FATAL_ID("Failed to lseek() to the end of file.");
|
||||
TP_LOG_FATAL_ID(strerror(errno));
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
while (curr_off < bid_to_file_offset(header_.total_blocks)) {
|
||||
TPIE_OS_WRITE(bcc_fd_, tbuf, header_.os_block_size);
|
||||
curr_off += header_.os_block_size;
|
||||
}
|
||||
file_pointer = curr_off;
|
||||
delete [] tbuf;
|
||||
#endif
|
||||
}
|
||||
bid = header_.last_block++;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_ufs<BIDT>::get_block_internals(BIDT bid, void * &place) {
|
||||
|
||||
if ((place = new char[header_.block_size]) == NULL) {
|
||||
TP_LOG_FATAL_ID("new() failed to alloc space for a block from file.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
|
||||
if (file_pointer != bid_to_file_offset(bid)) {
|
||||
if (TPIE_OS_LSEEK(bcc_fd_, bid_to_file_offset(bid), TPIE_OS_FLAG_SEEK_SET) !=
|
||||
bid_to_file_offset(bid)) {
|
||||
TP_LOG_FATAL_ID("lseek failed in file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (TPIE_OS_READ(bcc_fd_, (char *) place, header_.block_size) !=
|
||||
(TPIE_OS_SSIZE_T)header_.block_size) {
|
||||
TP_LOG_FATAL_ID("Failed to read() from file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
file_pointer = bid_to_file_offset(bid) + header_.block_size;
|
||||
|
||||
in_memory_blocks_++;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_ufs<BIDT>::put_block_internals(BIDT bid, void * place, char dirty) {
|
||||
|
||||
if ((bid < 0) || (bid >= header_.last_block)) {
|
||||
TP_LOG_FATAL_ID("Incorrect bid in placeholder.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (place == NULL) {
|
||||
TP_LOG_FATAL_ID("Null block ptr field in placeholder.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
// if (place->dirty)
|
||||
|
||||
if (!read_only_) {
|
||||
|
||||
if (file_pointer != bid_to_file_offset(bid)) {
|
||||
if (TPIE_OS_LSEEK(bcc_fd_, bid_to_file_offset(bid), TPIE_OS_FLAG_SEEK_SET)
|
||||
!= bid_to_file_offset(bid)) {
|
||||
TP_LOG_FATAL_ID("Failed to lseek() in file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (TPIE_OS_WRITE(bcc_fd_, place, header_.block_size) != (TPIE_OS_SSIZE_T)header_.block_size) {
|
||||
TP_LOG_FATAL_ID("Failed to write() block to file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
file_pointer = bid_to_file_offset(bid) + header_.block_size;
|
||||
}
|
||||
|
||||
delete [] (char *) place;
|
||||
|
||||
in_memory_blocks_--;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class BIDT>
|
||||
BTE_err BTE_collection_ufs<BIDT>::sync_block(BIDT bid, void* place, char dirty) {
|
||||
|
||||
if ((bid < 0) || (bid >= header_.last_block)) {
|
||||
TP_LOG_FATAL_ID("Incorrect bid in placeholder.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (place == NULL) {
|
||||
TP_LOG_FATAL_ID("Null block pointer.");
|
||||
return BTE_ERROR_INVALID_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (!read_only_) {
|
||||
|
||||
if (TPIE_OS_LSEEK(bcc_fd_, bid_to_file_offset(bid), TPIE_OS_FLAG_SEEK_SET)
|
||||
!= bid_to_file_offset(bid)) {
|
||||
TP_LOG_FATAL_ID("Failed to lseek() in file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
if (TPIE_OS_WRITE(bcc_fd_, place, header_.block_size) != (TPIE_OS_SSIZE_T)header_.block_size) {
|
||||
TP_LOG_FATAL_ID("Failed to write() block to file.");
|
||||
return BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
|
||||
file_pointer = bid_to_file_offset(bid) + header_.block_size;
|
||||
}
|
||||
|
||||
stats_.record(BLOCK_SYNC);
|
||||
gstats_.record(BLOCK_SYNC);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#endif // _BTE_COLL_UFS_H
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// File: bte_err.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// (from Darren's bte_base_stream.h)
|
||||
// Created: 12/29/01
|
||||
// $Id: bte_err.h,v 1.2 2003/04/17 14:56:26 jan Exp $
|
||||
//
|
||||
// BTE error codes, moved here from bte_base_stream.h
|
||||
//
|
||||
|
||||
#ifndef _BTE_ERR_H
|
||||
#define _BTE_ERR_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
//
|
||||
// BTE error codes are returned using the BTE_err type.
|
||||
//
|
||||
enum BTE_err {
|
||||
BTE_ERROR_NO_ERROR = 0,
|
||||
BTE_ERROR_IO_ERROR,
|
||||
BTE_ERROR_END_OF_STREAM,
|
||||
BTE_ERROR_READ_ONLY,
|
||||
BTE_ERROR_OS_ERROR,
|
||||
BTE_ERROR_BASE_METHOD,
|
||||
BTE_ERROR_MEMORY_ERROR,
|
||||
BTE_ERROR_PERMISSION_DENIED,
|
||||
BTE_ERROR_OFFSET_OUT_OF_RANGE,
|
||||
BTE_ERROR_OUT_OF_SPACE,
|
||||
BTE_ERROR_STREAM_IS_SUBSTREAM,
|
||||
BTE_ERROR_WRITE_ONLY,
|
||||
BTE_ERROR_BAD_HEADER,
|
||||
BTE_ERROR_INVALID_PLACEHOLDER
|
||||
};
|
||||
|
||||
#endif // _BTE_ERR_H
|
||||
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// File: bte_stack_ufs.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// Created: 09/15/03
|
||||
//
|
||||
// A stack implemented using BTE_stream_ufs. It is used by
|
||||
// BTE_collection_base to implement deletions.
|
||||
//
|
||||
// $Id: bte_stack_ufs.h,v 1.2 2005/01/14 18:47:22 tavi Exp $
|
||||
//
|
||||
|
||||
#ifndef _BTE_STACK_UFS_H
|
||||
#define _BTE_STACK_UFS_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <bte_stream_ufs.h>
|
||||
|
||||
template<class T>
|
||||
class BTE_stack_ufs : public BTE_stream_ufs<T> {
|
||||
public:
|
||||
using BTE_stream_ufs<T>::stream_len;
|
||||
using BTE_stream_ufs<T>::seek;
|
||||
using BTE_stream_ufs<T>::truncate;
|
||||
|
||||
// Construct a new stack with the given name and access type.
|
||||
BTE_stack_ufs(char *path, BTE_stream_type type = BTE_WRITE_STREAM);
|
||||
// Destroy this object.
|
||||
~BTE_stack_ufs(void);
|
||||
// Push an element on top of the stack.
|
||||
BTE_err push(const T &t);
|
||||
// Pop an element from the top of the stack.
|
||||
BTE_err pop(T **t);
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_stack_ufs<T>::BTE_stack_ufs(char *path,
|
||||
BTE_stream_type type) :
|
||||
BTE_stream_ufs<T>(path, type, 1)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BTE_stack_ufs<T>::~BTE_stack_ufs(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stack_ufs<T>::push(const T &t)
|
||||
{
|
||||
BTE_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
ae = truncate((slen = stream_len())+1);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = seek(slen);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return write_item(t);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stack_ufs<T>::pop(T **t)
|
||||
{
|
||||
BTE_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
slen = stream_len();
|
||||
ae = seek(slen-1);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = read_item(t);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return truncate(slen-1);
|
||||
}
|
||||
|
||||
#endif // _BTE_STACK_UFS_H
|
||||
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// File: bte_stream.h (formerly bte.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/9/94
|
||||
//
|
||||
// $Id: bte_stream.h,v 1.3 2003/04/17 14:59:16 jan Exp $
|
||||
//
|
||||
#ifndef _BTE_STREAM_H
|
||||
#define _BTE_STREAM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#ifndef BTE_VIRTUAL_BASE
|
||||
# define BTE_VIRTUAL_BASE 0
|
||||
#endif
|
||||
|
||||
// Get the base class, enums, etc...
|
||||
#include <bte_stream_base.h>
|
||||
|
||||
#ifdef BTE_IMP_UFS
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_USE_BTE_STREAM_IMP_UFS
|
||||
# define BTE_STREAM_IMP_UFS
|
||||
#endif
|
||||
|
||||
#ifdef BTE_IMP_MMB
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_USE_BTE_STREAM_IMP_MMAP
|
||||
# define BTE_STREAM_IMP_MMAP
|
||||
#endif
|
||||
|
||||
#ifdef BTE_IMP_STDIO
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_USE_BTE_STREAM_IMP_STDIO
|
||||
# define BTE_STREAM_IMP_STDIO
|
||||
#endif
|
||||
|
||||
#ifdef BTE_IMP_USER_DEFINED
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_USE_BTE_STREAM_IMP_USER_DEFINED
|
||||
# define BTE_STREAM_IMP_USER_DEFINED
|
||||
#endif
|
||||
|
||||
// The number of implementations to be defined.
|
||||
#define _BTE_STREAM_IMP_COUNT (defined(BTE_STREAM_IMP_USER_DEFINED) + \
|
||||
defined(BTE_STREAM_IMP_STDIO) + \
|
||||
defined(BTE_STREAM_IMP_MMAP) + \
|
||||
defined(BTE_STREAM_IMP_UFS) )
|
||||
|
||||
// Multiple implementations are allowed to coexist, with some
|
||||
// restrictions.
|
||||
|
||||
// If the including module did not explicitly ask for multiple
|
||||
// implementations but requested more than one implementation, issue a
|
||||
// warning.
|
||||
#ifndef BTE_STREAM_IMP_MULTI_IMP
|
||||
# if (_BTE_STREAM_IMP_COUNT > 1)
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_MULTIPLE_BTE_STREAM_IMP_DEFINED
|
||||
# define BTE_STREAM_IMP_MULTI_IMP
|
||||
# endif // (_BTE_STREAM_IMP_COUNT > 1)
|
||||
#endif // BTE_STREAM_IMP_MULTI_IMP
|
||||
|
||||
// Make sure at least one implementation was chosen. If none was, then
|
||||
// choose one by default, but warn the user.
|
||||
#if (_BTE_STREAM_IMP_COUNT < 1)
|
||||
// TPIE_OS_UNIX_ONLY_WARNING_NO_IMPLEMENTATION_USING_BTE_STREAM_IMP_UFS
|
||||
# define BTE_STREAM_IMP_STDIO
|
||||
#endif // (_BTE_STREAM_IMP_COUNT < 1)
|
||||
|
||||
// Now include the definitions of each implementation
|
||||
// that will be used.
|
||||
|
||||
#ifdef BTE_STREAM_IMP_MULTI_IMP
|
||||
// If we have multiple implem., set BTE_STREAM to be the base class.
|
||||
# define BTE_STREAM BTE_stream_base
|
||||
#endif
|
||||
|
||||
// User defined implementation.
|
||||
#if defined(BTE_STREAM_IMP_USER_DEFINED)
|
||||
// Do nothing. The user will provide a definition of BTE_STREAM.
|
||||
#endif
|
||||
|
||||
// stdio implementation.
|
||||
#if defined(BTE_STREAM_IMP_STDIO)
|
||||
# include <bte_stream_stdio.h>
|
||||
// If this is the only implementation, then make it easier to get to.
|
||||
# ifndef BTE_STREAM_IMP_MULTI_IMP
|
||||
#ifdef BTE_STREAM
|
||||
#undef BTE_STREAM
|
||||
#endif
|
||||
# define BTE_STREAM BTE_stream_stdio
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// mmap implementation.
|
||||
#if defined(BTE_STREAM_IMP_MMAP)
|
||||
# include <bte_stream_mmap.h>
|
||||
// If this is the only implementation, then make it easier to get to.
|
||||
# ifndef BTE_STREAM_IMP_MULTI_IMP
|
||||
#ifdef BTE_STREAM
|
||||
#undef BTE_STREAM
|
||||
#endif
|
||||
# define BTE_STREAM BTE_stream_mmap
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// ufs implementation.
|
||||
#if defined(BTE_STREAM_IMP_UFS)
|
||||
# include <bte_stream_ufs.h>
|
||||
// If this is the only implementation, then make it easier to get to.
|
||||
# ifndef BTE_STREAM_IMP_MULTI_IMP
|
||||
#ifdef BTE_STREAM
|
||||
#undef BTE_STREAM
|
||||
#endif
|
||||
# define BTE_STREAM BTE_stream_ufs
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _BTE_STREAM_H
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// File: bte_stream_base.cpp
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// (using some code by Darren Erik Vengroff)
|
||||
// Created: 01/08/02
|
||||
//
|
||||
|
||||
#include "lib_config.h"
|
||||
#include <versions.h>
|
||||
VERSION(bte_stream_base_cpp,"$Id: bte_stream_base.cpp,v 1.3 2003/04/23 07:32:15 tavi Exp $");
|
||||
|
||||
#include <bte_stream_base.h>
|
||||
|
||||
static unsigned long get_remaining_streams() {
|
||||
TPIE_OS_SET_LIMITS_BODY;
|
||||
}
|
||||
|
||||
tpie_stats_stream BTE_stream_base_generic::gstats_;
|
||||
|
||||
int BTE_stream_base_generic::remaining_streams = get_remaining_streams();
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// File: bte_stream_base.h (formerly bte_base_stream.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/11/94
|
||||
//
|
||||
// $Id: bte_stream_base.h,v 1.9 2005/01/26 20:12:53 tavi Exp $
|
||||
//
|
||||
#ifndef _BTE_STREAM_BASE_H
|
||||
#define _BTE_STREAM_BASE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <persist.h>
|
||||
// Get the BTE error codes.
|
||||
#include <bte_err.h>
|
||||
// Get statistics definitions.
|
||||
#include <tpie_stats_stream.h>
|
||||
|
||||
// Include the registration based memory manager.
|
||||
#define MM_IMP_REGISTER
|
||||
#include <mm.h>
|
||||
|
||||
// Inline commonly called functions.
|
||||
//#define B_INLINE
|
||||
#define B_INLINE inline
|
||||
|
||||
// Max length of a stream file name.
|
||||
#define BTE_STREAM_PATH_NAME_LEN 128
|
||||
|
||||
// The magic number of the file storing the stream.
|
||||
// (in network byteorder, it spells "TPST": TPie STream)
|
||||
#define BTE_STREAM_HEADER_MAGIC_NUMBER 0x54505354
|
||||
|
||||
// BTE stream types passed to constructors.
|
||||
enum BTE_stream_type {
|
||||
BTE_READ_STREAM = 1, // Open existing stream for reading.
|
||||
BTE_WRITE_STREAM, // Open for read/writing. Create if non-existent.
|
||||
BTE_APPEND_STREAM, // Open for writing at end. Create if needed.
|
||||
BTE_WRITEONLY_STREAM // Open only for writing (allows mmb optimization)
|
||||
// (must be sequential write through whole file)
|
||||
};
|
||||
|
||||
// BTE stream status.
|
||||
enum BTE_stream_status {
|
||||
BTE_STREAM_STATUS_NO_STATUS = 0,
|
||||
BTE_STREAM_STATUS_INVALID = 1,
|
||||
BTE_STREAM_STATUS_EOS_ON_NEXT_CALL,
|
||||
BTE_STREAM_STATUS_END_OF_STREAM
|
||||
};
|
||||
|
||||
// BTE stream header info.
|
||||
class BTE_stream_header {
|
||||
public:
|
||||
|
||||
// Unique header identifier. Set to BTE_STREAM_HEADER_MAGIC_NUMBER.
|
||||
unsigned int magic_number;
|
||||
// Should be 2 for current version (version 1 has been deprecated).
|
||||
unsigned int version;
|
||||
// The type of BTE_STREAM that created this header. Not all types of
|
||||
// BTE's are readable by all BTE implementations. For example,
|
||||
// BTE_STREAM_STDIO streams are not readable by either
|
||||
// BTE_STREAM_UFS or BTE_STREAM_MMAP implementations. The value 0 is
|
||||
// reserved for the base class. Use numbers bigger than 0 for the
|
||||
// various implementations.
|
||||
unsigned int type;
|
||||
// The number of bytes in this structure.
|
||||
TPIE_OS_SIZE_T header_length;
|
||||
// The size of each item in the stream.
|
||||
TPIE_OS_SIZE_T item_size;
|
||||
// The size of a physical block on the device this stream resides.
|
||||
TPIE_OS_SIZE_T os_block_size;
|
||||
// Size in bytes of each logical block, if applicable.
|
||||
TPIE_OS_SIZE_T block_size;
|
||||
// For all intents and purposes, the length of the stream in number
|
||||
// of items.
|
||||
TPIE_OS_OFFSET item_logical_eof;
|
||||
};
|
||||
|
||||
// A base class for the base class :). The role of this class is to
|
||||
// provide global variables, accessible by all streams, regardless of
|
||||
// template.
|
||||
class BTE_stream_base_generic {
|
||||
protected:
|
||||
static tpie_stats_stream gstats_;
|
||||
static int remaining_streams;
|
||||
public:
|
||||
// The number of globally available streams.
|
||||
static int available_streams() { return remaining_streams; }
|
||||
// The global stats.
|
||||
static const tpie_stats_stream& gstats() { return gstats_; }
|
||||
};
|
||||
|
||||
// An abstract class template which implements a single stream of objects
|
||||
// of type T within the BTE. This is the superclass of all actual
|
||||
// implementations of streams of T within the BTE (e.g. mmap() streams,
|
||||
// UN*X file system streams, and kernel streams).
|
||||
template<class T> class BTE_stream_base: public BTE_stream_base_generic {
|
||||
protected:
|
||||
using BTE_stream_base_generic::remaining_streams;
|
||||
using BTE_stream_base_generic::gstats_;
|
||||
|
||||
// The persistence status of this stream.
|
||||
persistence per;
|
||||
// The status (integrity) of this stream.
|
||||
BTE_stream_status status_;
|
||||
// How deeply is this stream nested.
|
||||
unsigned int substream_level;
|
||||
// Non-zero if this stream was opened for reading only.
|
||||
int r_only;
|
||||
// Statistics for this stream only.
|
||||
tpie_stats_stream stats_;
|
||||
|
||||
// Check the given header for reasonable values.
|
||||
int check_header(BTE_stream_header* ph);
|
||||
|
||||
// Initialize the header with as much information as is known here.
|
||||
void init_header(BTE_stream_header* ph);
|
||||
|
||||
inline BTE_err register_memory_allocation (TPIE_OS_SIZE_T sz);
|
||||
inline BTE_err register_memory_deallocation (TPIE_OS_SIZE_T sz);
|
||||
|
||||
public:
|
||||
BTE_stream_base() {};
|
||||
|
||||
// Tell the stream whether to leave its data on the disk or not
|
||||
// when it is destructed.
|
||||
void persist (persistence p) { per = p; }
|
||||
// Inquire the persistence status of this BTE stream.
|
||||
persistence persist() const { return per; }
|
||||
// Return true if a read-only stream.
|
||||
bool read_only () const { return (r_only != 0); }
|
||||
// Inquire the status.
|
||||
BTE_stream_status status() const { return status_; }
|
||||
|
||||
// Inquire the OS block size.
|
||||
TPIE_OS_SIZE_T os_block_size () const;
|
||||
|
||||
const tpie_stats_stream& stats() const { return stats_; }
|
||||
|
||||
#if BTE_VIRTUAL_BASE
|
||||
|
||||
// A virtual psuedo-constructor for substreams.
|
||||
virtual BTE_err new_substream(BTE_stream_type st,
|
||||
TPIE_OS_OFFSET sub_begin, TPIE_OS_OFFSET sub_end,
|
||||
BTE_stream_base<T> **sub_stream) = 0;
|
||||
|
||||
virtual B_INLINE BTE_err read_item(T **elt) = 0;
|
||||
|
||||
virtual B_INLINE BTE_err write_item(const T &elt) = 0;
|
||||
|
||||
// Query memory usage
|
||||
virtual BTE_err main_memory_usage(TPIE_OS_SIZE_T *usage,
|
||||
MM_stream_usage usage_type) = 0;
|
||||
|
||||
virtual TPIE_OS_OFFSET stream_len(void) = 0;
|
||||
|
||||
virtual BTE_err name(char **stream_name) = 0;
|
||||
|
||||
virtual BTE_err seek(TPIE_OS_OFFSET offset) = 0;
|
||||
|
||||
virtual BTE_err truncate(TPIE_OS_OFFSET offset) = 0;
|
||||
|
||||
virtual ~BTE_stream_base(void) {};
|
||||
|
||||
virtual int available_streams(void) = 0;
|
||||
|
||||
virtual TPIE_OS_OFFSET chunk_size(void) = 0;
|
||||
|
||||
#endif // BTE_VIRTUAL_BASE
|
||||
};
|
||||
|
||||
template<class T>
|
||||
int BTE_stream_base<T>::check_header(BTE_stream_header* ph) {
|
||||
|
||||
if (ph == NULL) {
|
||||
TP_LOG_FATAL_ID ("Could not map header.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->magic_number != BTE_STREAM_HEADER_MAGIC_NUMBER) {
|
||||
TP_LOG_FATAL_ID ("header: magic number mismatch (expected/obtained):");
|
||||
TP_LOG_FATAL_ID (BTE_STREAM_HEADER_MAGIC_NUMBER);
|
||||
TP_LOG_FATAL_ID (ph->magic_number);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->header_length != sizeof (*ph)) {
|
||||
TP_LOG_FATAL_ID ("header: incorrect header length; (expected/obtained):");
|
||||
TP_LOG_FATAL_ID (sizeof (BTE_stream_header));
|
||||
TP_LOG_FATAL_ID (ph->header_length);
|
||||
TP_LOG_FATAL_ID ("This could be due to a stream written without 64-bit support.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->version != 2) {
|
||||
TP_LOG_FATAL_ID ("header: incorrect version (expected/obtained):");
|
||||
TP_LOG_FATAL_ID (2);
|
||||
TP_LOG_FATAL_ID (ph->version);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->type == 0) {
|
||||
TP_LOG_FATAL_ID ("header: type is 0 (reserved for base class).");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->item_size != sizeof (T)) {
|
||||
TP_LOG_FATAL_ID ("header: incorrect item size (expected/obtained):");
|
||||
TP_LOG_FATAL_ID (sizeof(T));
|
||||
TP_LOG_FATAL_ID ((TPIE_OS_LONGLONG)ph->item_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ph->os_block_size != os_block_size()) {
|
||||
TP_LOG_FATAL_ID ("header: incorrect OS block size (expected/obtained):");
|
||||
TP_LOG_FATAL_ID ((TPIE_OS_LONGLONG)os_block_size());
|
||||
TP_LOG_FATAL_ID ((TPIE_OS_LONGLONG)ph->os_block_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void BTE_stream_base<T>::init_header (BTE_stream_header* ph) {
|
||||
tp_assert(ph != NULL, "NULL header pointer");
|
||||
ph->magic_number = BTE_STREAM_HEADER_MAGIC_NUMBER;
|
||||
ph->version = 2;
|
||||
ph->type = 0; // Not known here.
|
||||
ph->header_length = sizeof(*ph);
|
||||
ph->item_size = sizeof(T);
|
||||
ph->os_block_size = os_block_size();
|
||||
ph->block_size = 0; // Not known here.
|
||||
ph->item_logical_eof = 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_base<T>::register_memory_allocation (TPIE_OS_SIZE_T sz) {
|
||||
|
||||
if (MM_manager.register_allocation(sz) != MM_ERROR_NO_ERROR) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Memory manager error in allocation.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_base<T>::register_memory_deallocation (TPIE_OS_SIZE_T sz) {
|
||||
|
||||
if (MM_manager.register_deallocation (sz) != MM_ERROR_NO_ERROR) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Memory manager error in deallocation.");
|
||||
return BTE_ERROR_MEMORY_ERROR;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_SIZE_T BTE_stream_base<T>::os_block_size () const {
|
||||
return TPIE_OS_BLOCKSIZE();
|
||||
}
|
||||
|
||||
#endif // _BTE_STREAM_BASE_H
|
||||
@@ -0,0 +1,233 @@
|
||||
//
|
||||
// File: bte_stream_cache.h (formerly bte_cache.h)
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 9/19/94
|
||||
//
|
||||
// $Id: bte_stream_cache.h,v 1.4 2004/08/12 12:35:31 jan Exp $
|
||||
//
|
||||
// BTE streams for main memory caches.
|
||||
//
|
||||
#ifndef _BTE_STREAM_CACHE_H
|
||||
#define _BTE_STREAM_CACHE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Include the registration based memory manager.
|
||||
#define MM_IMP_REGISTER
|
||||
#include <mm.h>
|
||||
|
||||
#include <bte_stream_base.h>
|
||||
|
||||
// This code makes assertions and logs errors.
|
||||
#include <tpie_assert.h>
|
||||
#include <tpie_log.h>
|
||||
|
||||
|
||||
#define BTE_STREAM_CACHE_DEFAULT_MAX_LEN (1024 * 256)
|
||||
|
||||
#ifndef BTE_STREAM_CACHE_LINE_SIZE
|
||||
#define BTE_STREAM_CACHE_LINE_SIZE 64
|
||||
#endif // BTE_STREAM_CACHE_LINE_SIZE
|
||||
|
||||
//
|
||||
// The cache stream class.
|
||||
//
|
||||
|
||||
template <class T>
|
||||
class BTE_stream_cache : public BTE_stream_base<T> {
|
||||
private:
|
||||
T *data;
|
||||
T *current;
|
||||
T *data_max;
|
||||
T *data_hard_end;
|
||||
unsigned int substream_level;
|
||||
unsigned int valid;
|
||||
unsigned int r_only;
|
||||
|
||||
BTE_stream_cache(void);
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
BTE_stream_cache(const char *path, BTE_stream_type st, TPIE_OS_OFFSET max_len);
|
||||
|
||||
// A psuedo-constructor for substreams.
|
||||
BTE_err new_substream(BTE_stream_type st, TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end, BTE_stream_base<T> **sub_stream);
|
||||
|
||||
|
||||
// Query memory usage
|
||||
BTE_err main_memory_usage(size_t *usage,
|
||||
MM_stream_usage usage_type);
|
||||
|
||||
// Return the number of items in the stream.
|
||||
TPIE_OS_OFFSET stream_len(void);
|
||||
|
||||
// Move to a specific position in the stream.
|
||||
BTE_err seek(TPIE_OS_OFFSET offset);
|
||||
|
||||
// Destructor
|
||||
~BTE_stream_cache(void);
|
||||
|
||||
BTE_err read_item(T **elt);
|
||||
BTE_err write_item(const T &elt);
|
||||
int read_only(void) { return r_only; };
|
||||
|
||||
int available_streams(void) { return -1; };
|
||||
|
||||
TPIE_OS_OFFSET chunk_size(void);
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_stream_cache<T>::BTE_stream_cache(void)
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
BTE_stream_cache<T>::BTE_stream_cache(const char *path, BTE_stream_type st,
|
||||
TPIE_OS_OFFSET max_len) {
|
||||
|
||||
// A stream being created out of the blue must be writable, so we
|
||||
// return an error if it is not.
|
||||
|
||||
switch (st) {
|
||||
case BTE_READ_STREAM:
|
||||
case BTE_APPEND_STREAM:
|
||||
valid = 0;
|
||||
break;
|
||||
case BTE_WRITE_STREAM:
|
||||
r_only = 0;
|
||||
if (!max_len) {
|
||||
max_len = BTE_STREAM_CACHE_DEFAULT_MAX_LEN;
|
||||
}
|
||||
// Use malloc() directly rather than new becasue this is
|
||||
// in "secondary memory" and will not necessarily go into
|
||||
// the cache.
|
||||
data = (T*)malloc(max_len*sizeof(T));
|
||||
if (data == NULL) {
|
||||
valid = 0;
|
||||
TP_LOG_FATAL_ID("Out of \"secondary memory.\"");
|
||||
return;
|
||||
}
|
||||
current = data_max = data;
|
||||
data_hard_end = data + max_len;
|
||||
valid = 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_cache<T>::new_substream(BTE_stream_type st, TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
BTE_stream_base<T> **sub_stream)
|
||||
{
|
||||
BTE_stream_cache *ss;
|
||||
|
||||
if (st == BTE_APPEND_STREAM) {
|
||||
return BTE_ERROR_PERMISSION_DENIED;
|
||||
} else {
|
||||
if ((sub_begin >= data_hard_end - data) ||
|
||||
(sub_end >= data_hard_end - data) ||
|
||||
(sub_begin >= data_max - data) ||
|
||||
(sub_end >= data_max - data) ||
|
||||
(sub_end < sub_begin)) {
|
||||
return BTE_ERROR_OFFSET_OUT_OF_RANGE;
|
||||
}
|
||||
ss = new BTE_stream_cache;
|
||||
ss->r_only = (st == BTE_READ_STREAM);
|
||||
ss->substream_level = substream_level + 1;
|
||||
ss->current = ss->data = data + sub_begin;
|
||||
ss->data_max = ss->data_hard_end = data + sub_end + 1;
|
||||
*sub_stream = (BTE_stream_base<T> *)ss;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_cache<T>::main_memory_usage(size_t *usage,
|
||||
MM_stream_usage usage_type)
|
||||
{
|
||||
switch (usage_type) {
|
||||
case MM_STREAM_USAGE_CURRENT:
|
||||
case MM_STREAM_USAGE_MAXIMUM:
|
||||
case MM_STREAM_USAGE_SUBSTREAM:
|
||||
*usage = sizeof(*this) + BTE_STREAM_CACHE_LINE_SIZE;
|
||||
break;
|
||||
case MM_STREAM_USAGE_BUFFER:
|
||||
*usage = BTE_STREAM_CACHE_LINE_SIZE;
|
||||
break;
|
||||
case MM_STREAM_USAGE_OVERHEAD:
|
||||
*usage = sizeof(this);
|
||||
break;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET BTE_stream_cache<T>::stream_len(void)
|
||||
{
|
||||
return data_max - data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_cache<T>::seek(TPIE_OS_OFFSET offset)
|
||||
{
|
||||
if (offset > data_hard_end - data) {
|
||||
return BTE_ERROR_OFFSET_OUT_OF_RANGE;
|
||||
} else {
|
||||
current = data + offset;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_stream_cache<T>::~BTE_stream_cache(void)
|
||||
{
|
||||
if (!substream_level) {
|
||||
delete data;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_cache<T>::read_item(T **elt)
|
||||
{
|
||||
if (current >= data_max) {
|
||||
return BTE_ERROR_END_OF_STREAM;
|
||||
} else {
|
||||
*elt = current++;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
BTE_err BTE_stream_cache<T>::write_item(const T &elt)
|
||||
{
|
||||
if (r_only) {
|
||||
return BTE_ERROR_PERMISSION_DENIED;
|
||||
}
|
||||
if (current >= data_hard_end) {
|
||||
return BTE_ERROR_OUT_OF_SPACE;
|
||||
} else {
|
||||
*current++ = elt;
|
||||
if (current > data_max) {
|
||||
data_max = current;
|
||||
}
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET BTE_stream_cache<T>::chunk_size(void)
|
||||
{
|
||||
return BTE_STREAM_CACHE_LINE_SIZE / sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
#endif // _BTE_STREAM_CACHE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,635 @@
|
||||
//
|
||||
// File: bte_stream_stdio.h (formerly bte_stdio.h)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/11/94
|
||||
//
|
||||
// $Id: bte_stream_stdio.h,v 1.14 2005/07/07 20:36:12 adanner Exp $
|
||||
//
|
||||
#ifndef _BTE_STREAM_STDIO_H
|
||||
#define _BTE_STREAM_STDIO_H
|
||||
|
||||
// For header's type field (83 == 'S').
|
||||
#define BTE_STREAM_STDIO 83
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <tpie_log.h>
|
||||
#include <tpie_assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <bte_stream_base.h>
|
||||
|
||||
// File system streams are streams in a special format that is designed
|
||||
// to be stored in an ordinary file in a UN*X file system. They are
|
||||
// predominatly designed to be used to store streams in a persistent way.
|
||||
// They may disappear in later versions as persistence becomes an integral
|
||||
// part of TPIE.
|
||||
//
|
||||
// For simplicity, we work through the standard C I/O library (stdio).
|
||||
//
|
||||
|
||||
|
||||
// A class of BTE streams implemented using ordinary stdio
|
||||
// semantics.
|
||||
template < class T >
|
||||
class BTE_stream_stdio: public BTE_stream_base < T > {
|
||||
private:
|
||||
|
||||
FILE * file;
|
||||
BTE_stream_header header;
|
||||
|
||||
size_t os_block_size_;
|
||||
|
||||
int os_errno; // A place to cache OS error values. It is normally
|
||||
// set after each call to the OS.
|
||||
|
||||
char path[BTE_STREAM_PATH_NAME_LEN];
|
||||
|
||||
// If this stream is actually a substream, these will be set to
|
||||
// indicate the portion of the file that is part of this stream.
|
||||
// If the stream is the whole file, they will be set to -1.
|
||||
TPIE_OS_OFFSET logical_bos;
|
||||
TPIE_OS_OFFSET logical_eos;
|
||||
|
||||
// Offset of the current item in the file.
|
||||
TPIE_OS_OFFSET f_offset;
|
||||
|
||||
// Offset past the last item in the file.
|
||||
TPIE_OS_OFFSET f_eof;
|
||||
|
||||
// Read and check the header; used by constructors
|
||||
int readcheck_header ();
|
||||
|
||||
inline TPIE_OS_OFFSET file_off_to_item_off (TPIE_OS_OFFSET file_off) const;
|
||||
inline TPIE_OS_OFFSET item_off_to_file_off (TPIE_OS_OFFSET item_off) const;
|
||||
|
||||
protected:
|
||||
using BTE_stream_base<T>::remaining_streams;
|
||||
using BTE_stream_base<T>::gstats_;
|
||||
using BTE_stream_base<T>::status_;
|
||||
using BTE_stream_base<T>::stats_;
|
||||
using BTE_stream_base<T>::substream_level;
|
||||
using BTE_stream_base<T>::per;
|
||||
using BTE_stream_base<T>::r_only;
|
||||
|
||||
public:
|
||||
using BTE_stream_base<T>::os_block_size;
|
||||
using BTE_stream_base<T>::check_header;
|
||||
using BTE_stream_base<T>::init_header;
|
||||
using BTE_stream_base<T>::register_memory_allocation;
|
||||
using BTE_stream_base<T>::register_memory_deallocation;
|
||||
|
||||
T read_tmp;
|
||||
|
||||
// Constructors
|
||||
BTE_stream_stdio (const char *dev_path, const BTE_stream_type st,
|
||||
size_t lbf = 1);
|
||||
|
||||
// A psuedo-constructor for substreams.
|
||||
BTE_err new_substream (BTE_stream_type st, TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
BTE_stream_base < T > **sub_stream);
|
||||
|
||||
~BTE_stream_stdio (void);
|
||||
|
||||
BTE_err read_item (T ** elt);
|
||||
BTE_err write_item (const T & elt);
|
||||
|
||||
// Query memory usage
|
||||
BTE_err main_memory_usage (size_t * usage, MM_stream_usage usage_type);
|
||||
|
||||
// Return the number of items in the stream.
|
||||
TPIE_OS_OFFSET stream_len (void) const;
|
||||
|
||||
// Return the path name in newly allocated space.
|
||||
BTE_err name (char **stream_name);
|
||||
|
||||
// Move to a specific position in the stream.
|
||||
BTE_err seek (TPIE_OS_OFFSET offset);
|
||||
|
||||
// Return the current position in the stream.
|
||||
TPIE_OS_OFFSET tell () const;
|
||||
|
||||
// Truncate the stream.
|
||||
BTE_err truncate (TPIE_OS_OFFSET offset);
|
||||
|
||||
TPIE_OS_OFFSET chunk_size (void) const;
|
||||
};
|
||||
|
||||
template < class T >
|
||||
BTE_stream_stdio < T >::BTE_stream_stdio (const char *dev_path,
|
||||
const BTE_stream_type st,
|
||||
size_t lbf) {
|
||||
BTE_err berr;
|
||||
|
||||
// Reduce the number of streams avaialble.
|
||||
if (remaining_streams <= 0) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the path name
|
||||
if (strlen (dev_path) > BTE_STREAM_PATH_NAME_LEN - 1) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Path name too long:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
strncpy (path, dev_path, BTE_STREAM_PATH_NAME_LEN);
|
||||
status_ = BTE_STREAM_STATUS_NO_STATUS;
|
||||
|
||||
os_block_size_ = os_block_size ();
|
||||
|
||||
// Not a substream.
|
||||
substream_level = 0;
|
||||
|
||||
logical_bos = logical_eos = -1;
|
||||
|
||||
// By default, all streams are deleted at destruction time. (the
|
||||
// comment above is misleading. the AMI level stream is controlling
|
||||
// the persistency of this stream)
|
||||
per = PERSIST_DELETE;
|
||||
|
||||
remaining_streams--;
|
||||
|
||||
switch (st) {
|
||||
case BTE_READ_STREAM:
|
||||
// Open the file for reading.
|
||||
r_only = 1;
|
||||
if ((file = TPIE_OS_FOPEN(dev_path, "rb")) == NULL) {
|
||||
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Failed to open file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
// Read and check header
|
||||
if (readcheck_header () == -1) {
|
||||
TP_LOG_FATAL_ID("Bad header.");
|
||||
return;
|
||||
}
|
||||
// Seek past the end of the first block.
|
||||
//if (TPIE_OS_FSEEK (file, os_block_size_, 0) == -1) {
|
||||
//status_ = BTE_STREAM_STATUS_INVALID;
|
||||
//LOG_FATAL_ID("fseek failed.");
|
||||
//return;
|
||||
//}
|
||||
if ((berr = this->seek (0)) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("Cannot seek in file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTE_WRITE_STREAM:
|
||||
case BTE_WRITEONLY_STREAM:
|
||||
case BTE_APPEND_STREAM:
|
||||
// Open the file for appending.
|
||||
r_only = 0;
|
||||
if ((file = TPIE_OS_FOPEN(dev_path, "rb+")) == NULL) {
|
||||
//file does not exist - create it
|
||||
if ((file = TPIE_OS_FOPEN (dev_path, "wb+")) == NULL) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Failed to open file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
// Create and write the header
|
||||
init_header(&header);
|
||||
header.type = BTE_STREAM_STDIO;
|
||||
|
||||
if (TPIE_OS_FWRITE ((char *) &header, sizeof (header), 1, file) != 1) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Failed to write header to file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
|
||||
// Truncate the file to header block
|
||||
if ((berr = this->truncate (0)) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("Cannot truncate in file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
if ((berr = this->seek (0)) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("Cannot seek in file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
|
||||
gstats_.record(STREAM_CREATE);
|
||||
stats_.record(STREAM_CREATE);
|
||||
|
||||
} else {
|
||||
// File exists - read and check header
|
||||
if (readcheck_header () == -1) {
|
||||
TP_LOG_FATAL_ID("Bad header in file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
// Seek to the end of the stream if BTE_APPEND_STREAM
|
||||
if (st == BTE_APPEND_STREAM) {
|
||||
if (TPIE_OS_FSEEK (file, 0, TPIE_OS_FLAG_SEEK_END)) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Failed to go to EOF of file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
// Make sure there was at least a full block there to pass.
|
||||
if (TPIE_OS_FTELL (file) < (long)os_block_size_) {
|
||||
TP_LOG_FATAL_ID("File too short:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
}
|
||||
} else {
|
||||
// seek to 0 if BTE_WRITE_STREAM
|
||||
if ((berr = this->seek (0)) != BTE_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID("Cannot seek in file:");
|
||||
TP_LOG_FATAL_ID(dev_path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Either a bad value or a case that has not been implemented
|
||||
// yet.
|
||||
TP_LOG_WARNING_ID("Bad or unimplemented case.");
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
f_eof = item_off_to_file_off(header.item_logical_eof);
|
||||
|
||||
// Register memory usage before returning.
|
||||
// A quick and dirty guess. One block in the buffer cache, one in
|
||||
// user space. This is not accounted for by a "new" call, so we have to
|
||||
// register it ourselves. TODO: is 2*block_size accurate?
|
||||
register_memory_allocation (os_block_size_ * 2);
|
||||
gstats_.record(STREAM_OPEN);
|
||||
stats_.record(STREAM_OPEN);
|
||||
}
|
||||
|
||||
// A psuedo-constructor for substreams. This allows us to get around
|
||||
// the fact that one cannot have virtual constructors.
|
||||
template < class T >
|
||||
BTE_err BTE_stream_stdio < T >::new_substream (BTE_stream_type st,
|
||||
TPIE_OS_OFFSET sub_begin,
|
||||
TPIE_OS_OFFSET sub_end,
|
||||
BTE_stream_base < T >
|
||||
**sub_stream)
|
||||
{
|
||||
// Check permissions.
|
||||
if ((st != BTE_READ_STREAM) && ((st != BTE_WRITE_STREAM) || r_only)) {
|
||||
*sub_stream = NULL;
|
||||
return BTE_ERROR_PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
tp_assert (((st == BTE_WRITE_STREAM) && !r_only) ||
|
||||
(st == BTE_READ_STREAM),
|
||||
"Bad things got through the permisssion checks.");
|
||||
|
||||
if (substream_level) {
|
||||
if ((sub_begin * (TPIE_OS_OFFSET)sizeof (T) >=
|
||||
(logical_eos - logical_bos))
|
||||
|| (sub_end * (TPIE_OS_OFFSET)sizeof (T) >
|
||||
(logical_eos - logical_bos))) {
|
||||
*sub_stream = NULL;
|
||||
return BTE_ERROR_OFFSET_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
// We actually have to completely reopen the file in order to get
|
||||
// another seek pointer into it. We'll do this by constructing
|
||||
// the stream that will end up being the substream.
|
||||
BTE_stream_stdio *sub = new BTE_stream_stdio (path, st);
|
||||
|
||||
// Set up the beginning and end positions.
|
||||
if (substream_level) {
|
||||
sub->logical_bos = logical_bos + sub_begin * sizeof (T);
|
||||
sub->logical_eos = logical_bos + (sub_end + 1) * sizeof (T);
|
||||
} else {
|
||||
sub->logical_bos = sub->os_block_size_ + sub_begin * sizeof (T);
|
||||
sub->logical_eos =
|
||||
sub->os_block_size_ + (sub_end + 1) * sizeof (T);
|
||||
}
|
||||
|
||||
// Set the current position.
|
||||
TPIE_OS_FSEEK (sub->file, sub->logical_bos, 0);
|
||||
|
||||
sub->substream_level = substream_level + 1;
|
||||
sub->per =
|
||||
(per == PERSIST_READ_ONCE) ? PERSIST_READ_ONCE : PERSIST_PERSISTENT;
|
||||
*sub_stream = (BTE_stream_base < T > *)sub;
|
||||
|
||||
gstats_.record(SUBSTREAM_CREATE);
|
||||
stats_.record(SUBSTREAM_CREATE);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template < class T > BTE_stream_stdio < T >::~BTE_stream_stdio (void) {
|
||||
|
||||
if (!r_only) {
|
||||
header.item_logical_eof = file_off_to_item_off(f_eof);
|
||||
if (TPIE_OS_FSEEK (file, 0, TPIE_OS_FLAG_SEEK_SET) == -1) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_WARNING_ID("Failed to seek in file:");
|
||||
TP_LOG_WARNING_ID(path);
|
||||
} else if (TPIE_OS_FWRITE ((char *) &header, sizeof (header), 1, file) != 1) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_WARNING_ID("Failed to write header to file:");
|
||||
TP_LOG_WARNING_ID(path);
|
||||
// return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TPIE_OS_FCLOSE (file) != 0) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_WARNING_ID("Failed to close file:");
|
||||
TP_LOG_WARNING_ID(path);
|
||||
}
|
||||
|
||||
// Get rid of the file if not persistent and if not substream.
|
||||
if (!substream_level) {
|
||||
if (per == PERSIST_DELETE) {
|
||||
if (r_only) {
|
||||
TP_LOG_WARNING_ID("Read only stream is PERSIST_DELETE:");
|
||||
TP_LOG_WARNING_ID(path);
|
||||
TP_LOG_WARNING_ID("Ignoring persistency request.");
|
||||
} else if (unlink (path)) {
|
||||
os_errno = errno;
|
||||
TP_LOG_WARNING_ID("Failed to unlink() file:");
|
||||
TP_LOG_WARNING_ID(path);
|
||||
TP_LOG_WARNING_ID(strerror(os_errno));
|
||||
} else {
|
||||
gstats_.record(STREAM_DELETE);
|
||||
stats_.record(STREAM_DELETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gstats_.record(SUBSTREAM_DELETE);
|
||||
stats_.record(SUBSTREAM_DELETE);
|
||||
}
|
||||
// Register memory deallocation before returning.
|
||||
// A quick and dirty guess. One block in the buffer cache, one in
|
||||
// user space. TODO.
|
||||
register_memory_deallocation (os_block_size_ * 2);
|
||||
|
||||
if (remaining_streams >= 0) {
|
||||
remaining_streams++;
|
||||
}
|
||||
gstats_.record(STREAM_CLOSE);
|
||||
stats_.record(STREAM_CLOSE);
|
||||
}
|
||||
|
||||
template < class T > BTE_err BTE_stream_stdio < T >::read_item (T ** elt)
|
||||
{
|
||||
TPIE_OS_SIZE_T stdio_ret;
|
||||
BTE_err ret;
|
||||
|
||||
if ((logical_eos >= 0) && (TPIE_OS_FTELL (file) >= logical_eos)) {
|
||||
tp_assert ((logical_bos >= 0), "eos set but bos not.");
|
||||
status_ = BTE_STREAM_STATUS_END_OF_STREAM;
|
||||
ret = BTE_ERROR_END_OF_STREAM;
|
||||
} else {
|
||||
|
||||
stdio_ret = TPIE_OS_FREAD ((char *) (&read_tmp), sizeof (T), 1, file);
|
||||
|
||||
if (stdio_ret == 1) {
|
||||
f_offset += sizeof(T);
|
||||
*elt = &read_tmp;
|
||||
ret = BTE_ERROR_NO_ERROR;
|
||||
} else {
|
||||
// Assume EOF. Fix this later.
|
||||
status_ = BTE_STREAM_STATUS_END_OF_STREAM;
|
||||
ret = BTE_ERROR_END_OF_STREAM;
|
||||
}
|
||||
}
|
||||
|
||||
gstats_.record(ITEM_READ);
|
||||
stats_.record(ITEM_READ);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
BTE_err BTE_stream_stdio < T >::write_item (const T & elt) {
|
||||
|
||||
TPIE_OS_SIZE_T stdio_ret;
|
||||
BTE_err ret;
|
||||
|
||||
if ((logical_eos >= 0) && (TPIE_OS_FTELL (file) > logical_eos)) {
|
||||
tp_assert ((logical_bos >= 0), "eos set but bos not.");
|
||||
status_ = BTE_STREAM_STATUS_END_OF_STREAM;
|
||||
ret = BTE_ERROR_END_OF_STREAM;
|
||||
} else {
|
||||
stdio_ret = TPIE_OS_FWRITE ((char *) &elt, sizeof (T), 1, file);
|
||||
if (stdio_ret == 1) {
|
||||
if (f_eof == f_offset)
|
||||
f_eof += sizeof(T);
|
||||
f_offset += sizeof(T);
|
||||
ret = BTE_ERROR_NO_ERROR;
|
||||
} else {
|
||||
TP_LOG_FATAL_ID("write_item failed.");
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
ret = BTE_ERROR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
gstats_.record(ITEM_WRITE);
|
||||
stats_.record(ITEM_WRITE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template < class T >
|
||||
BTE_err BTE_stream_stdio < T >::main_memory_usage (size_t * usage,
|
||||
MM_stream_usage
|
||||
usage_type) {
|
||||
|
||||
switch (usage_type) {
|
||||
case MM_STREAM_USAGE_OVERHEAD:
|
||||
//Fixed overhead per object. *this includes base class.
|
||||
//Need to include 2*overhead per "new" that sizeof doesn't
|
||||
//know about.
|
||||
*usage = sizeof(*this)+2*MM_manager.space_overhead();
|
||||
break;
|
||||
case MM_STREAM_USAGE_BUFFER:
|
||||
//Amount used by stdio buffers. No "new" calls => no overhead
|
||||
*usage = 2 * os_block_size_;
|
||||
break;
|
||||
case MM_STREAM_USAGE_CURRENT:
|
||||
case MM_STREAM_USAGE_MAXIMUM:
|
||||
case MM_STREAM_USAGE_SUBSTREAM:
|
||||
*usage = sizeof(*this) + 2*os_block_size_ +
|
||||
2*MM_manager.space_overhead();
|
||||
break;
|
||||
}
|
||||
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Return the number of items in the stream.
|
||||
template < class T >
|
||||
TPIE_OS_OFFSET BTE_stream_stdio < T >::stream_len (void) const {
|
||||
|
||||
if (substream_level) { // We are in a substream.
|
||||
/// return (logical_eos - logical_bos) / sizeof (T);
|
||||
// [tavi 01/25/02] Commented out the above and replaced it with the following:
|
||||
return file_off_to_item_off(logical_eos) - file_off_to_item_off(logical_bos);
|
||||
} else {
|
||||
// There must be a way to get this information directly,
|
||||
// instead of fseeking around.
|
||||
|
||||
// Where are we now?
|
||||
/// TPIE_OS_OFFSET current = ftell (file);
|
||||
|
||||
// Go to the end and see where we are.
|
||||
/// TPIE_OS_FSEEK (file, 0, TPIE_OS_FLAG_SEEK_END);
|
||||
/// TPIE_OS_OFFSET end = ftell (file);
|
||||
|
||||
// Go back.
|
||||
/// TPIE_OS_FSEEK (file, current, TPIE_OS_FLAG_SEEK_SET);
|
||||
|
||||
// Lars May 22, 1997: This is a quick hack to fix a problem
|
||||
// with headers of length less than a block. That shouldn't
|
||||
// be possible but there is a bug somewhere
|
||||
// - Look at it later (seems to have something to do with
|
||||
// substreams. Header block is not truncated).
|
||||
/// if (end < (int) os_block_size_) {
|
||||
//printf("shouldnt be here! possible bug\n);
|
||||
/// return 0;
|
||||
/// } else {
|
||||
/// return (end - os_block_size_) / sizeof (T);
|
||||
/// }
|
||||
// [tavi 01/25/02] Commented out the above and replaced it with the following:
|
||||
return file_off_to_item_off(f_eof);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the path name in newly allocated space.
|
||||
template < class T >
|
||||
BTE_err BTE_stream_stdio < T >::name (char **stream_name) {
|
||||
|
||||
TPIE_OS_SIZE_T len = strlen (path);
|
||||
|
||||
tp_assert (len < BTE_STREAM_PATH_NAME_LEN, "Path length is too long.");
|
||||
|
||||
// Return the path name in newly allocated space.
|
||||
char *new_path = new char[len + 1];
|
||||
|
||||
strncpy (new_path, path, len + 1);
|
||||
*stream_name = new_path;
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// Move to a specific position.
|
||||
template < class T > BTE_err BTE_stream_stdio < T >::seek (TPIE_OS_OFFSET offset) {
|
||||
|
||||
TPIE_OS_OFFSET file_position;
|
||||
|
||||
if (substream_level) {
|
||||
if (offset * (TPIE_OS_OFFSET)sizeof (T) > (TPIE_OS_OFFSET)(logical_eos - logical_bos)) {
|
||||
return BTE_ERROR_OFFSET_OUT_OF_RANGE;
|
||||
} else {
|
||||
file_position = offset * sizeof (T) + logical_bos;
|
||||
}
|
||||
} else {
|
||||
file_position = offset * sizeof (T) + os_block_size_;
|
||||
}
|
||||
|
||||
if (TPIE_OS_FSEEK (file, file_position, TPIE_OS_FLAG_SEEK_SET)) {
|
||||
TP_LOG_FATAL("fseek failed to go to position " << file_position <<
|
||||
" of \"" << "\"\n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
|
||||
f_offset = file_position;
|
||||
gstats_.record(ITEM_SEEK);
|
||||
stats_.record(ITEM_SEEK);
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
template < class T >
|
||||
TPIE_OS_OFFSET BTE_stream_stdio < T >::tell() const {
|
||||
return file_off_to_item_off(f_offset);
|
||||
}
|
||||
|
||||
// Truncate the stream.
|
||||
template < class T >
|
||||
BTE_err BTE_stream_stdio < T >::truncate (TPIE_OS_OFFSET offset) {
|
||||
// TPIE_OS_TRUNCATE_STREAM_TEMPLATE_CLASS_BODY;
|
||||
TPIE_OS_OFFSET file_position;
|
||||
|
||||
if (substream_level) {
|
||||
return BTE_ERROR_STREAM_IS_SUBSTREAM;
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
return BTE_ERROR_OFFSET_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
file_position = offset * sizeof (T) + os_block_size_;
|
||||
|
||||
// if (::truncate (path, file_position)) {
|
||||
if (TPIE_OS_TRUNCATE(file, path, file_position) == -1) {
|
||||
os_errno = errno;
|
||||
TP_LOG_FATAL_ID("Failed to truncate() to the new end of file:");
|
||||
TP_LOG_FATAL_ID(path);
|
||||
TP_LOG_FATAL_ID(strerror (os_errno));
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
|
||||
if (TPIE_OS_FSEEK(file, file_position, SEEK_SET) == -1) {
|
||||
TP_LOG_FATAL("fseek failed to go to position " << file_position << " of \"" << "\"\n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
return BTE_ERROR_OS_ERROR;
|
||||
}
|
||||
|
||||
f_offset = file_position;
|
||||
f_eof = file_position;
|
||||
|
||||
return BTE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
TPIE_OS_OFFSET BTE_stream_stdio < T >::chunk_size (void) const {
|
||||
// Quick and dirty guess.
|
||||
return (os_block_size_ * 2) / sizeof (T);
|
||||
}
|
||||
|
||||
|
||||
// Return -1 if error, 0 otherwise.
|
||||
template<class T> int BTE_stream_stdio < T >::readcheck_header ()
|
||||
{
|
||||
// Read the header.
|
||||
if ((TPIE_OS_FREAD ((char *) &header, sizeof (header), 1, file)) != 1) {
|
||||
status_ = BTE_STREAM_STATUS_INVALID;
|
||||
TP_LOG_FATAL_ID("Failed to read header from file:");
|
||||
TP_LOG_FATAL_ID(path);
|
||||
return -1;
|
||||
}
|
||||
if (check_header(&header) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//everything's fine
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET BTE_stream_stdio < T >::file_off_to_item_off (TPIE_OS_OFFSET file_off) const {
|
||||
return (file_off - os_block_size_) / sizeof (T);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_OFFSET BTE_stream_stdio < T >::item_off_to_file_off (TPIE_OS_OFFSET item_off) const {
|
||||
return (os_block_size_ + item_off * sizeof (T));
|
||||
}
|
||||
|
||||
#endif // _BTE_STREAM_STDIO_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
librule(
|
||||
name="tpie",
|
||||
cflags = "-I. -DHAVE_CONFIG_H -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE",
|
||||
sources=["ami_bit_permute.cc",
|
||||
"ami_device.cc",
|
||||
"ami_key.cc",
|
||||
"ami_matrix_blocks.cc",
|
||||
#"ami_scan_mac.cc",
|
||||
"ami_stream_single.cc",
|
||||
"bit.cc",
|
||||
"bit_matrix.cc",
|
||||
"bte_stream_base.cc",
|
||||
"cpu_timer.cc",
|
||||
"cpu_timer.cc",
|
||||
"logstream.cc",
|
||||
"mm_base.cc",
|
||||
"mm_register.cc",
|
||||
"portability.cc",
|
||||
"tpie_log.cc",
|
||||
"tpie_tempnam.cc"],
|
||||
headers=lglob("*.h")
|
||||
);
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2005 Andrew Danner
|
||||
//
|
||||
// File: comparator.h
|
||||
// Author: Andrew Danner
|
||||
// Created: 28 Jun 2005
|
||||
//
|
||||
// Mappings/Wrappers for converting between different comparison types
|
||||
//
|
||||
// $Id: comparator.h,v 1.4 2005/07/07 20:39:22 adanner Exp $
|
||||
//
|
||||
#ifndef _COMPARATOR_H
|
||||
#define _COMPARATOR_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
|
||||
// In is unlikely that users will need to directly need these classes
|
||||
// except to maybe upgrade old code with minimal changes. In the future it
|
||||
// may be better to make TPIE's compare() method match the syntax of the
|
||||
// STL operator ()
|
||||
|
||||
//Convert STL comparison object with operator() to a TPIE comparison
|
||||
//object with a compare() function.
|
||||
template<class T, class STLCMP>
|
||||
class STL2TPIE_cmp{
|
||||
private:
|
||||
STLCMP *isLess; //Class with STL comparison operator()
|
||||
|
||||
public:
|
||||
STL2TPIE_cmp(STLCMP* _cmp) {isLess=_cmp; }
|
||||
//Do not use with applications that test if compare returns +1
|
||||
//Because it never does so.
|
||||
inline int compare(const T& left, const T& right){
|
||||
if( (*isLess)(left, right) ){ return -1; }
|
||||
else { return 0; }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//Convert a TPIE comparison object with a compare() function.
|
||||
//to STL comparison object with operator()
|
||||
template<class T, class TPCMP>
|
||||
class TPIE2STL_cmp{
|
||||
private:
|
||||
TPCMP* cmpobj; //Class with TPIE comparison compare()
|
||||
|
||||
public:
|
||||
TPIE2STL_cmp(TPCMP* cmp) {cmpobj=cmp;}
|
||||
inline bool operator()(const T& left, const T& right) const{
|
||||
return (cmpobj->compare(left, right) < 0);
|
||||
}
|
||||
};
|
||||
|
||||
//Convert a class with a comparison operator <
|
||||
//to a TPIE comparison object with a compare() function.
|
||||
template<class T>
|
||||
class op2TPIE_cmp{
|
||||
public:
|
||||
op2TPIE_cmp(){};
|
||||
//Do not use with applications that test if compare returns +1
|
||||
//Because it never does so.
|
||||
inline int compare(const T& left, const T& right){
|
||||
if( left < right ){ return -1; }
|
||||
else { return 0; }
|
||||
}
|
||||
};
|
||||
|
||||
//Convert a class with a comparison operator <
|
||||
//to an STL comparison object with a comparison operator ().
|
||||
//Not implemented here. It is called less in <functional>, part of STL
|
||||
|
||||
#endif // _COMPARATOR_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/* include/config.h. Generated by configure. */
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: config.h.in
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 10/13/94
|
||||
//
|
||||
// $Id: config.h.in,v 1.8 2003/04/17 18:51:20 jan Exp $
|
||||
//
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
// Define if you have getrusage()
|
||||
#define HAVE_GETRUSAGE 1
|
||||
|
||||
// Define if you have mmap()
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
// Define if asyncronous I/O is avaialable.
|
||||
#define HAVE_LIBAIO 0
|
||||
|
||||
// Define if you have a prototype for mmap()
|
||||
#define HAVE_PROTOTYPE_MMAP 1
|
||||
|
||||
// Define if you have a prototype for munmap()
|
||||
#define HAVE_PROTOTYPE_MUNMAP 1
|
||||
|
||||
// Define if you have a prototype for ftruncate()
|
||||
#define HAVE_PROTOTYPE_FTRUNCATE 1
|
||||
|
||||
// Do we have string.h or strings.h?
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
// Where is unistd.h?
|
||||
#ifdef _WIN32
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_SYS_UNISTD_H 1
|
||||
#else
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_SYS_UNISTD_H 1
|
||||
#endif
|
||||
|
||||
// Are we on a hacked kernel that supports zero()?
|
||||
#define HAVE_ZERO 0
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#elif HAVE_SYS_UNISTD_H
|
||||
#include <sys/unistd.h>
|
||||
#endif
|
||||
|
||||
// On Solaris, _SC_PAGE_SIZE is called _SC_PAGE_SIZE. Here's a quick
|
||||
// fix.
|
||||
#if !defined(_SC_PAGE_SIZE) && defined(_SC_PAGESIZE)
|
||||
#define _SC_PAGE_SIZE _SC_PAGESIZE
|
||||
#endif
|
||||
|
||||
// Flags to enable or disable various features of the system.
|
||||
|
||||
#define TP_ASSERT_APPS 1
|
||||
#define TP_ASSERT_LIB 1
|
||||
|
||||
#define TP_LOG_APPS 1
|
||||
#define TP_LOG_LIB 1
|
||||
|
||||
#endif // _CONFIG_H
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: config.h.in
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 10/13/94
|
||||
//
|
||||
// $Id: config.h.in,v 1.8 2003/04/17 18:51:20 jan Exp $
|
||||
//
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
// Define if you have getrusage()
|
||||
#define HAVE_GETRUSAGE 0
|
||||
|
||||
// Define if you have mmap()
|
||||
#define HAVE_MMAP 0
|
||||
|
||||
// Define if asyncronous I/O is avaialable.
|
||||
#define HAVE_LIBAIO 0
|
||||
|
||||
// Define if you have a prototype for mmap()
|
||||
#define HAVE_PROTOTYPE_MMAP 0
|
||||
|
||||
// Define if you have a prototype for munmap()
|
||||
#define HAVE_PROTOTYPE_MUNMAP 0
|
||||
|
||||
// Define if you have a prototype for ftruncate()
|
||||
#define HAVE_PROTOTYPE_FTRUNCATE 0
|
||||
|
||||
// Do we have string.h or strings.h?
|
||||
#define HAVE_STRING_H 0
|
||||
#define HAVE_STRINGS_H 0
|
||||
|
||||
// Where is unistd.h?
|
||||
#ifdef _WIN32
|
||||
#define HAVE_UNISTD_H 0
|
||||
#define HAVE_SYS_UNISTD_H 0
|
||||
#else
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define HAVE_SYS_UNISTD_H 1
|
||||
#endif
|
||||
|
||||
// Are we on a hacked kernel that supports zero()?
|
||||
#define HAVE_ZERO 0
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#elif HAVE_SYS_UNISTD_H
|
||||
#include <sys/unistd.h>
|
||||
#endif
|
||||
|
||||
// On Solaris, _SC_PAGE_SIZE is called _SC_PAGE_SIZE. Here's a quick
|
||||
// fix.
|
||||
#if !defined(_SC_PAGE_SIZE) && defined(_SC_PAGESIZE)
|
||||
#define _SC_PAGE_SIZE _SC_PAGESIZE
|
||||
#endif
|
||||
|
||||
// Flags to enable or disable various features of the system.
|
||||
|
||||
#define TP_ASSERT_APPS 1
|
||||
#define TP_ASSERT_LIB 1
|
||||
|
||||
#define TP_LOG_APPS 1
|
||||
#define TP_LOG_LIB 1
|
||||
|
||||
#endif // _CONFIG_H
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: cpu_timer.cpp
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/11/95
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(cpu_timer_cpp,"$Id: cpu_timer.cpp,v 1.9 2004/08/17 16:48:50 jan Exp $");
|
||||
|
||||
#include <cpu_timer.h>
|
||||
|
||||
cpu_timer::cpu_timer() :
|
||||
running(false)
|
||||
{
|
||||
TPIE_OS_SET_CLOCK_TICK;
|
||||
|
||||
elapsed_real = 0;
|
||||
}
|
||||
|
||||
cpu_timer::~cpu_timer()
|
||||
{
|
||||
}
|
||||
|
||||
void cpu_timer::sync()
|
||||
{
|
||||
clock_t current_real;
|
||||
|
||||
TPIE_OS_TMS current;
|
||||
TPIE_OS_SET_CURRENT_TIME(current);
|
||||
TPIE_OS_UNIX_ONLY_SET_ELAPSED_TIME(current);
|
||||
|
||||
elapsed_real += current_real - last_sync_real;
|
||||
|
||||
last_sync = current;
|
||||
last_sync_real = current_real;
|
||||
}
|
||||
|
||||
|
||||
void cpu_timer::start()
|
||||
{
|
||||
if (!running) {
|
||||
TPIE_OS_LAST_SYNC_REAL_DECLARATION;
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_timer::stop()
|
||||
{
|
||||
if (running) {
|
||||
sync();
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_timer::reset()
|
||||
{
|
||||
if (running) {
|
||||
TPIE_OS_LAST_SYNC_REAL_DECLARATION;
|
||||
}
|
||||
|
||||
TPIE_OS_SET_CLOCK_TICK;
|
||||
elapsed_real = 0;
|
||||
}
|
||||
|
||||
double cpu_timer::user_time() {
|
||||
if (running) sync();
|
||||
TPIE_OS_USER_TIME_BODY;
|
||||
}
|
||||
|
||||
double cpu_timer::system_time() {
|
||||
if (running) sync();
|
||||
TPIE_OS_USER_TIME_BODY;
|
||||
}
|
||||
|
||||
double cpu_timer::wall_time() {
|
||||
if (running) sync();
|
||||
return double(elapsed_real) / double(clock_tick);
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &s, cpu_timer &wt)
|
||||
{
|
||||
if (wt.running) {
|
||||
wt.sync();
|
||||
}
|
||||
|
||||
TPIE_OS_OPERATOR_OVERLOAD;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// File: cpu_timer.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/11/95
|
||||
//
|
||||
// $Id: cpu_timer.h,v 1.8 2004/08/17 16:48:11 jan Exp $
|
||||
//
|
||||
// A timer measuring user time, system time and wall clock time. The
|
||||
// timer can be start()'ed, stop()'ed, and queried. Querying can be
|
||||
// done without stopping the timer, to report intermediate values.
|
||||
//
|
||||
#ifndef _CPU_TIMER_H
|
||||
#define _CPU_TIMER_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <timer.h>
|
||||
|
||||
class cpu_timer : public timer {
|
||||
private:
|
||||
long clock_tick;
|
||||
|
||||
TPIE_OS_TMS last_sync;
|
||||
TPIE_OS_TMS elapsed;
|
||||
|
||||
clock_t last_sync_real;
|
||||
clock_t elapsed_real;
|
||||
bool running;
|
||||
public:
|
||||
cpu_timer();
|
||||
virtual ~cpu_timer();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
void sync();
|
||||
void reset();
|
||||
|
||||
double user_time();
|
||||
double system_time();
|
||||
double wall_time();
|
||||
|
||||
friend ostream &operator<<(ostream &s, cpu_timer &ct);
|
||||
};
|
||||
|
||||
ostream &operator<<(ostream &s, cpu_timer &ct);
|
||||
|
||||
#endif // _CPU_TIMER_H
|
||||
@@ -0,0 +1,469 @@
|
||||
// Copyright (c) 2005 Andrew Danner
|
||||
//
|
||||
// File: internal_sorter.h
|
||||
// Author: Andrew Danner <adanner@cs.duke.edu>
|
||||
// Created: 28 Jun 2005
|
||||
//
|
||||
// Internal sorter class that can be used within AMI_sort() on small
|
||||
// streams/substreams
|
||||
//
|
||||
// $Id: internal_sort.h,v 1.1 2005/08/24 19:32:38 adanner Exp $
|
||||
//
|
||||
#ifndef _INTERNAL_SORT_H
|
||||
#define _INTERNAL_SORT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
#include <quicksort.h>
|
||||
|
||||
// Use our quicksort, or the sort from STL
|
||||
#ifdef TPIE_USE_STL_SORT
|
||||
// portability.h includes <algorithm> for us in the case of STL sort
|
||||
#include <comparator.h> //to convert TPIE comparisons to STL
|
||||
#endif
|
||||
|
||||
// The base class. This class does not have a sort() function, so it
|
||||
// cannot be used directly
|
||||
template<class T>
|
||||
class Internal_Sorter_Base{
|
||||
protected:
|
||||
T* ItemArray; //Array that holds items to be sorted
|
||||
TPIE_OS_OFFSET len; //length of ItemArray
|
||||
|
||||
public:
|
||||
//Constructor
|
||||
Internal_Sorter_Base(void): len(0) { ItemArray=NULL; }
|
||||
~Internal_Sorter_Base(void); //Destructor
|
||||
|
||||
//Allocate array that can hold nItems
|
||||
void allocate(TPIE_OS_OFFSET nItems);
|
||||
|
||||
void deallocate(void); //Clean up internal array
|
||||
|
||||
// Maximum number of Items that can be sorted using memSize bytes
|
||||
TPIE_OS_OFFSET MaxItemCount(TPIE_OS_OFFSET memSize);
|
||||
|
||||
// Memory usage per sort item
|
||||
TPIE_OS_SIZE_T space_per_item();
|
||||
|
||||
// Fixed memory usage overhead per class instantiation
|
||||
TPIE_OS_SIZE_T space_overhead();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
Internal_Sorter_Base<T>::~Internal_Sorter_Base(void){
|
||||
//In case someone forgot to call deallocate()
|
||||
if(ItemArray){
|
||||
delete [] ItemArray;
|
||||
ItemArray=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Internal_Sorter_Base<T>::allocate(TPIE_OS_OFFSET nitems){
|
||||
len=nitems;
|
||||
ItemArray = new T[len];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void Internal_Sorter_Base<T>::deallocate(void){
|
||||
if(ItemArray){
|
||||
delete [] ItemArray;
|
||||
ItemArray=NULL;
|
||||
len=0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline TPIE_OS_OFFSET Internal_Sorter_Base<T>::MaxItemCount(
|
||||
TPIE_OS_OFFSET memSize)
|
||||
{
|
||||
//Space available for items
|
||||
TPIE_OS_OFFSET memAvail=memSize-space_overhead();
|
||||
|
||||
if(memAvail < space_per_item() ){ return -1; }
|
||||
else{ return memAvail/space_per_item(); }
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline TPIE_OS_SIZE_T Internal_Sorter_Base<T>::space_overhead(void)
|
||||
{
|
||||
// Space usage independent of space_per_item
|
||||
// accounts MM_manager space overhead on "new" call
|
||||
return MM_manager.space_overhead();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline TPIE_OS_SIZE_T Internal_Sorter_Base<T>::space_per_item(void)
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * *
|
||||
// * Operator based Internal Sorter. *
|
||||
// * *
|
||||
// *********************************************************************
|
||||
|
||||
template<class T>
|
||||
class Internal_Sorter_Op: public Internal_Sorter_Base<T>{
|
||||
protected:
|
||||
using Internal_Sorter_Base<T>::len;
|
||||
using Internal_Sorter_Base<T>::ItemArray;
|
||||
|
||||
public:
|
||||
//Constructor/Destructor
|
||||
Internal_Sorter_Op(){};
|
||||
~Internal_Sorter_Op(){};
|
||||
|
||||
using Internal_Sorter_Base<T>::space_overhead;
|
||||
|
||||
//Sort nItems from input stream and write to output stream
|
||||
AMI_err sort(AMI_STREAM<T>* InStr, AMI_STREAM<T>* OutStr,
|
||||
TPIE_OS_OFFSET nItems);
|
||||
};
|
||||
|
||||
// Read nItems sequentially from InStr, starting at the current file
|
||||
// position. Write the sorted output to OutStr, starting from the current
|
||||
// file position.
|
||||
template<class T>
|
||||
AMI_err Internal_Sorter_Op<T>::sort(AMI_STREAM<T>* InStr,
|
||||
AMI_STREAM<T>* OutStr, TPIE_OS_OFFSET nItems){
|
||||
|
||||
AMI_err ae;
|
||||
T *next_item;
|
||||
TPIE_OS_OFFSET i = 0;
|
||||
|
||||
TP_LOG_DEBUG_ID("Sorting internal run of " << nItems
|
||||
<< " items using \"<\" operator.");
|
||||
tp_assert ( nItems <= len, "nItems more than interal buffer size.");
|
||||
|
||||
// Read a memory load out of the input stream one item at a time,
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae=InStr->read_item (&next_item)) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal sort: AMI read error " << ae);
|
||||
return ae;
|
||||
}
|
||||
ItemArray[i] = *next_item;
|
||||
}
|
||||
|
||||
//Sort the array.
|
||||
#ifdef TPIE_USE_STL_SORT
|
||||
TP_LOG_DEBUG_ID("calling STL sort for " << nItems << " items");
|
||||
std::sort(ItemArray, ItemArray+nItems);
|
||||
#else
|
||||
TP_LOG_DEBUG_ID("calling quick_sort_op for " << nItems << " items");
|
||||
quick_sort_op<T> (ItemArray, nItems);
|
||||
#endif
|
||||
|
||||
if(InStr==OutStr){ //Do the right thing if we are doing 2x sort
|
||||
//Internal sort objects should probably be re-written so that
|
||||
//the interface is cleaner and they don't have to worry about I/O
|
||||
InStr->truncate(0); //delete original items
|
||||
InStr->seek(0); //rewind
|
||||
}
|
||||
//Write sorted array to OutStr
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae = OutStr->write_item(ItemArray[i])) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal Sorter: AMI write error" << ae );
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
TP_LOG_DEBUG_ID("returning from Internal_Sorter_Op");
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * *
|
||||
// * Comparison object based Internal Sorter. *
|
||||
// * *
|
||||
// *********************************************************************
|
||||
|
||||
template<class T, class CMPR>
|
||||
class Internal_Sorter_Obj: public Internal_Sorter_Base<T>{
|
||||
protected:
|
||||
using Internal_Sorter_Base<T>::ItemArray;
|
||||
using Internal_Sorter_Base<T>::len;
|
||||
CMPR *cmp_o; //Comparison object used for sorting
|
||||
|
||||
public:
|
||||
//Constructor/Destructor
|
||||
Internal_Sorter_Obj(CMPR* cmp){cmp_o=cmp;};
|
||||
~Internal_Sorter_Obj(){};
|
||||
|
||||
using Internal_Sorter_Base<T>::space_overhead;
|
||||
|
||||
//Sort nItems from input stream and write to output stream
|
||||
AMI_err sort(AMI_STREAM<T>* InStr, AMI_STREAM<T>* OutStr,
|
||||
TPIE_OS_OFFSET nItems);
|
||||
};
|
||||
|
||||
// Read nItems sequentially from InStr, starting at the current file
|
||||
// position. Write the sorted output to OutStr, starting from the current
|
||||
// file position.
|
||||
template<class T, class CMPR>
|
||||
AMI_err Internal_Sorter_Obj<T, CMPR>::sort(AMI_STREAM<T>* InStr,
|
||||
AMI_STREAM<T>* OutStr, TPIE_OS_OFFSET nItems){
|
||||
|
||||
AMI_err ae;
|
||||
T *next_item;
|
||||
TPIE_OS_OFFSET i = 0;
|
||||
|
||||
TP_LOG_DEBUG_ID("Sorting internal run of " << nItems
|
||||
<< " items using TPIE comparison object.");
|
||||
tp_assert ( nItems <= len, "nItems more than interal buffer size.");
|
||||
|
||||
// Read a memory load out of the input stream one item at a time,
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae=InStr->read_item (&next_item)) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal sort: AMI read error " << ae);
|
||||
return ae;
|
||||
}
|
||||
ItemArray[i] = *next_item;
|
||||
}
|
||||
|
||||
//Sort the array.
|
||||
#ifdef TPIE_USE_STL_SORT
|
||||
TP_LOG_DEBUG_ID("calling STL sort for " << nItems << " items");
|
||||
TP_LOG_DEBUG_ID("converting TPIE comparison object to STL");
|
||||
std::sort(ItemArray, ItemArray+nItems, TPIE2STL_cmp<T,CMPR>(cmp_o));
|
||||
#else
|
||||
TP_LOG_DEBUG_ID("calling quick_sort_obj for " << nItems << " items");
|
||||
quick_sort_obj<T> (ItemArray, nItems, cmp_o);
|
||||
#endif
|
||||
|
||||
if(InStr==OutStr){ //Do the right thing if we are doing 2x sort
|
||||
//Internal sort objects should probably be re-written so that
|
||||
//the interface is cleaner and they don't have to worry about I/O
|
||||
InStr->truncate(0); //delete original items
|
||||
InStr->seek(0); //rewind
|
||||
}
|
||||
//Write sorted array to OutStr
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae = OutStr->write_item(ItemArray[i])) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal Sorter: AMI write error" << ae );
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
TP_LOG_DEBUG_ID("returning from Internal_Sorter_Op");
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * *
|
||||
// * Key + Object based Internal Sorter *
|
||||
// * *
|
||||
// *********************************************************************
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
class Internal_Sorter_KObj{
|
||||
protected:
|
||||
T* ItemArray; //Array that holds original items
|
||||
qsort_item<KEY>* sortItemArray; //Holds keys to be sorted
|
||||
CMPR *UsrObject; //Copy,compare keys
|
||||
TPIE_OS_OFFSET len; //length of ItemArray
|
||||
|
||||
public:
|
||||
//Constructor:
|
||||
Internal_Sorter_KObj(CMPR* cmp): len(0) {
|
||||
ItemArray=NULL;
|
||||
sortItemArray=NULL;
|
||||
UsrObject=cmp;
|
||||
}
|
||||
~Internal_Sorter_KObj(void); //Destructor
|
||||
|
||||
//Allocate array that can hold nItems
|
||||
void allocate(TPIE_OS_OFFSET nItems);
|
||||
|
||||
//Sort nItems from input stream and write to output stream
|
||||
AMI_err sort(AMI_STREAM<T>* InStr, AMI_STREAM<T>* OutStr,
|
||||
TPIE_OS_OFFSET nItems);
|
||||
|
||||
void deallocate(void); //Clean up internal array
|
||||
|
||||
// Maximum number of Items that can be sorted using memSize bytes
|
||||
TPIE_OS_OFFSET MaxItemCount(TPIE_OS_OFFSET memSize);
|
||||
|
||||
// Memory usage per sort item
|
||||
TPIE_OS_SIZE_T space_per_item();
|
||||
|
||||
// Fixed memory usage overhead per class instantiation
|
||||
TPIE_OS_SIZE_T space_overhead();
|
||||
};
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
Internal_Sorter_KObj<T, KEY, CMPR>::~Internal_Sorter_KObj(void){
|
||||
//In case someone forgot to call deallocate()
|
||||
if(ItemArray){
|
||||
delete [] ItemArray;
|
||||
ItemArray=NULL;
|
||||
}
|
||||
if(sortItemArray){
|
||||
delete [] sortItemArray;
|
||||
sortItemArray=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline void Internal_Sorter_KObj<T, KEY, CMPR>::allocate(TPIE_OS_OFFSET nitems){
|
||||
len=nitems;
|
||||
ItemArray = new T[len];
|
||||
sortItemArray = new qsort_item<KEY>[len];
|
||||
}
|
||||
|
||||
// A helper class to quick sort qsort_item<KEY> types
|
||||
// given a comparison object for comparing keys
|
||||
template<class KEY, class KCMP>
|
||||
class QsortKeyCmp{
|
||||
private:
|
||||
KCMP *isLess; //Class with function compare that compares 2 keys
|
||||
|
||||
public:
|
||||
QsortKeyCmp(KCMP* kcmp) {isLess=kcmp; }
|
||||
inline int compare(const qsort_item<KEY>& left,
|
||||
const qsort_item<KEY>& right){
|
||||
return isLess->compare(left.keyval, right.keyval);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline AMI_err Internal_Sorter_KObj<T, KEY, CMPR>::sort(AMI_STREAM<T>* InStr,
|
||||
AMI_STREAM<T>* OutStr, TPIE_OS_OFFSET nItems){
|
||||
|
||||
AMI_err ae;
|
||||
T *next_item;
|
||||
TPIE_OS_OFFSET i = 0;
|
||||
|
||||
TP_LOG_DEBUG_ID("Sorting internal run of " << nItems
|
||||
<< " items using \"<\" operator.");
|
||||
tp_assert ( nItems <= len, "nItems more than interal buffer size.");
|
||||
|
||||
// Read a memory load out of the input stream one item at a time,
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae=InStr->read_item (&next_item)) != AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal sort: AMI read error " << ae);
|
||||
return ae;
|
||||
}
|
||||
ItemArray[i] = *next_item;
|
||||
UsrObject->copy(&sortItemArray[i].keyval, *next_item);
|
||||
sortItemArray[i].source=i;
|
||||
}
|
||||
|
||||
//Sort the array.
|
||||
#ifdef TPIE_USE_STL_SORT
|
||||
TP_LOG_DEBUG_ID("calling STL sort for " << nItems << " items");
|
||||
TP_LOG_DEBUG_ID("converting TPIE Key comparison object to STL");
|
||||
std::sort(sortItemArray, ItemArray+nItems,
|
||||
TPIE2STL_cmp<qsort_item<KEY>,QsortKeyCmp<KEY,CMPR> >
|
||||
(QsortKeyCmp<KEY, CMPR>(UsrObject)));
|
||||
#else
|
||||
QsortKeyCmp<KEY, CMPR> qcmp(UsrObject);
|
||||
TP_LOG_DEBUG_ID("calling quick_sort_obj for " << nItems << " items");
|
||||
quick_sort_obj< qsort_item<KEY> > (sortItemArray, nItems, &qcmp);
|
||||
#endif
|
||||
|
||||
if(InStr==OutStr){ //Do the right thing if we are doing 2x sort
|
||||
//Internal sort objects should probably be re-written so that
|
||||
//the interface is cleaner and they don't have to worry about I/O
|
||||
InStr->truncate(0); //delete original items
|
||||
InStr->seek(0); //rewind
|
||||
}
|
||||
//Write sorted array to OutStr
|
||||
for (i = 0; i < nItems; i++) {
|
||||
if ((ae = OutStr->write_item(ItemArray[sortItemArray[i].source]))
|
||||
!= AMI_ERROR_NO_ERROR) {
|
||||
TP_LOG_FATAL_ID ("Internal Sorter: AMI write error" << ae );
|
||||
return ae;
|
||||
}
|
||||
}
|
||||
TP_LOG_DEBUG_ID("returning from Internal_Sorter_Op");
|
||||
return AMI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline void Internal_Sorter_KObj<T, KEY, CMPR>::deallocate(void){
|
||||
len=0;
|
||||
if(ItemArray){
|
||||
delete [] ItemArray;
|
||||
ItemArray=NULL;
|
||||
}
|
||||
if(sortItemArray){
|
||||
delete [] sortItemArray;
|
||||
sortItemArray=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline TPIE_OS_OFFSET Internal_Sorter_KObj<T, KEY, CMPR>::MaxItemCount(
|
||||
TPIE_OS_OFFSET memSize)
|
||||
{
|
||||
//Space available for items
|
||||
TPIE_OS_OFFSET memAvail=memSize-space_overhead();
|
||||
|
||||
if(memAvail < space_per_item() ){ return -1; }
|
||||
else{ return memAvail/space_per_item(); }
|
||||
}
|
||||
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline TPIE_OS_SIZE_T Internal_Sorter_KObj<T, KEY, CMPR>::space_overhead(void)
|
||||
{
|
||||
// Space usage independent of space_per_item
|
||||
// accounts MM_manager space overhead on "new" call
|
||||
return 2*MM_manager.space_overhead();
|
||||
}
|
||||
|
||||
template<class T, class KEY, class CMPR>
|
||||
inline TPIE_OS_SIZE_T Internal_Sorter_KObj<T, KEY, CMPR>::space_per_item(void)
|
||||
{
|
||||
return sizeof(T) + sizeof(qsort_item<KEY>);
|
||||
}
|
||||
|
||||
#endif // _INTERNAL_SORT_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// File: lib_config.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 10/31/94
|
||||
//
|
||||
// $Id: lib_config.h,v 1.4 2003/04/17 21:00:01 jan Exp $
|
||||
//
|
||||
#ifndef _LIB_CONFIG_H
|
||||
#define _LIB_CONFIG_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
// Use logs if requested.
|
||||
#if TP_LOG_LIB
|
||||
#define TPL_LOGGING 1
|
||||
#endif
|
||||
#include <tpie_log.h>
|
||||
|
||||
// Enable assertions if requested.
|
||||
#if TP_ASSERT_LIB
|
||||
#define DEBUG_ASSERTIONS 1
|
||||
#endif
|
||||
#include <tpie_assert.h>
|
||||
|
||||
|
||||
#endif // _LIB_CONFIG_H
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: logstream.cpp
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/12/94
|
||||
//
|
||||
// The logstream class, for writing to the log.
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(logstream_cpp,"$Id: logstream.cpp,v 1.20 2004/08/17 16:48:53 jan Exp $");
|
||||
|
||||
#include <logstream.h>
|
||||
|
||||
// Constructor.
|
||||
logstream::logstream(const char *fname,
|
||||
unsigned int p,
|
||||
unsigned int tp)
|
||||
#ifdef UNIFIED_LOGGING
|
||||
: ofstream(2), priority(p), threshold(tp) { log_initialized = true; }
|
||||
#else
|
||||
: ofstream(fname), priority(p), threshold(tp) { log_initialized = true; }
|
||||
#endif
|
||||
|
||||
bool logstream::log_initialized = false;
|
||||
|
||||
// Destructor.
|
||||
logstream::~logstream() {
|
||||
log_initialized = false;
|
||||
}
|
||||
|
||||
// Output operators.
|
||||
|
||||
// A macro to define a log stream output operator for a given type.
|
||||
// The type can be any type that has an ofstream output operator.
|
||||
#define _DEFINE_LOGSTREAM_OUTPUT_OPERATOR(T) \
|
||||
logstream& logstream::operator<<(const T x) \
|
||||
{ \
|
||||
if (priority <= threshold) { \
|
||||
ofstream::operator<<(x); \
|
||||
} \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
|
||||
logstream& logstream::operator<<(const char *x)
|
||||
{
|
||||
if (priority <= threshold) {
|
||||
std::operator<<((*this), x);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(char *)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(char)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(int)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(unsigned int)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(long int)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(unsigned long)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(float)
|
||||
_DEFINE_LOGSTREAM_OUTPUT_OPERATOR(double)
|
||||
|
||||
//"LONGLONG" and "long long" are different in Win32/Unix
|
||||
TPIE_OS_DEFINE_LOGSTREAM_LONGLONG
|
||||
|
||||
// Setting priority and threshold on the fly with manipulators.
|
||||
|
||||
logstream& manip_priority(logstream& tpl, unsigned long p)
|
||||
{
|
||||
tpl.priority = p;
|
||||
return tpl;
|
||||
}
|
||||
|
||||
logmanip<unsigned long> setpriority(unsigned long p)
|
||||
{
|
||||
return logmanip<unsigned long>(&manip_priority, p);
|
||||
}
|
||||
|
||||
logstream& manip_threshold(logstream& tpl, unsigned long p)
|
||||
{
|
||||
tpl.threshold = p;
|
||||
return tpl;
|
||||
}
|
||||
|
||||
logmanip<unsigned long> setthreshold(unsigned long p)
|
||||
{
|
||||
return logmanip<unsigned long>(&manip_threshold, p);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: logstream.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/12/94
|
||||
//
|
||||
// $Id: logstream.h,v 1.20 2004/08/17 16:48:14 jan Exp $
|
||||
//
|
||||
|
||||
#ifndef _LOGSTREAM_H
|
||||
#define _LOGSTREAM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// For size_t
|
||||
#include <sys/types.h>
|
||||
|
||||
// A macro for declaring output operators for log streams.
|
||||
#define _DECLARE_LOGSTREAM_OUTPUT_OPERATOR(T) logstream& operator<<(T)
|
||||
|
||||
// A log is like a regular output stream, but it also supports messages
|
||||
// at different priorities. If a message's priority is at least as high
|
||||
// as the current priority threshold, then it appears in the log.
|
||||
// Otherwise, it does not. Lower numbers have higher priority; 0 is
|
||||
// the highest. 1 is the default if not
|
||||
|
||||
class logstream : public ofstream {
|
||||
|
||||
public:
|
||||
static bool log_initialized;
|
||||
unsigned int priority;
|
||||
unsigned int threshold;
|
||||
|
||||
logstream(const char *fname, unsigned int p = 0, unsigned int tp = 0);
|
||||
~logstream();
|
||||
|
||||
// Output operators
|
||||
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const char *);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const char);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const int);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const unsigned int);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const long int);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const long unsigned int);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const float);
|
||||
_DECLARE_LOGSTREAM_OUTPUT_OPERATOR(const double);
|
||||
|
||||
// Unix "long long", Win32 "LONGLONG".
|
||||
TPIE_OS_DECLARE_LOGSTREAM_LONGLONG
|
||||
};
|
||||
|
||||
|
||||
// The logmanip template is based on the omanip template from iomanip.h
|
||||
// in the libg++ sources.
|
||||
|
||||
template <class TP> class logmanip {
|
||||
logstream& (*_f)(logstream&, TP);
|
||||
TP _a;
|
||||
public:
|
||||
logmanip(logstream& (*f)(logstream&, TP), TP a) : _f(f), _a(a) {}
|
||||
|
||||
friend logstream& operator<< (logstream& o, const logmanip<TP>& m) {
|
||||
(*m._f)(o, m._a);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
logmanip<unsigned long> setpriority(unsigned long p);
|
||||
logmanip<unsigned long> setthreshold(unsigned long p);
|
||||
|
||||
#endif // _LOGSTREAM_H
|
||||
@@ -0,0 +1,922 @@
|
||||
// Copyright (c) 1994 Darren Vengroff
|
||||
//
|
||||
// File: matrix.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 11/4/94
|
||||
//
|
||||
// $Id: matrix.h,v 1.11 2005/01/14 18:35:00 tavi Exp $
|
||||
//
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <tpie_assert.h>
|
||||
|
||||
|
||||
// Enable exceptions if the compiler supports them.
|
||||
#ifndef HANDLE_EXCEPTIONS
|
||||
#define HANDLE_EXCEPTIONS 0
|
||||
#endif
|
||||
|
||||
// References to rows and colums and submatrices.
|
||||
template<class T> class rowref;
|
||||
template<class T> class colref;
|
||||
|
||||
// Matrices and submatrices.
|
||||
template<class T> class matrix_base;
|
||||
template<class T> class matrix;
|
||||
template<class T> class submatrix;
|
||||
|
||||
// A base class for matrices and submatrices.
|
||||
template<class T> class matrix_base
|
||||
{
|
||||
protected:
|
||||
TPIE_OS_SIZE_T r,c;
|
||||
|
||||
public:
|
||||
#if HANDLE_EXCEPTIONS
|
||||
// Exception class.
|
||||
class range { };
|
||||
#endif
|
||||
|
||||
matrix_base(TPIE_OS_SIZE_T rows, TPIE_OS_SIZE_T cols);
|
||||
virtual ~matrix_base(void);
|
||||
|
||||
// What is the size of the matrix?
|
||||
TPIE_OS_SIZE_T rows(void) const;
|
||||
TPIE_OS_SIZE_T cols(void) const;
|
||||
|
||||
// Access to the contents of the matrix.
|
||||
virtual T &elt(TPIE_OS_SIZE_T row, TPIE_OS_SIZE_T col) const = 0;
|
||||
|
||||
rowref<T> row(TPIE_OS_SIZE_T row) ;
|
||||
colref<T> col(TPIE_OS_SIZE_T col) ;
|
||||
|
||||
rowref<T> operator[](TPIE_OS_SIZE_T row) ;
|
||||
|
||||
// Assignement.
|
||||
matrix_base<T> &operator=(const matrix_base<T> &rhs);
|
||||
matrix_base<T> &operator=(const rowref<T> &rhs);
|
||||
matrix_base<T> &operator=(const colref<T> &rhs);
|
||||
|
||||
// Addition in place.
|
||||
matrix_base<T> &operator+=(const matrix_base<T> &rhs);
|
||||
};
|
||||
|
||||
|
||||
// References to rows and columns.
|
||||
template<class T>
|
||||
class rowref
|
||||
{
|
||||
private:
|
||||
matrix_base<T> &m;
|
||||
TPIE_OS_SIZE_T r;
|
||||
public:
|
||||
rowref(matrix_base<T> &amatrix, TPIE_OS_SIZE_T row);
|
||||
~rowref(void);
|
||||
|
||||
T &operator[](const TPIE_OS_SIZE_T col) const;
|
||||
|
||||
friend class matrix_base<T>;
|
||||
friend class matrix<T>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class colref
|
||||
{
|
||||
private:
|
||||
matrix_base<T> &m;
|
||||
TPIE_OS_SIZE_T c;
|
||||
public:
|
||||
colref(matrix_base<T> &amatrix, TPIE_OS_SIZE_T col);
|
||||
~colref(void);
|
||||
|
||||
T &operator[](const TPIE_OS_SIZE_T col) const;
|
||||
|
||||
friend class matrix_base<T>;
|
||||
friend class matrix<T>;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix_base<T>::matrix_base(TPIE_OS_SIZE_T rows, TPIE_OS_SIZE_T cols) :
|
||||
r(rows),
|
||||
c(cols)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix_base<T>::~matrix_base(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_SIZE_T matrix_base<T>::rows(void) const
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
TPIE_OS_SIZE_T matrix_base<T>::cols(void) const
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
rowref<T> matrix_base<T>::row(TPIE_OS_SIZE_T row)
|
||||
{
|
||||
if (row >= r) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return rowref<T>(*this, row);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
colref<T> matrix_base<T>::col(TPIE_OS_SIZE_T col)
|
||||
{
|
||||
if (col >= c) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return colref<T>(*this, col);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
rowref<T> matrix_base<T>::operator[](TPIE_OS_SIZE_T row)
|
||||
{
|
||||
return this->row(row);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix_base<T> &matrix_base<T>::operator=(const matrix_base<T> &rhs)
|
||||
{
|
||||
if ((rows() != rhs.rows()) || (cols() != rhs.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
|
||||
for (ii = rows(); ii--; ) {
|
||||
for (jj = cols(); jj--; ) {
|
||||
elt(ii,jj) = rhs.elt(ii,jj);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix_base<T> &matrix_base<T>::operator=(const rowref<T> &rhs)
|
||||
{
|
||||
if ((rows() != 1) || (cols() != rhs.m.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii;
|
||||
|
||||
for (ii = cols(); ii--; ) {
|
||||
elt(0,ii) = rhs[ii];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix_base<T> &matrix_base<T>::operator=(const colref<T> &rhs)
|
||||
{
|
||||
if ((cols() != 1) || (rows() != rhs.m.rows())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii;
|
||||
T t;
|
||||
|
||||
for (ii = rows(); ii--; ) {
|
||||
t = rhs[ii];
|
||||
elt(ii,0) = t;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix_base<T> &matrix_base<T>::
|
||||
operator+=(const matrix_base<T> &rhs)
|
||||
{
|
||||
if ((rows() != rhs.rows()) || (cols() != rhs.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
|
||||
for (ii = rows(); ii--; ) {
|
||||
for (jj = cols(); jj--; ) {
|
||||
elt(ii,jj) = elt(ii,jj) + rhs.elt(ii,jj);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix<T> operator+(const matrix_base<T> &op1,
|
||||
const matrix_base<T> &op2)
|
||||
{
|
||||
if ((op1.rows() != op2.rows()) || (op1.cols() != op2.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
matrix<T> temp(op1);
|
||||
|
||||
return temp += op2;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void perform_mult_in_place(const matrix_base<T> &op1,
|
||||
const matrix_base<T> &op2,
|
||||
matrix_base<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
T t;
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = op1.rows(); ii--; ) {
|
||||
// Iterate over colums of op2.
|
||||
for (jj = op2.cols(); jj--; ) {
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
t = op1.elt(ii,op1.cols()-1) * op2.elt(op2.rows()-1,jj);
|
||||
for (kk = op2.rows() - 1; kk--; ) {
|
||||
t += op1.elt(ii,kk) * op2.elt(kk,jj);
|
||||
}
|
||||
// Assign into the result.
|
||||
res.elt(ii,jj) = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void perform_mult_add_in_place(matrix_base<T> &op1,
|
||||
matrix_base<T> &op2,
|
||||
matrix_base<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
T t;
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = op1.rows(); ii--; ) {
|
||||
// Iterate over colums of op2.
|
||||
for (jj = op2.cols(); jj--; ) {
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
t = op1.elt(ii,op1.cols()-1) * op2.elt(op2.rows()-1,jj);
|
||||
for (kk = op2.rows() - 1; kk--; ) {
|
||||
t += op1.elt(ii,kk) * op2.elt(kk,jj);
|
||||
}
|
||||
// Add into the result.
|
||||
res.elt(ii,jj) += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix<T> operator*(const matrix_base<T> &op1,
|
||||
const matrix_base<T> &op2)
|
||||
{
|
||||
if (op1.cols() != op2.rows()) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
matrix<T> temp(op1.rows(),op2.cols());
|
||||
|
||||
perform_mult_in_place(op1, op2, (matrix_base<T> &)temp);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ostream &operator<<(ostream &s, matrix_base<T> &m)
|
||||
{
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
|
||||
// Iterate over rows
|
||||
for (ii = 0; ii < m.rows(); ii++) {
|
||||
// Iterate over cols
|
||||
s << m.elt(ii,0);
|
||||
for (jj = 1; jj < m.cols(); jj++) {
|
||||
if (jj) (s << ' ');
|
||||
s << m.elt(ii,jj);
|
||||
}
|
||||
s << '\n';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// Member functions for row and column reference classes.
|
||||
|
||||
template<class T>
|
||||
rowref<T>::rowref(matrix_base<T> &amatrix, TPIE_OS_SIZE_T row) :
|
||||
m(amatrix),
|
||||
r(row)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
rowref<T>::~rowref(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T &rowref<T>::operator[](const TPIE_OS_SIZE_T col) const
|
||||
{
|
||||
return m.elt(r,col);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
colref<T>::colref(matrix_base<T> &amatrix, TPIE_OS_SIZE_T col) :
|
||||
m(amatrix),
|
||||
c(col)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
colref<T>::~colref(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T &colref<T>::operator[](const TPIE_OS_SIZE_T row) const
|
||||
{
|
||||
return m.elt(row,c);
|
||||
}
|
||||
|
||||
|
||||
// A submatrix class.
|
||||
template<class T>
|
||||
class submatrix : public matrix_base<T>
|
||||
{
|
||||
private:
|
||||
|
||||
matrix_base<T> &m;
|
||||
TPIE_OS_SIZE_T r1,r2,c1,c2;
|
||||
public:
|
||||
using matrix_base<T>::rows;
|
||||
using matrix_base<T>::cols;
|
||||
|
||||
// Construction/destruction.
|
||||
submatrix(matrix_base<T> &amatrix,
|
||||
TPIE_OS_SIZE_T row1, TPIE_OS_SIZE_T row2,
|
||||
TPIE_OS_SIZE_T col1, TPIE_OS_SIZE_T col2);
|
||||
|
||||
virtual ~submatrix(void);
|
||||
|
||||
// We need an assignement operator that copies data by explicitly
|
||||
// calling the base class's assignment operator to do elementwise
|
||||
// copying. Otherwise, m, r1, r2, c1, and c2 are just copied.
|
||||
submatrix<T> &operator=(const submatrix<T> &rhs);
|
||||
|
||||
// We also want to be able to assign from matrices.
|
||||
submatrix<T> &operator=(const matrix<T> &rhs);
|
||||
|
||||
// Access to elements.
|
||||
T& elt(TPIE_OS_SIZE_T row, TPIE_OS_SIZE_T col) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
submatrix<T>::submatrix(matrix_base<T> &amatrix,
|
||||
TPIE_OS_SIZE_T row1, TPIE_OS_SIZE_T row2,
|
||||
TPIE_OS_SIZE_T col1, TPIE_OS_SIZE_T col2) :
|
||||
matrix_base<T>(row2 - row1 + 1,
|
||||
col2 - col1 + 1),
|
||||
m(amatrix),
|
||||
r1(row1), r2(row2),
|
||||
c1(col1), c2(col2)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
submatrix<T>::~submatrix(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
submatrix<T> &submatrix<T>::operator=(const submatrix<T> &rhs)
|
||||
{
|
||||
// Call the assignement operator from the base class to do range
|
||||
// checking and elementwise assignment.
|
||||
(matrix_base<T> &)(*this) = (matrix_base<T> &)rhs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
submatrix<T> &submatrix<T>::operator=(const matrix<T> &rhs)
|
||||
{
|
||||
// Call the assignement operator from the base class to do range
|
||||
// checking and elementwise assignment.
|
||||
(matrix_base<T> &)(*this) = (matrix_base<T> &)rhs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T& submatrix<T>::elt(TPIE_OS_SIZE_T row, TPIE_OS_SIZE_T col) const
|
||||
{
|
||||
if ((row >= rows()) || (col >= cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
return m.elt(row + r1, col + c1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The matrix class itself.
|
||||
template<class T>
|
||||
class matrix : public matrix_base<T> {
|
||||
private:
|
||||
using matrix_base<T>::r;
|
||||
using matrix_base<T>::c;
|
||||
|
||||
T *data;
|
||||
public:
|
||||
using matrix_base<T>::rows;
|
||||
using matrix_base<T>::cols;
|
||||
|
||||
// Construction/destruction.
|
||||
matrix(TPIE_OS_SIZE_T arows, TPIE_OS_SIZE_T acols);
|
||||
matrix(const matrix<T> &rhs);
|
||||
matrix(const matrix_base<T> &rhs);
|
||||
matrix(const submatrix<T> &rhs);
|
||||
matrix(const rowref<T> umrr);
|
||||
matrix(const colref<T> umcr);
|
||||
|
||||
virtual ~matrix(void);
|
||||
|
||||
// We need an assignement operator that copies data by explicitly
|
||||
// calling the base class's assignment operator to do elementwise
|
||||
// copying. Otherwise, the data pointer is just copied.
|
||||
matrix<T> &operator=(const matrix<T> &rhs);
|
||||
|
||||
// We also want to be able to assign from submatrices.
|
||||
matrix<T> &operator=(const submatrix<T> &rhs);
|
||||
|
||||
// Access to elements.
|
||||
T &elt(TPIE_OS_SIZE_T row, TPIE_OS_SIZE_T col) const;
|
||||
|
||||
// Friends that need direct access to data for fast multiplication.
|
||||
// friend void quick_matrix_mult_in_place(const matrix<T> &op1,
|
||||
// const matrix<T> &op2,
|
||||
// matrix<T> &res);
|
||||
// friend void quick_matrix_mult_add_in_place(const matrix<T> &op1,
|
||||
// const matrix<T> &op2,
|
||||
// matrix<T> &res);
|
||||
// friend void aggarwal_matrix_mult_in_place(const matrix<T> &op1,
|
||||
// const matrix<T> &op2,
|
||||
// matrix<T> &res);
|
||||
// friend void aggarwal_matrix_mult_add_in_place(const matrix<T> &op1,
|
||||
// const matrix<T> &op2,
|
||||
// matrix<T> &res);
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(TPIE_OS_SIZE_T arows, TPIE_OS_SIZE_T acols) :
|
||||
matrix_base<T>(arows, acols)
|
||||
{
|
||||
data = new T[arows * acols];
|
||||
|
||||
// Initialize the contents of the matrix.
|
||||
memset(data, 0, arows * acols * sizeof(T));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(const matrix<T> &rhs) :
|
||||
matrix_base<T>(rhs.rows(), rhs.cols())
|
||||
{
|
||||
TPIE_OS_SIZE_T ii;
|
||||
|
||||
data = new T[r*c];
|
||||
|
||||
for (ii = r*c; ii--; ) {
|
||||
data[ii] = rhs.data[ii];
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(const matrix_base<T> &rhs) :
|
||||
matrix_base<T>(rhs.rows(), rhs.cols())
|
||||
{
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
|
||||
data = new T[r*c];
|
||||
|
||||
for (ii = r; ii--; ) {
|
||||
for (jj = c; jj--; ) {
|
||||
data[c*ii+jj] = ((matrix_base<T> &)rhs).elt(ii,jj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(const submatrix<T> &rhs) :
|
||||
matrix_base<T>(rhs.rows(), rhs.cols())
|
||||
{
|
||||
TPIE_OS_SIZE_T ii,jj;
|
||||
|
||||
data = new T[r*c];
|
||||
|
||||
for (ii = r; ii--; ) {
|
||||
for (jj = c; jj--; ) {
|
||||
data[c*ii+jj] = ((submatrix<T> &)rhs).elt(ii,jj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(const rowref<T> umrr) :
|
||||
matrix_base<T>(1, umrr.m.cols())
|
||||
{
|
||||
data = new T[c];
|
||||
|
||||
matrix_base<T>::operator=(umrr);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::matrix(const colref<T> umcr) :
|
||||
matrix_base<T>(umcr.m.rows(),1)
|
||||
{
|
||||
data = new T[r];
|
||||
|
||||
matrix_base<T>::operator=(umcr);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T>::~matrix(void) {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
matrix<T> &matrix<T>::operator=(const matrix<T> &rhs)
|
||||
{
|
||||
// Call the assignement operator from the base class to do range
|
||||
// checking and elementwise assignment.
|
||||
(matrix_base<T> &)(*this) = (matrix_base<T> &)rhs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
matrix<T> &matrix<T>::operator=(const submatrix<T> &rhs)
|
||||
{
|
||||
// Call the assignement operator from the base class to do range
|
||||
// checking and elementwise assignment.
|
||||
(matrix_base<T> &)(*this) = (matrix_base<T> &)rhs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
T& matrix<T>::elt(TPIE_OS_SIZE_T row, TPIE_OS_SIZE_T col) const
|
||||
{
|
||||
if ((row >= rows()) || (col >= cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
return data[row*cols()+col];
|
||||
}
|
||||
|
||||
|
||||
// These are needed since template functions accept only exact argument
|
||||
// type matches. Base class promotion is not done as it is for
|
||||
// ordinary functions.
|
||||
|
||||
#define MAT_DUMMY_OP(TM1,TM2,OP) \
|
||||
template<class T> \
|
||||
matrix<T> operator OP (const TM1 &op1, \
|
||||
const TM2 &op2) \
|
||||
{ \
|
||||
return ((matrix_base<T> &)op1) OP \
|
||||
((matrix_base<T> &)op2); \
|
||||
}
|
||||
|
||||
MAT_DUMMY_OP(matrix<T>,matrix<T>,+)
|
||||
MAT_DUMMY_OP(matrix<T>,submatrix<T>,+)
|
||||
MAT_DUMMY_OP(submatrix<T>,matrix<T>,+)
|
||||
MAT_DUMMY_OP(submatrix<T>,submatrix<T>,+)
|
||||
|
||||
MAT_DUMMY_OP(matrix<T>,matrix<T>,*)
|
||||
MAT_DUMMY_OP(matrix<T>,submatrix<T>,*)
|
||||
MAT_DUMMY_OP(submatrix<T>,matrix<T>,*)
|
||||
MAT_DUMMY_OP(submatrix<T>,submatrix<T>,*)
|
||||
|
||||
template<class T>
|
||||
ostream &operator<<(ostream &s, const matrix<T> &m)
|
||||
{
|
||||
return s << (matrix_base<T> &)m;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ostream &operator<<(ostream &s, const submatrix<T> &m)
|
||||
{
|
||||
return s << (matrix_base<T> &)m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Speedups for multiplying matrices. This is only for use with the
|
||||
// specific implementation of matrices above. General purpose
|
||||
// multiplication still has to be done with perform_mult_in_place or
|
||||
// perform_mult_add_in_place.
|
||||
|
||||
template<class T>
|
||||
void quick_matrix_mult_in_place(const matrix<T> &op1,
|
||||
const matrix<T> &op2,
|
||||
matrix<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
TPIE_OS_SIZE_T r1,r2,c1,c2,cres;
|
||||
T t;
|
||||
|
||||
r1 = op1.rows();
|
||||
r2 = op2.rows();
|
||||
c1 = op1.cols();
|
||||
c2 = op2.cols();
|
||||
cres = res.cols();
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = r1; ii--; ) {
|
||||
// Iterate over colums of op2.
|
||||
for (jj = c2; jj--; ) {
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
// t = op1.data[ii*c1+c1-1] * op2.data[(r2-1)*c2+jj];
|
||||
// // op1.elt(ii,op1.cols()-1) * op2.elt(op2.rows()-1,jj);
|
||||
t = op1.elt(ii,c1-1) * op2.elt(r2-1,jj);
|
||||
for (kk = r2 - 1; kk--; ) {
|
||||
// t += op1.data[ii*c1+kk] * op2.data[kk*c2+jj];
|
||||
// // op1.elt(ii,kk) * op2.elt(kk,jj);
|
||||
t += op1.elt(ii,kk) * op2.elt(kk,jj);
|
||||
}
|
||||
// Assign into the result.
|
||||
// res.data[ii*cres+jj] = t;
|
||||
res.elt(ii,jj) = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void quick_matrix_mult_add_in_place(const matrix<T> &op1,
|
||||
const matrix<T> &op2,
|
||||
matrix<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
TPIE_OS_SIZE_T r1,r2,c1,c2,cres;
|
||||
T t;
|
||||
|
||||
r1 = op1.rows();
|
||||
r2 = op2.rows();
|
||||
c1 = op1.cols();
|
||||
c2 = op2.cols();
|
||||
cres = res.cols();
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = r1; ii--; ) {
|
||||
// Iterate over colums of op2.
|
||||
for (jj = c2; jj--; ) {
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
// t = op1.data[ii*c1+c1-1] * op2.data[(r2-1)*c2+jj];
|
||||
// // op1.elt(ii,op1.cols()-1) * op2.elt(op2.rows()-1,jj);
|
||||
t = op1.elt(ii,c1-1) * op2.elt(r2-1,jj);
|
||||
for (kk = r2 - 1; kk--; ) {
|
||||
// t += op1.data[ii*c1+kk] * op2.data[kk*c2+jj];
|
||||
t += op1.elt(ii,kk) * op2.elt(kk,jj);
|
||||
}
|
||||
// Assign into the result.
|
||||
// res.data[ii*cres+jj] += t;
|
||||
res.elt(ii,jj) += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Aggarwal et. al.'s algorithm.
|
||||
|
||||
template<class T>
|
||||
void aggarwal_matrix_mult_in_place(const matrix<T> &op1,
|
||||
const matrix<T> &op2,
|
||||
matrix<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
TPIE_OS_SIZE_T r1,r2,c1,c2,cres;
|
||||
|
||||
r1 = op1.rows();
|
||||
r2 = op2.rows();
|
||||
c1 = op1.cols();
|
||||
c2 = op2.cols();
|
||||
cres = res.cols();
|
||||
|
||||
// Temporary results.
|
||||
|
||||
T *temp = new T[c2];
|
||||
T op1elt;
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = r1; ii--; ) {
|
||||
|
||||
// Clear out the temporary sums.
|
||||
for (jj = c2; jj--; ) {
|
||||
temp[jj] = 0;
|
||||
}
|
||||
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
for (kk = r2; kk--; ) {
|
||||
|
||||
// Iterate over columns of op2.
|
||||
// op1elt = op1.data[ii*c1+kk];
|
||||
op1elt = op1.elt(ii,kk);
|
||||
for (jj = c2; jj--; ) {
|
||||
// temp[jj] += op1elt * op2.data[kk*c2+jj];
|
||||
temp[jj] += op1elt * op2.elt(kk,jj);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the results.
|
||||
for (jj = c2; jj--; ) {
|
||||
// res.data[ii*cres+jj] = temp[jj];
|
||||
res.elt(ii,jj) = temp[jj];
|
||||
}
|
||||
}
|
||||
|
||||
delete [] temp;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void aggarwal_matrix_mult_add_in_place(const matrix<T> &op1,
|
||||
const matrix<T> &op2,
|
||||
matrix<T> &res)
|
||||
{
|
||||
if ((op1.cols() != op2.rows()) ||
|
||||
(op1.rows() != res.rows()) ||
|
||||
(op2.cols() != res.cols())) {
|
||||
#if HANDLE_EXCEPTIONS
|
||||
throw matrix_base<T>::range();
|
||||
#else
|
||||
tp_assert(0, "Range error.");
|
||||
#endif
|
||||
}
|
||||
|
||||
TPIE_OS_SIZE_T ii,jj,kk;
|
||||
TPIE_OS_SIZE_T r1,r2,c1,c2,cres;
|
||||
|
||||
r1 = op1.rows();
|
||||
r2 = op2.rows();
|
||||
c1 = op1.cols();
|
||||
c2 = op2.cols();
|
||||
cres = res.cols();
|
||||
|
||||
// Temporary results.
|
||||
|
||||
T *temp = new T[c2];
|
||||
T op1elt;
|
||||
|
||||
// Iterate over rows of op1.
|
||||
for (ii = r1; ii--; ) {
|
||||
|
||||
// Clear out the temporary sums.
|
||||
for (jj = c2; jj--; ) {
|
||||
temp[jj] = 0;
|
||||
}
|
||||
// Iterate through the row of r1 and the column of r2.
|
||||
for (kk = r2; kk--; ) {
|
||||
|
||||
// Iterate over columns of op2.
|
||||
// op1elt = op1.data[ii*c1+kk];
|
||||
op1elt = op1.elt(ii,kk);
|
||||
for (jj = c2; jj--; ) {
|
||||
// temp[jj] += op1elt * op2.data[kk*c2+jj];
|
||||
temp[jj] += op1elt * op2.elt(kk,jj);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the results.
|
||||
for (jj = c2; jj--; ) {
|
||||
// res.data[ii*cres+jj] += temp[jj];
|
||||
res.elt(ii,jj) += temp[jj];
|
||||
}
|
||||
}
|
||||
|
||||
delete [] temp;
|
||||
|
||||
}
|
||||
|
||||
#endif // MATRIX_H
|
||||
@@ -0,0 +1,254 @@
|
||||
//
|
||||
// File: mergeheap.h
|
||||
// Author: Rakesh Barve <rbarve@cs.duke.edu>
|
||||
//
|
||||
// Id: mergeheap.h,v 1.6 1999/11/23 16:49:10 tavi Exp tavi $
|
||||
|
||||
// A template useful during merge operations. Basically a heap can be
|
||||
// maintained on keys; so that the log n comparisons per item involve
|
||||
// touching an array of keys; not items. The heap is basically the
|
||||
// heap from CLR except that there is provision to exploit the fact
|
||||
// that when you are merging you know you will be inserting a new
|
||||
// element whenever you are doing a delete_min.
|
||||
//
|
||||
|
||||
#ifndef _MERGE_HEAP_H
|
||||
#define _MERGE_HEAP_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//Macros for left and right.
|
||||
#define Left(i) 2*i
|
||||
#define Right(i) 2*i+1
|
||||
#define Parent(i) i/2
|
||||
|
||||
//This is a heap element. Meant to encapsulate the key, along with
|
||||
//the label run_id indicating the run the key originates from.
|
||||
|
||||
template<class Key>
|
||||
class merge_heap_element {
|
||||
public:
|
||||
Key key;
|
||||
unsigned short run_id;
|
||||
};
|
||||
|
||||
/*
|
||||
TPIE_OS_WIN_ONLY_TEMPLATE_MERGE_HEAP_ELEMENT_COMPILER_FOOLER
|
||||
*/
|
||||
|
||||
//This is the actual heap; there is a constructor, destructor and
|
||||
//various useful public member functions.
|
||||
|
||||
template<class Key>
|
||||
class merge_heap{
|
||||
|
||||
merge_heap_element<Key> *Heaparray;
|
||||
TPIE_OS_SIZE_T Heapsize;
|
||||
void Exchange(TPIE_OS_SIZE_T i, TPIE_OS_SIZE_T j) {
|
||||
|
||||
Key tmpkey;
|
||||
unsigned short tmpid;
|
||||
|
||||
tmpkey = Heaparray[i].key;
|
||||
tmpid = Heaparray[i].run_id;
|
||||
|
||||
Heaparray[i].key = Heaparray[j].key;
|
||||
Heaparray[i].run_id = Heaparray[j].run_id;
|
||||
|
||||
Heaparray[j].key = tmpkey;
|
||||
Heaparray[j].run_id = tmpid;
|
||||
};
|
||||
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
merge_heap(merge_heap_element<Key> *array_of_elements,
|
||||
TPIE_OS_SIZE_T array_size);
|
||||
|
||||
// Destructor
|
||||
~merge_heap(void) {if (Heaparray) {delete Heaparray; Heaparray = NULL;}};
|
||||
|
||||
// Report size of Heap (number of elements)
|
||||
TPIE_OS_SIZE_T sizeofheap(void) {return Heapsize;};
|
||||
|
||||
//Delete the current minimum and insert the new item from
|
||||
//the same source / run.
|
||||
|
||||
void delete_min_and_insert(Key *nextelement_same_run){
|
||||
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else
|
||||
Heaparray[1].key = *nextelement_same_run;
|
||||
this->Heapify(1);
|
||||
};
|
||||
|
||||
// Return the minimum key.
|
||||
Key get_min_key(void) {return Heaparray[1].key;};
|
||||
|
||||
//Return the run with the minimum key.
|
||||
unsigned short get_min_run_id(void) {return Heaparray[1].run_id;};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This is the primary function; note that we have unfolded the
|
||||
// recursion.
|
||||
template<class Key>
|
||||
inline void merge_heap<Key>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(Heaparray[l].key < Heaparray[i].key)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(Heaparray[r].key < Heaparray[smallest].key))? r : smallest;
|
||||
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
|
||||
i = smallest;
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(Heaparray[l].key < Heaparray[i].key))? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(Heaparray[r].key < Heaparray[smallest].key))? r : smallest;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Constructor
|
||||
template<class Key>
|
||||
merge_heap<Key>::merge_heap(merge_heap_element<Key> *array_of_elements,
|
||||
TPIE_OS_SIZE_T size_of_array) {
|
||||
TPIE_OS_SIZE_T i;
|
||||
Heapsize = size_of_array;
|
||||
Heaparray = array_of_elements;
|
||||
for ( i = Heapsize/2; i >= 1; i--)
|
||||
this->Heapify(i);
|
||||
}
|
||||
|
||||
|
||||
template<class Key>
|
||||
class merge_heap_cmp {
|
||||
|
||||
class merge_heap_element<Key> *Heaparray;
|
||||
int (*cmp)(const Key&, const Key&);
|
||||
TPIE_OS_SIZE_T Heapsize;
|
||||
|
||||
void Exchange(TPIE_OS_SIZE_T i, TPIE_OS_SIZE_T j){
|
||||
|
||||
Key tmpkey;
|
||||
unsigned short tmpid;
|
||||
|
||||
tmpkey = Heaparray[i].key;
|
||||
tmpid = Heaparray[i].run_id;
|
||||
|
||||
Heaparray[i].key = Heaparray[j].key;
|
||||
Heaparray[i].run_id = Heaparray[j].run_id;
|
||||
|
||||
Heaparray[j].key = tmpkey;
|
||||
Heaparray[j].run_id = tmpid;
|
||||
};
|
||||
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
merge_heap_cmp(class merge_heap_element<Key> *array_of_elements,
|
||||
TPIE_OS_SIZE_T array_size, int (*comp_fun)(const Key&, const Key&));
|
||||
|
||||
// Destructor
|
||||
~merge_heap_cmp(void) {if (Heaparray) {delete Heaparray; Heaparray = NULL;}};
|
||||
|
||||
// Report size of Heap (number of elements)
|
||||
TPIE_OS_SIZE_T sizeofheap(void) {return Heapsize;};
|
||||
|
||||
// Delete the current minimum and insert the new item from
|
||||
// the same source / run.
|
||||
|
||||
void delete_min_and_insert(Key *nextelement_same_run) {
|
||||
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else Heaparray[1].key = *nextelement_same_run;
|
||||
this->Heapify(1);
|
||||
};
|
||||
|
||||
//Return the minimum key.
|
||||
Key get_min_key(void) {return Heaparray[1].key;};
|
||||
|
||||
//Return the run with the minimum key.
|
||||
unsigned short get_min_run_id(void) {return Heaparray[1].run_id;};
|
||||
};
|
||||
|
||||
|
||||
// This is the primary function; note that we have unfolded the
|
||||
// recursion.
|
||||
template<class Key>
|
||||
inline void merge_heap_cmp<Key>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) && (cmp(Heaparray[l].key,Heaparray[i].key)< 0)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(cmp(Heaparray[r].key,Heaparray[smallest].key)<0))? r : smallest;
|
||||
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
|
||||
i = smallest;
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(cmp(Heaparray[l].key,Heaparray[i].key)<0))? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(cmp(Heaparray[r].key,Heaparray[smallest].key)<0))? r : smallest;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor
|
||||
template<class Key>
|
||||
merge_heap_cmp<Key>::merge_heap_cmp(class merge_heap_element<Key> *array_of_elements,
|
||||
TPIE_OS_SIZE_T size_of_array,
|
||||
int (*comp_fun)(const Key&, const Key&)) {
|
||||
TPIE_OS_SIZE_T i;
|
||||
Heapsize = size_of_array;
|
||||
Heaparray = array_of_elements;
|
||||
cmp = comp_fun;
|
||||
|
||||
for ( i = Heapsize/2; i >= 1; i--)
|
||||
this->Heapify(i);
|
||||
}
|
||||
|
||||
|
||||
#undef Left
|
||||
#undef Right
|
||||
#undef Parent
|
||||
#endif // _MERGE_HEAP_H
|
||||
@@ -0,0 +1,827 @@
|
||||
//
|
||||
// File: mergeheap_dh.h
|
||||
//
|
||||
// $Id: mergeheap_dh.h,v 1.9 2005/08/24 19:32:38 adanner Exp $
|
||||
|
||||
// This file contains several merge heap templates.
|
||||
// Originally written by Rakesh Barve.
|
||||
|
||||
// The heap is basically the heap from CLR except that there is
|
||||
// provision to exploit the fact that when you are merging you know
|
||||
// you will be inserting a new element whenever you are doing a
|
||||
// delete_min.
|
||||
|
||||
// Modified by David Hutchinson 2000 03 02
|
||||
|
||||
// - main purpose of the mods is to allow the merge heap to be
|
||||
// part of a sort management object. The sort management object
|
||||
// contains several procedures and data structures needed for
|
||||
// sorting, but the precise versions of these procedures and data
|
||||
// structures depend on the sorting approach used (this permits
|
||||
// parameterization of the sorting procedure via the sort
|
||||
// management object, and avoids having multiple versions of large
|
||||
// pieces of code that are highly redundant and difficult to
|
||||
// maintain).
|
||||
|
||||
// - move initialization from constructor to an explicit
|
||||
// "initialize" member function
|
||||
|
||||
// - add a "comparison object" version of the merge heap
|
||||
// object. This allows a comparison object with a "compare" member
|
||||
// function to be specified for comparing keys. "Comparison
|
||||
// operator" and "comparison function" versions previously
|
||||
// existed.
|
||||
|
||||
// - add a set of three (comparison object, operator and function)
|
||||
// versions of the merge heap that maintain pointers to the
|
||||
// current records at the head of the streams being merged. The
|
||||
// previous versions kept the entire corresponding record in the heap.
|
||||
|
||||
#ifndef _MERGE_HEAP_DH_H
|
||||
#define _MERGE_HEAP_DH_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Macros for left and right.
|
||||
#define Left(i) 2*(i)
|
||||
#define Right(i) 2*(i)+1
|
||||
#define Parent(i) (i)/2
|
||||
|
||||
// This is a heap element. Encapsulates the key, along with
|
||||
// the label run_id indicating the run the key originates from.
|
||||
|
||||
template<class KEY>
|
||||
class heap_element {
|
||||
public:
|
||||
heap_element(){};
|
||||
KEY key;
|
||||
TPIE_OS_SIZE_T run_id;
|
||||
};
|
||||
|
||||
// This is a record pointer element. Encapsulates the record pointer,
|
||||
// along with the label run_id indicating the run the record
|
||||
// originates from.
|
||||
|
||||
template<class REC>
|
||||
class heap_ptr {
|
||||
public:
|
||||
heap_ptr(){};
|
||||
~heap_ptr(){};
|
||||
REC *recptr;
|
||||
TPIE_OS_SIZE_T run_id;
|
||||
};
|
||||
|
||||
// ********************************************************************
|
||||
// * A record pointer heap base class - also serves as the full *
|
||||
// * implementation for objects with a < comparison operator *
|
||||
// ********************************************************************
|
||||
|
||||
template<class REC>
|
||||
class merge_heap_pdh_op{
|
||||
|
||||
protected:
|
||||
|
||||
heap_ptr<REC> *Heaparray;
|
||||
TPIE_OS_SIZE_T Heapsize;
|
||||
TPIE_OS_SIZE_T maxHeapsize;
|
||||
|
||||
inline void Exchange(TPIE_OS_SIZE_T i, TPIE_OS_SIZE_T j);
|
||||
|
||||
//These functions will typically be overridden by subclasses
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor/Destructor
|
||||
merge_heap_pdh_op() { Heaparray=NULL; };
|
||||
~merge_heap_pdh_op() {
|
||||
//Cleanup if someone forgot de-allocate
|
||||
//(abd) This seems to cause double free errors, but I don't know why
|
||||
//This was just a safeguard anyways, turn off for now
|
||||
//if(Heaparray != NULL){delete [] Heaparray;}
|
||||
}
|
||||
|
||||
// Report size of Heap (number of elements)
|
||||
TPIE_OS_SIZE_T sizeofheap(void) {return Heapsize;};
|
||||
|
||||
// Return the run with the minimum key.
|
||||
inline TPIE_OS_SIZE_T get_min_run_id(void) {return Heaparray[1].run_id;};
|
||||
|
||||
void allocate (TPIE_OS_SIZE_T size);
|
||||
void insert (REC *ptr, TPIE_OS_SIZE_T run_id);
|
||||
void deallocate (void);
|
||||
|
||||
// heapify's an initial array of elements
|
||||
// typically overridden in sub class.
|
||||
void initialize (void);
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
|
||||
// Return main memory space usage per item
|
||||
inline TPIE_OS_SIZE_T space_per_item(void) { return sizeof(heap_ptr<REC>); }
|
||||
|
||||
// Return fixed main memory space overhead, regardless of item count
|
||||
inline TPIE_OS_SIZE_T space_overhead(void) {
|
||||
// One extra array item is defined to make heap indexing easier
|
||||
return sizeof(heap_ptr<REC>)+MM_manager.space_overhead();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::Exchange(TPIE_OS_SIZE_T i,
|
||||
TPIE_OS_SIZE_T j)
|
||||
{
|
||||
REC* tmpptr;
|
||||
TPIE_OS_SIZE_T tmpid;
|
||||
tmpptr = Heaparray[i].recptr;
|
||||
tmpid = Heaparray[i].run_id;
|
||||
Heaparray[i].recptr = Heaparray[j].recptr;
|
||||
Heaparray[i].run_id = Heaparray[j].run_id;
|
||||
Heaparray[j].recptr = tmpptr;
|
||||
Heaparray[j].run_id = tmpid;
|
||||
}
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC>
|
||||
inline TPIE_OS_SIZE_T merge_heap_pdh_op<REC>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(*Heaparray[l].recptr < *Heaparray[i].recptr)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(*Heaparray[r].recptr < *Heaparray[smallest].recptr))? r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
// This is the primary function; note that we have unfolded the
|
||||
// recursion.
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
|
||||
TPIE_OS_SIZE_T smallest = get_smallest(i);
|
||||
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].recptr = Heaparray[Heapsize].recptr;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
Heaparray[1].recptr = nextelement_same_run;
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
// Allocate space for the heap
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::allocate ( TPIE_OS_SIZE_T size ) {
|
||||
Heaparray = new heap_ptr<REC> [size+1];
|
||||
Heapsize = 0;
|
||||
maxHeapsize = size;
|
||||
}
|
||||
|
||||
// Copy an (initial) element into the heap array
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::insert (REC *ptr, TPIE_OS_SIZE_T run_id)
|
||||
{
|
||||
Heaparray[Heapsize+1].recptr = ptr;
|
||||
Heaparray[Heapsize+1].run_id = run_id;
|
||||
Heapsize++;
|
||||
}
|
||||
|
||||
// Deallocate the space used by the heap
|
||||
template<class REC>
|
||||
inline void merge_heap_pdh_op<REC>::deallocate () {
|
||||
if (Heaparray){
|
||||
delete [] Heaparray;
|
||||
Heaparray=NULL;
|
||||
}
|
||||
Heapsize = 0;
|
||||
maxHeapsize = 0;
|
||||
}
|
||||
|
||||
template<class REC>
|
||||
void merge_heap_pdh_op<REC>::initialize () {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--){ Heapify(i); }
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
// * A record pointer heap that uses a comparison object *
|
||||
// ********************************************************************
|
||||
|
||||
template<class REC, class CMPR>
|
||||
class merge_heap_pdh_obj: public merge_heap_pdh_op<REC>{
|
||||
|
||||
protected:
|
||||
|
||||
using merge_heap_pdh_op<REC>::Heapsize;
|
||||
using merge_heap_pdh_op<REC>::Heaparray;
|
||||
using merge_heap_pdh_op<REC>::maxHeapsize;
|
||||
CMPR* cmp;
|
||||
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
|
||||
public:
|
||||
using merge_heap_pdh_op<REC>::sizeofheap;
|
||||
|
||||
// Constructor initializes a pointer to the user's comparison object
|
||||
// The object may contain dynamic data although the 'compare' method is const
|
||||
// and therefore inline'able.
|
||||
merge_heap_pdh_obj ( CMPR *cmptr ) : cmp(cmptr) {};
|
||||
~merge_heap_pdh_obj(){};
|
||||
|
||||
void initialize (void);
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
};
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC, class CMPR>
|
||||
inline TPIE_OS_SIZE_T merge_heap_pdh_obj<REC,CMPR>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(cmp->compare(*Heaparray[l].recptr,*Heaparray[i].recptr)< 0)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(cmp->compare(*Heaparray[r].recptr,*Heaparray[smallest].recptr)<0))?
|
||||
r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
template<class REC, class CMPR>
|
||||
inline void merge_heap_pdh_obj<REC, CMPR>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
TPIE_OS_SIZE_T smallest = get_smallest(i);
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC, class CMPR>
|
||||
inline void merge_heap_pdh_obj<REC, CMPR>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].recptr = Heaparray[Heapsize].recptr;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
Heaparray[1].recptr = nextelement_same_run;
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
|
||||
template<class REC, class CMPR>
|
||||
void merge_heap_pdh_obj<REC, CMPR>::initialize () {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--){ Heapify(i); }
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
// * A merge heap object base class - also serves as the full *
|
||||
// * implementation for objects with a < comparison operator *
|
||||
// ********************************************************************
|
||||
|
||||
template<class REC>
|
||||
class merge_heap_dh_op{
|
||||
|
||||
protected:
|
||||
|
||||
heap_element<REC> *Heaparray;
|
||||
TPIE_OS_SIZE_T Heapsize;
|
||||
TPIE_OS_SIZE_T maxHeapsize;
|
||||
|
||||
inline void Exchange(TPIE_OS_SIZE_T i, TPIE_OS_SIZE_T j);
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
//This function will typically be overridden by subclasses
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor/Destructor
|
||||
merge_heap_dh_op() { Heaparray=NULL; };
|
||||
~merge_heap_dh_op() {
|
||||
//Cleanup if someone forgot de-allocate
|
||||
//(abd) This seems to cause double free errors, but I don't know why
|
||||
//This was just a safeguard anyways, turn off for now
|
||||
//if(Heaparray != NULL){delete [] Heaparray;}
|
||||
}
|
||||
|
||||
// Report size of Heap (number of elements)
|
||||
TPIE_OS_SIZE_T sizeofheap(void) {return Heapsize;};
|
||||
|
||||
// Return the run with the minimum key.
|
||||
inline TPIE_OS_SIZE_T get_min_run_id(void) {return Heaparray[1].run_id;};
|
||||
|
||||
void allocate (TPIE_OS_SIZE_T size);
|
||||
void insert (REC *ptr, TPIE_OS_SIZE_T run_id);
|
||||
void deallocate (void);
|
||||
|
||||
// heapify's an initial array of elements
|
||||
void initialize (void);
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
|
||||
// Return main memory space usage per item
|
||||
inline TPIE_OS_SIZE_T space_per_item(void) {
|
||||
return sizeof(heap_element<REC>);
|
||||
}
|
||||
|
||||
// Return fixed main memory space overhead, regardless of item count
|
||||
inline TPIE_OS_SIZE_T space_overhead(void) {
|
||||
// One extra array item is defined to make heap indexing easier
|
||||
return sizeof(heap_element<REC>)+MM_manager.space_overhead();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::Exchange(TPIE_OS_SIZE_T i,
|
||||
TPIE_OS_SIZE_T j)
|
||||
{
|
||||
REC tmpkey;
|
||||
TPIE_OS_SIZE_T tmpid;
|
||||
tmpkey = Heaparray[i].key;
|
||||
tmpid = Heaparray[i].run_id;
|
||||
Heaparray[i].key = Heaparray[j].key;
|
||||
Heaparray[i].run_id = Heaparray[j].run_id;
|
||||
Heaparray[j].key = tmpkey;
|
||||
Heaparray[j].run_id = tmpid;
|
||||
}
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC>
|
||||
inline TPIE_OS_SIZE_T merge_heap_dh_op<REC>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(Heaparray[l].key < Heaparray[i].key)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(Heaparray[r].key < Heaparray[smallest].key))? r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
// This is the primary function; note that we have unfolded the
|
||||
// recursion.
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
|
||||
TPIE_OS_SIZE_T smallest = get_smallest(i);
|
||||
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
Heaparray[1].key = *nextelement_same_run;
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
// Allocate space for the heap
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::allocate ( TPIE_OS_SIZE_T size ) {
|
||||
Heaparray = new heap_element<REC> [size+1];
|
||||
Heapsize = 0;
|
||||
maxHeapsize = size;
|
||||
}
|
||||
|
||||
// Copy an (initial) element into the heap array
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::insert (REC *ptr, TPIE_OS_SIZE_T run_id)
|
||||
{
|
||||
Heaparray[Heapsize+1].key = *ptr;
|
||||
Heaparray[Heapsize+1].run_id = run_id;
|
||||
Heapsize++;
|
||||
}
|
||||
|
||||
// Deallocate the space used by the heap
|
||||
template<class REC>
|
||||
inline void merge_heap_dh_op<REC>::deallocate () {
|
||||
if (Heaparray){
|
||||
delete [] Heaparray;
|
||||
Heaparray=NULL;
|
||||
}
|
||||
Heapsize = 0;
|
||||
maxHeapsize = 0;
|
||||
};
|
||||
|
||||
template<class REC>
|
||||
void merge_heap_dh_op<REC>::initialize () {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--){ Heapify(i); }
|
||||
}
|
||||
|
||||
|
||||
// ********************************************************************
|
||||
// * A merge heap that uses a comparison object *
|
||||
// ********************************************************************
|
||||
|
||||
template<class REC, class CMPR>
|
||||
class merge_heap_dh_obj: public merge_heap_dh_op<REC>{
|
||||
|
||||
protected:
|
||||
using merge_heap_dh_op<REC>::Heapsize;
|
||||
using merge_heap_dh_op<REC>::Heaparray;
|
||||
using merge_heap_dh_op<REC>::maxHeapsize;
|
||||
CMPR* cmp;
|
||||
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
public:
|
||||
using merge_heap_dh_op<REC>::sizeofheap;
|
||||
|
||||
// Constructor initializes a pointer to the user's comparison object
|
||||
// The object may contain dynamic data although the 'compare' method is const
|
||||
// and therefore inline'able.
|
||||
merge_heap_dh_obj ( CMPR *cmptr ) : cmp(cmptr) {};
|
||||
~merge_heap_dh_obj(){};
|
||||
|
||||
// heapify's an initial array of elements
|
||||
void initialize (void);
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
};
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC, class CMPR>
|
||||
inline TPIE_OS_SIZE_T merge_heap_dh_obj<REC,CMPR>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(cmp->compare(Heaparray[l].key,Heaparray[i].key)< 0)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(cmp->compare(Heaparray[r].key,Heaparray[smallest].key)<0))?
|
||||
r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
template<class REC, class CMPR>
|
||||
inline void merge_heap_dh_obj<REC, CMPR>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
TPIE_OS_SIZE_T smallest = get_smallest(i);
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC, class CMPR>
|
||||
inline void merge_heap_dh_obj<REC, CMPR>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
Heaparray[1].key = *nextelement_same_run;
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
|
||||
template<class REC, class CMPR>
|
||||
void merge_heap_dh_obj<REC, CMPR>::initialize () {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--){ Heapify(i); }
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
// * A merge heap key-object base class *
|
||||
// * Also serves as a full impelementation of a *
|
||||
// * key-merge heap that uses a comparison operator < *
|
||||
// ********************************************************************
|
||||
|
||||
// The merge_heap_dh_kop object maintains only the keys in its heap,
|
||||
// and uses the member function "copy" of the user-provided class CMPR
|
||||
// to copy these keys from each record.
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
class merge_heap_dh_kop{
|
||||
|
||||
protected:
|
||||
|
||||
heap_element<KEY> *Heaparray;
|
||||
TPIE_OS_SIZE_T Heapsize;
|
||||
TPIE_OS_SIZE_T maxHeapsize;
|
||||
inline void Exchange(TPIE_OS_SIZE_T i, TPIE_OS_SIZE_T j);
|
||||
inline void Heapify(TPIE_OS_SIZE_T i);
|
||||
//This function will typically be overridden by subclasses
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
CMPR *UsrObject;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor/Destructor
|
||||
merge_heap_dh_kop( CMPR* cmpptr) : UsrObject(cmpptr), Heaparray(NULL) {};
|
||||
~merge_heap_dh_kop() {
|
||||
//Cleanup if someone forgot de-allocate
|
||||
//(abd) This seems to cause double free errors, but I don't know why
|
||||
//This was just a safeguard anyways, turn off for now
|
||||
//if(Heaparray != NULL){delete [] Heaparray;}
|
||||
}
|
||||
|
||||
// Report size of Heap (number of elements)
|
||||
TPIE_OS_SIZE_T sizeofheap(void) {return Heapsize;};
|
||||
|
||||
// Return the run with the minimum key.
|
||||
inline TPIE_OS_SIZE_T get_min_run_id(void) {return Heaparray[1].run_id;};
|
||||
|
||||
void allocate (TPIE_OS_SIZE_T size);
|
||||
void insert (REC *ptr, TPIE_OS_SIZE_T run_id);
|
||||
void deallocate ();
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
|
||||
// Return main memory space usage per item
|
||||
inline TPIE_OS_SIZE_T space_per_item(void) {
|
||||
return sizeof(heap_element<REC>);
|
||||
}
|
||||
|
||||
// Return fixed main memory space overhead, regardless of item count
|
||||
inline TPIE_OS_SIZE_T space_overhead(void) {
|
||||
// One extra array item is defined to make heap indexing easier
|
||||
return sizeof(heap_ptr<REC>)+MM_manager.space_overhead();
|
||||
}
|
||||
|
||||
// heapify's an initial array of elements
|
||||
void initialize (void);
|
||||
|
||||
};
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::Exchange(TPIE_OS_SIZE_T i,
|
||||
TPIE_OS_SIZE_T j)
|
||||
{
|
||||
KEY tmpkey;
|
||||
TPIE_OS_SIZE_T tmpid;
|
||||
tmpkey = Heaparray[i].key;
|
||||
tmpid = Heaparray[i].run_id;
|
||||
Heaparray[i].key = Heaparray[j].key;
|
||||
Heaparray[i].run_id = Heaparray[j].run_id;
|
||||
Heaparray[j].key = tmpkey;
|
||||
Heaparray[j].run_id = tmpid;
|
||||
}
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
UsrObject->copy(&Heaparray[1].key, *nextelement_same_run);
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
// Allocate space for the heap
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::allocate ( TPIE_OS_SIZE_T size ) {
|
||||
Heaparray = new heap_element<KEY> [size+1];
|
||||
Heapsize = 0;
|
||||
maxHeapsize = size;
|
||||
}
|
||||
|
||||
// Copy an (initial) element into the heap array
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::insert (REC *ptr,
|
||||
TPIE_OS_SIZE_T run_id)
|
||||
{
|
||||
UsrObject->copy(&Heaparray[Heapsize+1].key, *ptr);
|
||||
Heaparray[Heapsize+1].run_id = run_id;
|
||||
Heapsize++;
|
||||
}
|
||||
|
||||
// Deallocate the space used by the heap
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::deallocate () {
|
||||
if (Heaparray){
|
||||
delete [] Heaparray;
|
||||
Heaparray=NULL;
|
||||
}
|
||||
Heapsize = 0;
|
||||
maxHeapsize = 0;
|
||||
};
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline TPIE_OS_SIZE_T merge_heap_dh_kop<REC,KEY,CMPR>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(Heaparray[l].key < Heaparray[i].key)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(Heaparray[r].key < Heaparray[smallest].key))? r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
// This is the primary function; note that we have unfolded the
|
||||
// recursion.
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kop<REC,KEY,CMPR>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
|
||||
TPIE_OS_SIZE_T smallest=get_smallest(i);
|
||||
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
void merge_heap_dh_kop<REC,KEY,CMPR>::initialize ( ) {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--)
|
||||
this->Heapify(i);
|
||||
}
|
||||
|
||||
// ********************************************************************
|
||||
// * A key-merge heap that uses a comparison object *
|
||||
// ********************************************************************
|
||||
|
||||
// The merge_heap_dh_kobj object maintains only the keys in its heap,
|
||||
// and uses the member function "copy" of the user-provided class CMPR
|
||||
// to copy these keys from each record. It uses the member function
|
||||
// "compare" of the user-provided class CMPR to determine the relative
|
||||
// order of two such keys in the sort order.
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
class merge_heap_dh_kobj: public merge_heap_dh_kop<REC,KEY,CMPR>{
|
||||
|
||||
protected:
|
||||
|
||||
using merge_heap_dh_kop<REC,KEY,CMPR>::Heapsize;
|
||||
using merge_heap_dh_kop<REC,KEY,CMPR>::Heaparray;
|
||||
using merge_heap_dh_kop<REC,KEY,CMPR>::maxHeapsize;
|
||||
using merge_heap_dh_kop<REC,KEY,CMPR>::UsrObject;
|
||||
|
||||
inline TPIE_OS_SIZE_T get_smallest(TPIE_OS_SIZE_T i);
|
||||
|
||||
inline void Heapify(TPIE_OS_SIZE_T);
|
||||
public:
|
||||
using merge_heap_dh_kop<REC,KEY,CMPR>::sizeofheap;
|
||||
|
||||
// Constructor initializes a pointer to the user's comparison object
|
||||
// The object may contain dynamic data although the 'compare' method is const
|
||||
// and therefore inline'able.
|
||||
merge_heap_dh_kobj ( CMPR *cmptr ) :
|
||||
merge_heap_dh_kop<REC, KEY, CMPR>(cmptr){};
|
||||
~merge_heap_dh_kobj(){};
|
||||
|
||||
// heapify's an initial array of elements
|
||||
void initialize (void);
|
||||
|
||||
// Delete the current minimum and insert the new item from the same
|
||||
// source / run.
|
||||
inline void delete_min_and_insert(REC *nextelement_same_run);
|
||||
|
||||
};
|
||||
|
||||
//Returns the index of the smallest element out of
|
||||
//i, the left child of i, and the right child of i
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline TPIE_OS_SIZE_T merge_heap_dh_kobj<REC,KEY,CMPR>::get_smallest(
|
||||
TPIE_OS_SIZE_T i)
|
||||
{
|
||||
TPIE_OS_SIZE_T l,r, smallest;
|
||||
|
||||
l = Left(i);
|
||||
r = Right(i);
|
||||
|
||||
smallest = ((l <= Heapsize) &&
|
||||
(UsrObject->compare(Heaparray[l].key,Heaparray[i].key)<0)) ? l : i;
|
||||
|
||||
smallest = ((r <= Heapsize) &&
|
||||
(UsrObject->compare(Heaparray[r].key,Heaparray[smallest].key)<0)) ?
|
||||
r : smallest;
|
||||
|
||||
return smallest;
|
||||
}
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kobj<REC, KEY, CMPR>::Heapify(TPIE_OS_SIZE_T i) {
|
||||
TPIE_OS_SIZE_T smallest = get_smallest(i);
|
||||
while (smallest != i) {
|
||||
this->Exchange(i,smallest);
|
||||
i = smallest;
|
||||
smallest = get_smallest(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
inline void merge_heap_dh_kobj<REC,KEY,CMPR>::delete_min_and_insert
|
||||
(REC *nextelement_same_run)
|
||||
{
|
||||
if (nextelement_same_run == NULL) {
|
||||
Heaparray[1].key = Heaparray[Heapsize].key;
|
||||
Heaparray[1].run_id = Heaparray[Heapsize].run_id;
|
||||
Heapsize--;
|
||||
} else {
|
||||
UsrObject->copy(&Heaparray[1].key, *nextelement_same_run);
|
||||
}
|
||||
Heapify(1);
|
||||
}
|
||||
|
||||
template<class REC, class KEY, class CMPR>
|
||||
void merge_heap_dh_kobj<REC, KEY, CMPR>::initialize () {
|
||||
for ( TPIE_OS_SIZE_T i = Heapsize/2; i >= 1; i--){ Heapify(i); }
|
||||
}
|
||||
|
||||
|
||||
#undef Left
|
||||
#undef Right
|
||||
#undef Parent
|
||||
|
||||
/*
|
||||
DEPRECATED: comparision function heaps
|
||||
Earlier TPIE versions allowed a heap that uses C-style
|
||||
comparison functions. However, comparison functions cannot be
|
||||
inlined, so each comparison requires one function call. Given that the
|
||||
comparison operator < and comparison object classes can be inlined and
|
||||
have better performance while providing the exact same functionality,
|
||||
comparison functions have been removed from TPIE. If you can provide us
|
||||
with a compelling argument on why they should be in here, we may consider
|
||||
adding them again, but you must demonstrate that comparision functions
|
||||
can outperform other methods in at least some cases or give an example
|
||||
were it is impossible to use a comparison operator or comparison object
|
||||
*/
|
||||
|
||||
#endif // _MERGE_HEAP_DH_H
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: mm.h (plus contents from mm_imps.h, now deprecated)
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/30/94
|
||||
//
|
||||
// $Id: mm.h,v 1.3 2003/04/17 19:38:28 jan Exp $
|
||||
//
|
||||
#ifndef _MM_H
|
||||
#define _MM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// Get the base class, enums, etc...
|
||||
#include <mm_base.h>
|
||||
|
||||
// Get an implementation definition
|
||||
|
||||
// For now only single address space memory management is supported.
|
||||
#ifdef MM_IMP_REGISTER
|
||||
#include <mm_register.h>
|
||||
#else
|
||||
#error No MM implementation selected.
|
||||
#endif
|
||||
|
||||
#endif // _MM_H
|
||||
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: mm_base.cpp
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 9/2/94
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(mm_base_cpp,"$Id: mm_base.cpp,v 1.29 2004/10/27 19:13:54 adanner Exp $");
|
||||
|
||||
#include "lib_config.h"
|
||||
#include <mm_base.h>
|
||||
#include <tpie_log.h>
|
||||
#include <mm_register.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
// support for dmalloc (for tracking memory leaks)
|
||||
#ifdef USE_DMALLOC
|
||||
#define DMALLOC_DISABLE
|
||||
#include <dmalloc.h>
|
||||
#include <return.h>
|
||||
#endif
|
||||
|
||||
#ifdef MM_BACKWARD_COMPATIBLE
|
||||
int register_new = MM_IGNORE_MEMORY_EXCEEDED;
|
||||
#endif
|
||||
|
||||
// SIZE_SPACE is to ensure alignment on quad word boundaries. It may be
|
||||
// possible to check whether a machine needs this at configuration
|
||||
// time or if dword alignment is ok. On the HP 9000, bus errors occur
|
||||
// when loading doubles that are not qword aligned.
|
||||
static const TPIE_OS_SIZE_T SIZE_SPACE=(sizeof(TPIE_OS_SIZE_T) > 8 ? sizeof(TPIE_OS_SIZE_T) : 8);
|
||||
|
||||
void *operator new (TPIE_OS_SIZE_T sz)
|
||||
{
|
||||
void *p;
|
||||
#ifdef USE_DMALLOC
|
||||
char *file;
|
||||
GET_RET_ADDR(file);
|
||||
#endif
|
||||
|
||||
if ((MM_manager.register_new != MM_IGNORE_MEMORY_EXCEEDED)
|
||||
&& (MM_manager.register_allocation (sz + SIZE_SPACE) !=
|
||||
MM_ERROR_NO_ERROR)) {
|
||||
switch(MM_manager.register_new) {
|
||||
case MM_ABORT_ON_MEMORY_EXCEEDED:
|
||||
TP_LOG_FATAL_ID ("In operator new() - allocation request \"");
|
||||
TP_LOG_FATAL ((TPIE_OS_LONG)(sz + SIZE_SPACE));
|
||||
TP_LOG_FATAL ("\" plus previous allocation \"");
|
||||
TP_LOG_FATAL ((TPIE_OS_LONG)(MM_manager.memory_used () - (sz + SIZE_SPACE)));
|
||||
TP_LOG_FATAL ("\" exceeds user-defined limit \"");
|
||||
TP_LOG_FATAL ((TPIE_OS_LONG)(MM_manager.memory_limit ()));
|
||||
TP_LOG_FATAL ("\" \n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
cerr << "memory manager: memory allocation limit " <<
|
||||
(TPIE_OS_LONG)MM_manager.memory_limit () << " exceeded "
|
||||
<< "while allocating " << (TPIE_OS_LONG)sz << " bytes" << "\n";
|
||||
#ifdef USE_DMALLOC
|
||||
dmalloc_shutdown();
|
||||
#endif
|
||||
assert (0); // core dump if debugging
|
||||
exit (1);
|
||||
break;
|
||||
case MM_WARN_ON_MEMORY_EXCEEDED:
|
||||
TP_LOG_WARNING_ID ("In operator new() - allocation request \"");
|
||||
TP_LOG_WARNING ((TPIE_OS_LONG)(sz + SIZE_SPACE));
|
||||
TP_LOG_WARNING ("\" plus previous allocation \"");
|
||||
TP_LOG_WARNING ((TPIE_OS_LONG)(MM_manager.memory_used () - (sz + SIZE_SPACE)));
|
||||
TP_LOG_WARNING ("\" exceeds user-defined limit \"");
|
||||
TP_LOG_WARNING ((TPIE_OS_LONG)(MM_manager.memory_limit ()));
|
||||
TP_LOG_WARNING ("\" \n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
cerr << "memory manager: memory allocation limit " <<
|
||||
(TPIE_OS_LONG)MM_manager.memory_limit () << " exceeded "
|
||||
<< "while allocating " << (TPIE_OS_LONG)sz << " bytes" << "\n";
|
||||
break;
|
||||
case MM_IGNORE_MEMORY_EXCEEDED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_DMALLOC
|
||||
p = _malloc_leap(file, 0, sz + SIZE_SPACE);
|
||||
#else
|
||||
p = malloc(sz + SIZE_SPACE);
|
||||
#endif
|
||||
if (!p) {
|
||||
TP_LOG_FATAL_ID ("Out of memory. Cannot continue.");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
cerr << "out of memory while allocating " << (TPIE_OS_LONG)sz << " bytes" << "\n";
|
||||
perror ("mm_base::new malloc");
|
||||
assert(0);
|
||||
exit (1);
|
||||
}
|
||||
*((size_t *) p) = sz;
|
||||
return ((char *) p) + SIZE_SPACE;
|
||||
}
|
||||
|
||||
void operator delete (void *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
TP_LOG_WARNING_ID ("operator delete was given a NULL pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MM_manager.register_new != MM_IGNORE_MEMORY_EXCEEDED) {
|
||||
if (MM_manager.register_deallocation (
|
||||
(TPIE_OS_SIZE_T)*((size_t *) (((char *) ptr) - SIZE_SPACE)) + SIZE_SPACE)
|
||||
!= MM_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("In operator delete - MM_manager.register_deallocation failed");
|
||||
}
|
||||
}
|
||||
void *p = ((char *)ptr) - SIZE_SPACE;
|
||||
|
||||
#ifdef USE_DMALLOC
|
||||
char *file;
|
||||
GET_RET_ADDR(file);
|
||||
_free_leap(file, 0, p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator delete[] (void *ptr) {
|
||||
if (!ptr) {
|
||||
TP_LOG_WARNING_ID ("operator delete [] was given a NULL pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MM_manager.register_new != MM_IGNORE_MEMORY_EXCEEDED) {
|
||||
if (MM_manager.register_deallocation (
|
||||
(TPIE_OS_SIZE_T)*((size_t *) (((char *) ptr) - SIZE_SPACE)) + SIZE_SPACE)
|
||||
!= MM_ERROR_NO_ERROR) {
|
||||
TP_LOG_WARNING_ID("In operator delete [] - MM_manager.register_deallocation failed");
|
||||
}
|
||||
}
|
||||
void *p = ((char *)ptr) - SIZE_SPACE;
|
||||
#ifdef USE_DMALLOC
|
||||
char *file;
|
||||
GET_RET_ADDR(file);
|
||||
_free_leap(file, 0, p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
// return the overhead on each memory allocation request
|
||||
int MM_register::space_overhead ()
|
||||
{
|
||||
return SIZE_SPACE;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
TPIE_OS_SPACE_OVERHEAD_BODY
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: mm_base.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/30/94
|
||||
//
|
||||
// $Id: mm_base.h,v 1.8 2005/04/22 13:52:50 jan Exp $
|
||||
//
|
||||
#ifndef _MM_BASE_H
|
||||
#define _MM_BASE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// dh. MM accounting modes
|
||||
typedef enum {
|
||||
MM_IGNORE_MEMORY_EXCEEDED=0,
|
||||
MM_ABORT_ON_MEMORY_EXCEEDED,
|
||||
MM_WARN_ON_MEMORY_EXCEEDED
|
||||
} MM_mode;
|
||||
|
||||
// MM Error codes
|
||||
enum MM_err {
|
||||
MM_ERROR_NO_ERROR = 0,
|
||||
MM_ERROR_INSUFFICIENT_SPACE,
|
||||
MM_ERROR_UNDERFLOW,
|
||||
MM_ERROR_EXCESSIVE_ALLOCATION
|
||||
};
|
||||
|
||||
// types of memory usage queries we can make on streams (either BTE or MM)
|
||||
enum MM_stream_usage {
|
||||
// Overhead of the object without the buffer
|
||||
MM_STREAM_USAGE_OVERHEAD = 1,
|
||||
// Max amount ever used by a buffer
|
||||
MM_STREAM_USAGE_BUFFER,
|
||||
// Amount currently in use.
|
||||
MM_STREAM_USAGE_CURRENT,
|
||||
// Max amount that will ever be used.
|
||||
MM_STREAM_USAGE_MAXIMUM,
|
||||
// Maximum additional amount used by each substream created.
|
||||
MM_STREAM_USAGE_SUBSTREAM
|
||||
};
|
||||
|
||||
// The base class for pointers into memory being managed by memory
|
||||
// managers. In a uniprocessor, these objects will simply contain
|
||||
// pointers. In multiprocessors, they will be more complicated
|
||||
// descriptions of the layout of memory.
|
||||
|
||||
class MM_ptr_base
|
||||
{
|
||||
public:
|
||||
// This should return 1 to indicate a valid pointer and 0 to
|
||||
// indicate an invalid one. It is useful for tests and
|
||||
// assertions.
|
||||
virtual operator int (void) = 0;
|
||||
};
|
||||
|
||||
// The base class for all memory management objects.
|
||||
|
||||
class MM_manager_base
|
||||
{
|
||||
public:
|
||||
|
||||
// How much is currently available.
|
||||
virtual MM_err available (TPIE_OS_SIZE_T *sz_a) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // _MM_BASE_H
|
||||
@@ -0,0 +1,240 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: mm_register.cpp
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/31/94
|
||||
//
|
||||
|
||||
// A simple registration based memory manager.
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(mm_register_cpp,"$Id: mm_register.cpp,v 1.23 2005/07/07 20:37:39 adanner Exp $");
|
||||
|
||||
//#include <assert.h>
|
||||
#include "lib_config.h"
|
||||
|
||||
#define MM_IMP_REGISTER
|
||||
#include <mm.h>
|
||||
#include <mm_register.h>
|
||||
|
||||
#ifdef REPORT_LARGE_MEMOPS
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#ifdef MM_BACKWARD_COMPATIBLE
|
||||
extern int register_new;
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
MM_register::MM_register()
|
||||
{
|
||||
instances++;
|
||||
|
||||
tp_assert(instances == 1,
|
||||
"Only 1 instance of MM_register_base should exist.");
|
||||
}
|
||||
|
||||
|
||||
MM_register::~MM_register(void)
|
||||
{
|
||||
tp_assert(instances == 1,
|
||||
"Only 1 instance of MM_register_base should exist.");
|
||||
|
||||
instances--;
|
||||
}
|
||||
|
||||
// check that new allocation request is below user-defined limit.
|
||||
// This should be a private method, only called by operator new.
|
||||
|
||||
MM_err MM_register::register_allocation(TPIE_OS_SIZE_T request)
|
||||
{
|
||||
// quick hack to allow operation before limit is set
|
||||
// XXX
|
||||
if(!user_limit) {
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
used += request;
|
||||
|
||||
if (request > remaining) {
|
||||
TP_LOG_WARNING("Memory allocation request: ");
|
||||
TP_LOG_WARNING(static_cast<TPIE_OS_OUTPUT_SIZE_T>(request));
|
||||
TP_LOG_WARNING(": User-specified memory limit exceeded.");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
remaining = 0;
|
||||
return MM_ERROR_INSUFFICIENT_SPACE;
|
||||
}
|
||||
|
||||
remaining -= request;
|
||||
|
||||
TP_LOG_MEM_DEBUG("mm_register Allocated ");
|
||||
TP_LOG_MEM_DEBUG(static_cast<TPIE_OS_OUTPUT_SIZE_T>(request));
|
||||
TP_LOG_MEM_DEBUG("; ");
|
||||
TP_LOG_MEM_DEBUG(static_cast<TPIE_OS_OUTPUT_SIZE_T>(remaining));
|
||||
TP_LOG_MEM_DEBUG(" remaining.\n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
|
||||
#ifdef REPORT_LARGE_MEMOPS
|
||||
if(request > user_limit/10) {
|
||||
cerr << "MEM alloc " << request
|
||||
<< " (" << remaining << " remaining)" << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// do the accounting for a memory deallocation request.
|
||||
// This should be a private method, only called by operators
|
||||
// delete and delete [].
|
||||
|
||||
MM_err MM_register::register_deallocation(TPIE_OS_SIZE_T sz)
|
||||
{
|
||||
remaining += sz;
|
||||
|
||||
if (sz > used) {
|
||||
TP_LOG_WARNING("Error in deallocation sz=");
|
||||
TP_LOG_WARNING((TPIE_OS_LONG)sz);
|
||||
TP_LOG_WARNING(", remaining=");
|
||||
TP_LOG_WARNING((TPIE_OS_LONG)remaining);
|
||||
TP_LOG_WARNING(", user_limit=");
|
||||
TP_LOG_WARNING((TPIE_OS_LONG)user_limit);
|
||||
TP_LOG_WARNING("\n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
used = 0;
|
||||
return MM_ERROR_UNDERFLOW;
|
||||
}
|
||||
|
||||
used -= sz;
|
||||
|
||||
TP_LOG_MEM_DEBUG("mm_register De-allocated ");
|
||||
TP_LOG_MEM_DEBUG((unsigned int)sz);
|
||||
TP_LOG_MEM_DEBUG("; ");
|
||||
TP_LOG_MEM_DEBUG((unsigned int)remaining);
|
||||
TP_LOG_MEM_DEBUG(" now available.\n");
|
||||
TP_LOG_FLUSH_LOG;
|
||||
|
||||
#ifdef REPORT_LARGE_MEMOPS
|
||||
if(sz > user_limit/10) {
|
||||
cerr << "MEM free " << sz
|
||||
<< " (" << remaining << " remaining)" << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifdef MM_BACKWARD_COMPATIBLE
|
||||
// (Old) way to query how much memory is available
|
||||
|
||||
MM_err MM_register::available (TPIE_OS_SIZE_T *sz)
|
||||
{
|
||||
*sz = remaining;
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
// resize_heap has the same purpose as set_memory_limit.
|
||||
// It is retained for backward compatibility.
|
||||
// dh. 1999 09 29
|
||||
|
||||
MM_err MM_register::resize_heap(TPIE_OS_SIZE_T sz)
|
||||
{
|
||||
return set_memory_limit(sz);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// User-callable method to set allowable memory size
|
||||
|
||||
MM_err MM_register::set_memory_limit (TPIE_OS_SIZE_T new_limit)
|
||||
{
|
||||
// by default, we keep track and abort if memory limit exceeded
|
||||
if (register_new == MM_IGNORE_MEMORY_EXCEEDED){
|
||||
register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
|
||||
}
|
||||
// dh. unless the user indicates otherwise
|
||||
if (new_limit == 0){
|
||||
register_new = MM_IGNORE_MEMORY_EXCEEDED;
|
||||
remaining = used = user_limit = 0;
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (used > new_limit) {
|
||||
return MM_ERROR_EXCESSIVE_ALLOCATION;
|
||||
} else {
|
||||
// These are unsigned, so be careful.
|
||||
if (new_limit < user_limit) {
|
||||
remaining -= user_limit - new_limit;
|
||||
} else {
|
||||
remaining += new_limit - user_limit;
|
||||
}
|
||||
user_limit = new_limit;
|
||||
return MM_ERROR_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// dh. only warn if memory limit exceeded
|
||||
void MM_register::warn_memory_limit()
|
||||
{
|
||||
register_new = MM_WARN_ON_MEMORY_EXCEEDED;
|
||||
}
|
||||
|
||||
// dh. abort if memory limit exceeded
|
||||
void MM_register::enforce_memory_limit()
|
||||
{
|
||||
register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
|
||||
}
|
||||
|
||||
// dh. ignore memory limit accounting
|
||||
void MM_register::ignore_memory_limit()
|
||||
{
|
||||
register_new = MM_IGNORE_MEMORY_EXCEEDED;
|
||||
}
|
||||
|
||||
// rw. provide accounting state
|
||||
MM_mode MM_register::get_limit_mode() {
|
||||
return register_new;
|
||||
}
|
||||
|
||||
|
||||
// dh. return the amount of memory available before user-specified
|
||||
// memory limit exceeded
|
||||
TPIE_OS_SIZE_T MM_register::memory_available()
|
||||
{
|
||||
return remaining;
|
||||
}
|
||||
|
||||
size_t MM_register::memory_used()
|
||||
{
|
||||
return used;
|
||||
}
|
||||
|
||||
size_t MM_register::memory_limit()
|
||||
{
|
||||
return user_limit;
|
||||
}
|
||||
|
||||
// Instantiate the actual memory manager, and allocate the
|
||||
// its static data members
|
||||
MM_register MM_manager;
|
||||
int MM_register::instances = 0; // Number of instances. (init)
|
||||
// TPIE's "register memory requests" flag
|
||||
MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
|
||||
|
||||
// The counter of mm_register_init instances. It is implicity set to 0.
|
||||
unsigned int mm_register_init::count;
|
||||
|
||||
// The constructor and destructor that ensure that the memory manager is
|
||||
// created exactly once, and destroyed when appropriate.
|
||||
mm_register_init::mm_register_init(void)
|
||||
{
|
||||
if (count++ == 0) {
|
||||
MM_manager.set_memory_limit(MM_DEFAULT_MM_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
mm_register_init::~mm_register_init(void)
|
||||
{
|
||||
--count;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: mm_register.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/30/94
|
||||
//
|
||||
// $Id: mm_register.h,v 1.10 2004/08/12 12:35:32 jan Exp $
|
||||
//
|
||||
#ifndef _MM_REGISTER_H
|
||||
#define _MM_REGISTER_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#define MM_REGISTER_VERSION 2
|
||||
|
||||
// To be defined later in this file.
|
||||
class mm_register_init;
|
||||
|
||||
// Declarations of a very simple memory manager desgined to work with
|
||||
// BTEs that rely on the underlying OS to manage physical memory.
|
||||
// Examples include BTEs based on mmap() and the stdio library.
|
||||
// Another type of BTE this MM would be useful for is one which is
|
||||
// designed to make efficient use of a cache for programs running
|
||||
// entirely in main memory.
|
||||
|
||||
class MM_register {
|
||||
private:
|
||||
// The number of instances of this class and descendents that exist.
|
||||
static int instances;
|
||||
|
||||
// The amount of space remaining to be allocated.
|
||||
TPIE_OS_SIZE_T remaining;
|
||||
|
||||
// The user-specified limit on memory.
|
||||
TPIE_OS_SIZE_T user_limit;
|
||||
|
||||
// the amount that has been allocated.
|
||||
TPIE_OS_SIZE_T used;
|
||||
|
||||
|
||||
public:
|
||||
// made public since Linux c++ doesn't like the fact that our new
|
||||
// and delete operators don't throw exceptions. [tavi]
|
||||
// flag indicates whether we are keeping track of memory or not
|
||||
static MM_mode register_new;
|
||||
|
||||
MM_register();
|
||||
~MM_register(void);
|
||||
|
||||
MM_err register_allocation (TPIE_OS_SIZE_T sz);
|
||||
MM_err register_deallocation(TPIE_OS_SIZE_T sz);
|
||||
#ifdef MM_BACKWARD_COMPATIBLE
|
||||
// retained for backward compatibility
|
||||
MM_err available (TPIE_OS_SIZE_T *sz);
|
||||
MM_err resize_heap (TPIE_OS_SIZE_T sz);
|
||||
#endif
|
||||
MM_err set_memory_limit(TPIE_OS_SIZE_T sz); // dh.
|
||||
|
||||
void enforce_memory_limit (); // dh.
|
||||
void ignore_memory_limit (); // dh.
|
||||
void warn_memory_limit (); // dh.
|
||||
MM_mode get_limit_mode();
|
||||
|
||||
TPIE_OS_SIZE_T memory_available (); // dh.
|
||||
TPIE_OS_SIZE_T memory_used (); // dh.
|
||||
TPIE_OS_SIZE_T memory_limit (); // dh.
|
||||
int space_overhead (); // dh.
|
||||
|
||||
friend class mm_register_init;
|
||||
//friend void * operator new(TPIE_OS_SIZE_T);
|
||||
//friend void operator delete(void *);
|
||||
//friend void operator delete[](void *);
|
||||
};
|
||||
|
||||
|
||||
// The default amount of memory we will allow to be allocated.
|
||||
// 40MB
|
||||
#define MM_DEFAULT_MM_SIZE (40<<20)
|
||||
|
||||
|
||||
// Here is the single memory management object.
|
||||
extern MM_register MM_manager;
|
||||
|
||||
|
||||
// A class to make sure that MM_manager gets set up properly. It is
|
||||
// based on the code in tpie_log.h that does the same thing for logs,
|
||||
// which is in turn based on item 47 from sdm's book.
|
||||
class mm_register_init {
|
||||
private:
|
||||
// The number of mm_register_init objects that exist.
|
||||
static unsigned int count;
|
||||
|
||||
public:
|
||||
mm_register_init(void);
|
||||
~mm_register_init(void);
|
||||
};
|
||||
|
||||
static mm_register_init source_file_mm_register_init;
|
||||
|
||||
#endif // _MM_REGISTER_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 1995 Darren Erik Vengroff
|
||||
//
|
||||
// File: persist.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 4/7/95
|
||||
//
|
||||
// $Id: persist.h,v 1.3 2003/09/13 17:42:27 jan Exp $
|
||||
//
|
||||
// Persistence flags for TPIE streams.
|
||||
//
|
||||
#ifndef _PERSIST_H
|
||||
#define _PERSIST_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
enum persistence {
|
||||
// Delete the stream from the disk when it is destructed.
|
||||
PERSIST_DELETE = 0,
|
||||
// Do not delete the stream from the disk when it is destructed.
|
||||
PERSIST_PERSISTENT = 1,
|
||||
// Delete each block of data from the disk as it is read.
|
||||
// If not supported by the OS (see portability.h), delete
|
||||
// the stream when it is destructed (see PERSIST_DELETE).
|
||||
PERSIST_READ_ONCE = TPIE_OS_PERSIST_READ_ONCE
|
||||
};
|
||||
|
||||
#endif // _PERSIST_H
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <portability.h>
|
||||
|
||||
//Needed for windows only
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
ostream& operator<<(ostream& s, const TPIE_OS_OFFSET x){
|
||||
char buf[30];
|
||||
sprintf(buf,"%I64d",x);
|
||||
return s << buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,459 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: pqueue_heap.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 10/4/94
|
||||
//
|
||||
// $Id: pqueue_heap.h,v 1.10 2005/01/14 18:36:24 tavi Exp $
|
||||
//
|
||||
// A priority queue class implemented as a binary heap.
|
||||
//
|
||||
|
||||
#ifndef _PQUEUE_HEAP_H
|
||||
#define _PQUEUE_HEAP_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
// The virtual base class that defines what priority queues must do.
|
||||
template <class T, class P>
|
||||
class pqueue
|
||||
{
|
||||
public:
|
||||
// Is it full?
|
||||
virtual bool full(void) = 0;
|
||||
|
||||
// How many elements?
|
||||
virtual unsigned int num_elts(void) = 0;
|
||||
|
||||
// Insert
|
||||
virtual bool insert(const T& elt, const P& prio) = 0;
|
||||
|
||||
// Min
|
||||
virtual void get_min(T& elt, P& prio) = 0;
|
||||
|
||||
// Extract min.
|
||||
virtual bool extract_min(T& elt, P& prio) = 0;
|
||||
};
|
||||
|
||||
|
||||
// Helper functions for navigating through a binary heap.
|
||||
|
||||
// The children of an element of the heap.
|
||||
|
||||
static inline unsigned int lchild(unsigned int index) {
|
||||
return 2 * index;
|
||||
}
|
||||
|
||||
static inline unsigned int rchild(unsigned int index) {
|
||||
return 2 * index + 1;
|
||||
}
|
||||
|
||||
// The parent of an element.
|
||||
|
||||
static inline unsigned int parent(unsigned int index) {
|
||||
return index >> 1;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
struct q_elt {
|
||||
T elt;
|
||||
P priority;
|
||||
};
|
||||
|
||||
|
||||
// A base class for priority queues that use heaps.
|
||||
|
||||
template <class T, class P>
|
||||
class pqueue_heap
|
||||
{
|
||||
protected:
|
||||
// A pointer to the array of elements and their priorities.
|
||||
q_elt<T,P> * elements;
|
||||
|
||||
// The number currently in the queue.
|
||||
unsigned int cur_elts;
|
||||
|
||||
// The maximum number the queue can hold.
|
||||
unsigned int max_elts;
|
||||
|
||||
// Fix up the heap after a deletion.
|
||||
/* virtual void heapify(unsigned int root) = 0; */
|
||||
|
||||
public:
|
||||
pqueue_heap(unsigned int size);
|
||||
|
||||
virtual ~pqueue_heap();
|
||||
|
||||
// Is it full?
|
||||
bool full(void);
|
||||
|
||||
// How many elements?
|
||||
unsigned int num_elts(void);
|
||||
|
||||
// Min
|
||||
void get_min(T& elt, P& prio);
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
pqueue_heap<T,P>::pqueue_heap(unsigned int size)
|
||||
{
|
||||
elements = new q_elt<T,P>[max_elts = size];
|
||||
cur_elts = 0;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
pqueue_heap<T,P>::~pqueue_heap() {
|
||||
delete [] elements;
|
||||
cur_elts = 0;
|
||||
max_elts = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
bool pqueue_heap<T,P>::full(void) {
|
||||
return cur_elts == max_elts;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
unsigned int pqueue_heap<T,P>::num_elts(void) {
|
||||
return cur_elts;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void pqueue_heap<T,P>::get_min(T& elt, P& prio) {
|
||||
elt = elements->elt;
|
||||
prio = elements->priority;
|
||||
}
|
||||
|
||||
|
||||
// Comment: (jan) You must not use this version anymore.
|
||||
|
||||
// // A priority queue that uses a comparison function for comparing
|
||||
// // priorities.
|
||||
|
||||
// End Comment.
|
||||
|
||||
|
||||
// A priority queue that uses the builtin operator < for comparing
|
||||
// priorities instead of a comparison function.
|
||||
|
||||
template <class T, class P>
|
||||
class pqueue_heap_op : public pqueue_heap<T,P>
|
||||
{
|
||||
private:
|
||||
void heapify(unsigned int root);
|
||||
protected:
|
||||
using pqueue_heap<T,P>::cur_elts;
|
||||
using pqueue_heap<T,P>::max_elts;
|
||||
using pqueue_heap<T,P>::elements;
|
||||
|
||||
public:
|
||||
using pqueue_heap<T,P>::full;
|
||||
using pqueue_heap<T,P>::num_elts;
|
||||
|
||||
pqueue_heap_op(unsigned int size);
|
||||
virtual ~pqueue_heap_op(void) {};
|
||||
|
||||
// Insert
|
||||
bool insert(const T& elt, const P& prio);
|
||||
// Extract min.
|
||||
bool extract_min(T& elt, P& prio);
|
||||
};
|
||||
|
||||
template <class T, class P>
|
||||
bool pqueue_heap_op<T,P>::extract_min(T& elt, P& prio) {
|
||||
if (!cur_elts) {
|
||||
return false;
|
||||
}
|
||||
elt = elements->elt;
|
||||
prio = elements->priority;
|
||||
elements[0] = elements[--cur_elts];
|
||||
heapify(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
pqueue_heap_op<T,P>::pqueue_heap_op(unsigned int size) :
|
||||
pqueue_heap<T,P>(size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
bool pqueue_heap_op<T,P>::insert(const T& elt, const P& prio) {
|
||||
unsigned int ii;
|
||||
|
||||
if (full()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ii = cur_elts++;
|
||||
ii && (elements[parent(ii)].priority > prio);
|
||||
ii = parent(ii)) {
|
||||
elements[ii] = elements[parent(ii)];
|
||||
}
|
||||
elements[ii].priority = prio;
|
||||
elements[ii].elt = elt;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class P>
|
||||
void pqueue_heap_op<T,P>::heapify(unsigned int root) {
|
||||
unsigned int min_index = root;
|
||||
unsigned int lc = lchild(root);
|
||||
unsigned int rc = rchild(root);
|
||||
|
||||
if ((lc < cur_elts) && (elements[lc].priority <
|
||||
elements[min_index].priority)) {
|
||||
min_index = lc;
|
||||
}
|
||||
if ((rc < cur_elts) && (elements[rc].priority <
|
||||
elements[min_index].priority)) {
|
||||
min_index = rc;
|
||||
}
|
||||
|
||||
if (min_index != root) {
|
||||
q_elt<T,P> tmp_q = elements[min_index];
|
||||
|
||||
elements[min_index] = elements[root];
|
||||
elements[root] = tmp_q;
|
||||
|
||||
heapify(min_index);
|
||||
}
|
||||
}
|
||||
|
||||
// A priority queue that uses a comparison object.
|
||||
|
||||
template <class T, class P, class CMPR>
|
||||
class pqueue_heap_obj : public pqueue_heap<T,P>
|
||||
{
|
||||
private:
|
||||
CMPR *cmp_o;
|
||||
void heapify(unsigned int root);
|
||||
protected:
|
||||
using pqueue_heap<T,P>::cur_elts;
|
||||
using pqueue_heap<T,P>::max_elts;
|
||||
using pqueue_heap<T,P>::elements;
|
||||
|
||||
public:
|
||||
using pqueue_heap<T,P>::full;
|
||||
using pqueue_heap<T,P>::num_elts;
|
||||
|
||||
public:
|
||||
pqueue_heap_obj(unsigned int size, CMPR *cmp);
|
||||
virtual ~pqueue_heap_obj(void) {};
|
||||
|
||||
// Insert
|
||||
bool insert(const T& elt, const P& prio);
|
||||
// Extract min.
|
||||
bool extract_min(T& elt, P& prio);
|
||||
};
|
||||
|
||||
template <class T, class P, class CMPR>
|
||||
bool pqueue_heap_obj<T,P,CMPR>::extract_min(T& elt, P& prio) {
|
||||
if (!cur_elts) {
|
||||
return false;
|
||||
}
|
||||
elt = elements->elt;
|
||||
prio = elements->priority;
|
||||
elements[0] = elements[--cur_elts];
|
||||
heapify(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class P, class CMPR>
|
||||
pqueue_heap_obj<T,P,CMPR>::pqueue_heap_obj(unsigned int size, CMPR *cmp)
|
||||
: pqueue_heap<T,P>(size)
|
||||
|
||||
{
|
||||
cmp_o = cmp;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class P, class CMPR>
|
||||
bool pqueue_heap_obj<T,P,CMPR>::insert(const T& elt, const P& prio) {
|
||||
unsigned int ii;
|
||||
|
||||
if (full()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ii = cur_elts++;
|
||||
ii && (cmp_o->compare(elements[parent(ii)].priority, prio) > 0);
|
||||
ii = parent(ii)) {
|
||||
elements[ii] = elements[parent(ii)];
|
||||
}
|
||||
elements[ii].priority = prio;
|
||||
elements[ii].elt = elt;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, class P, class CMPR>
|
||||
void pqueue_heap_obj<T,P,CMPR>::heapify(unsigned int root) {
|
||||
unsigned int min_index = root;
|
||||
unsigned int lc = lchild(root);
|
||||
unsigned int rc = rchild(root);
|
||||
|
||||
if ((lc < cur_elts) &&
|
||||
(cmp_o->compare(elements[lc].priority,
|
||||
elements[min_index].priority) < 0)) {
|
||||
min_index = lc;
|
||||
}
|
||||
if ((rc < cur_elts) &&
|
||||
(cmp_o->compare(elements[rc].priority,
|
||||
elements[min_index].priority) < 0)) {
|
||||
min_index = rc;
|
||||
}
|
||||
|
||||
if (min_index != root) {
|
||||
q_elt<T,P> tmp_q = elements[min_index];
|
||||
|
||||
elements[min_index] = elements[root];
|
||||
elements[root] = tmp_q;
|
||||
|
||||
heapify(min_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Comment: (jan) You must not use this version anymore.
|
||||
|
||||
template <class T, class P>
|
||||
class pqueue_heap_cmp : public pqueue_heap<T,P>
|
||||
{
|
||||
|
||||
private:
|
||||
// A pointer to the function used to compare the priorities of
|
||||
// elements.
|
||||
int (*cmp_f)(const P&, const P&);
|
||||
void heapify(unsigned int root);
|
||||
protected:
|
||||
using pqueue_heap<T,P>::cur_elts;
|
||||
using pqueue_heap<T,P>::max_elts;
|
||||
using pqueue_heap<T,P>::elements;
|
||||
public:
|
||||
using pqueue_heap<T,P>::full;
|
||||
using pqueue_heap<T,P>::num_elts;
|
||||
|
||||
public:
|
||||
pqueue_heap_cmp(unsigned int size, int (*cmp)(const P&, const P&));
|
||||
virtual ~pqueue_heap_cmp(void) {}
|
||||
// Insert
|
||||
bool insert(const T& elt, const P& prio);
|
||||
// Extract min.
|
||||
bool extract_min(T& elt, P& prio);
|
||||
};
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
bool pqueue_heap_cmp<T,P>::extract_min(T& elt, P& prio)
|
||||
{
|
||||
|
||||
if (!cur_elts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
elt = elements->elt;
|
||||
prio = elements->priority;
|
||||
elements[0] = elements[--cur_elts];
|
||||
heapify(0);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
pqueue_heap_cmp<T,P>::pqueue_heap_cmp(unsigned int size,
|
||||
int (*cmp)(const P&, const P&)) :
|
||||
pqueue_heap<T,P>(size) {
|
||||
cmp_f = cmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
bool pqueue_heap_cmp<T,P>::insert(const T& elt, const P& prio)
|
||||
{
|
||||
unsigned int ii;
|
||||
if (full()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (ii = cur_elts++;
|
||||
ii && (cmp_f(elements[parent(ii)].priority, prio) > 0);
|
||||
ii = parent(ii))
|
||||
{
|
||||
|
||||
elements[ii] = elements[parent(ii)];
|
||||
|
||||
}
|
||||
|
||||
elements[ii].priority = prio;
|
||||
|
||||
elements[ii].elt = elt;
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
void pqueue_heap_cmp<T,P>::heapify(unsigned int root)
|
||||
{
|
||||
|
||||
unsigned int min_index = root;
|
||||
|
||||
unsigned int lc = lchild(root);
|
||||
|
||||
unsigned int rc = rchild(root);
|
||||
|
||||
|
||||
if ((lc < cur_elts) && (cmp_f(elements[lc].priority,
|
||||
elements[min_index].priority) < 0))
|
||||
{
|
||||
|
||||
min_index = lc;
|
||||
|
||||
}
|
||||
|
||||
if ((rc < cur_elts) && (cmp_f(elements[rc].priority,
|
||||
elements[min_index].priority) < 0))
|
||||
{
|
||||
|
||||
min_index = rc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (min_index != root)
|
||||
{
|
||||
|
||||
q_elt<T,P> tmp_q = elements[min_index];
|
||||
|
||||
|
||||
elements[min_index] = elements[root];
|
||||
|
||||
elements[root] = tmp_q;
|
||||
|
||||
|
||||
heapify(min_index);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// // A priority queue that simply uses an array.
|
||||
|
||||
// End Comment.
|
||||
|
||||
#endif // _PQUEUE_HEAP_H
|
||||
@@ -0,0 +1,306 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: quicksort.h
|
||||
// Author: Darren Erik Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 9/28/94
|
||||
//
|
||||
// A basic implementation of quicksort for use in core by AMI_sort() on
|
||||
// streams or substreams that are small enough.
|
||||
//
|
||||
// $Id: quicksort.h,v 1.23 2005/07/07 20:42:31 adanner Exp $
|
||||
//
|
||||
#ifndef _QUICKSORT_H
|
||||
#define _QUICKSORT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
//A simple class that facilitates doing key sorting followed
|
||||
//by in-memory permuting to sort items in-memory. This is
|
||||
//particularly useful when key size is much smaller than
|
||||
//item size. Note that using this requires that the class Key
|
||||
//have the comparison operators defined appropriately.
|
||||
|
||||
template<class Key>
|
||||
class qsort_item {
|
||||
public:
|
||||
Key keyval;
|
||||
unsigned int source;
|
||||
|
||||
friend int operator==(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval == y.keyval);}
|
||||
|
||||
friend int operator!=(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval != y.keyval);}
|
||||
|
||||
friend int operator<=(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval <= y.keyval);}
|
||||
|
||||
friend int operator>=(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval >= y.keyval);}
|
||||
|
||||
friend int operator<(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval < y.keyval);}
|
||||
|
||||
friend int operator>(const qsort_item &x, const qsort_item &y)
|
||||
{return (x.keyval > y.keyval);}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// A version that uses the < operator. This should be faster for
|
||||
// intrinsic types such as int, where the compiler can generate very
|
||||
// good code and avoid a function call inside the innermost loop of
|
||||
// partition().
|
||||
|
||||
template<class T>
|
||||
void partition_op(T *data, size_t len, size_t &partition);
|
||||
|
||||
template<class T>
|
||||
void __quick_sort_op(T *data, size_t len,
|
||||
size_t min_file_len = 2)
|
||||
{
|
||||
// On return from partition(), everything at or below this index
|
||||
// will be less that or equal to everything above it.
|
||||
// Furthermore, it will not be 0 since this will leave us to
|
||||
// recurse on the whole array again.
|
||||
|
||||
size_t part_index;
|
||||
|
||||
if (len < min_file_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
partition_op(data, len, part_index);
|
||||
|
||||
__quick_sort_op(data, part_index + 1, min_file_len);
|
||||
__quick_sort_op(data + part_index + 1, len - part_index - 1, min_file_len);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void partition_op(T *data, size_t len, size_t &part_index)
|
||||
{
|
||||
T *ptpart, tpart;
|
||||
T *p, *q;
|
||||
T t0;
|
||||
|
||||
// Try to get a good partition value and avoid being bitten by already
|
||||
// sorted input.
|
||||
|
||||
ptpart = data + (TPIE_OS_RANDOM() % len);
|
||||
|
||||
tpart = *ptpart;
|
||||
*ptpart = data[0];
|
||||
data[0] = tpart;
|
||||
|
||||
// Walk through the array and partition them.
|
||||
|
||||
for (p = data - 1, q = data + len; ; ) {
|
||||
|
||||
do {
|
||||
q--;
|
||||
} while (tpart < *q );
|
||||
do {
|
||||
p++;
|
||||
} while (*p < tpart);
|
||||
|
||||
if (p < q) {
|
||||
t0 = *p;
|
||||
*p = *q;
|
||||
*q = t0;
|
||||
} else {
|
||||
part_index = q - data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void insertion_sort_op(T *data, size_t len);
|
||||
|
||||
template<class T>
|
||||
void quick_sort_op(T *data, size_t len,
|
||||
size_t min_file_len = 20)
|
||||
{
|
||||
__quick_sort_op(data, len, min_file_len);
|
||||
insertion_sort_op(data, len);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void insertion_sort_op(T *data, size_t len)
|
||||
{
|
||||
T *p, *q, test;
|
||||
|
||||
for (p = data + 1; p < data + len; p++) {
|
||||
//for (q = p - 1, test = *p; *q > test; q--) { dh
|
||||
for (q = p - 1, test = *p; test < *q; q--) {
|
||||
*(q+1) = *q;
|
||||
if (q == data) {
|
||||
q--; // to make assignment below correct
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(q+1) = test;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A version that uses a comparison object.
|
||||
template<class T, class CMPR>
|
||||
void partition_obj(T *data, size_t len, size_t &partition,
|
||||
CMPR *cmp);
|
||||
|
||||
template<class T, class CMPR>
|
||||
void __quick_sort_obj(T *data, size_t len, CMPR *cmp,
|
||||
size_t min_file_len = 2)
|
||||
{
|
||||
// On return from partition(), everything at or below this index
|
||||
// will be less that or equal to everything above it.
|
||||
// Furthermore, it will not be 0 since this will leave us to
|
||||
// recurse on the whole array again.
|
||||
|
||||
size_t part_index;
|
||||
|
||||
if (len < min_file_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
partition_obj(data, len, part_index, cmp);
|
||||
|
||||
__quick_sort_obj(data, part_index + 1, cmp, min_file_len);
|
||||
__quick_sort_obj(data + part_index + 1, len - part_index - 1, cmp, min_file_len);
|
||||
}
|
||||
|
||||
template<class T, class CMPR>
|
||||
void partition_obj(T *data, size_t len, size_t &part_index,
|
||||
CMPR *cmp)
|
||||
{
|
||||
T *ptpart, tpart;
|
||||
T *p, *q;
|
||||
T t0;
|
||||
|
||||
// Try to get a good partition value and avoid being bitten by already
|
||||
// sorted input.
|
||||
|
||||
ptpart = data + (TPIE_OS_RANDOM() % len);
|
||||
|
||||
tpart = *ptpart;
|
||||
*ptpart = data[0];
|
||||
data[0] = tpart;
|
||||
|
||||
// Walk through the array and partition them.
|
||||
|
||||
for (p = data - 1, q = data + len; ; ) {
|
||||
|
||||
do {
|
||||
q--;
|
||||
} while (cmp->compare(tpart, *q) < 0);
|
||||
do {
|
||||
p++;
|
||||
} while (cmp->compare(*p, tpart) < 0);
|
||||
|
||||
if (p < q) {
|
||||
t0 = *p;
|
||||
*p = *q;
|
||||
*q = t0;
|
||||
} else {
|
||||
part_index = q - data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T, class CMPR>
|
||||
void insertion_sort_obj(T *data, size_t len,
|
||||
CMPR *cmp);
|
||||
|
||||
template<class T, class CMPR>
|
||||
void quick_sort_obj(T *data, size_t len,
|
||||
CMPR *cmp,
|
||||
size_t min_file_len = 20)
|
||||
{
|
||||
__quick_sort_obj(data, len, cmp, min_file_len);
|
||||
insertion_sort_obj(data, len, cmp);
|
||||
}
|
||||
|
||||
template<class T, class CMPR>
|
||||
void insertion_sort_obj(T *data, size_t len,
|
||||
CMPR *cmp)
|
||||
{
|
||||
T *p, *q, test;
|
||||
|
||||
for (p = data + 1; p < data + len; p++) {
|
||||
for (q = p - 1, test = *p; (cmp->compare(test, *q) < 0); q--) {
|
||||
*(q+1) = *q;
|
||||
if (q==data) {
|
||||
q--; // to make assignment below correct
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(q+1) = test;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DEPRECATED: quick_sort_cmp
|
||||
Earlier TPIE versions allowed a quicksort that used a C-style
|
||||
comparison function to sort. However, comparison functions cannot be
|
||||
inlined, so each comparison requires one function call. Given that the
|
||||
comparison operator < and comparison object classes can be inlined and
|
||||
have better performance while providing the exact same functionality,
|
||||
comparison functions have been removed from TPIE. If you can provide us
|
||||
with a compelling argument on why they should be in here, we may consider
|
||||
adding them again, but you must demonstrate that comparision functions
|
||||
can outperform other methods in at least some cases or give an example
|
||||
were it is impossible to use a comparison operator or comparison object
|
||||
*/
|
||||
|
||||
#endif // _QUICKSORT_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// File: stdio_stack.h
|
||||
// Authors: Rakesh Barve
|
||||
//
|
||||
// Defining a stack based on bte_stdio separately specifically
|
||||
// for use in block collection class and related apps.
|
||||
// The reason we don't want to use ami_stack is because
|
||||
// then the stack would be implemented as a BTE_STREAM, which
|
||||
// may have large block size etc. which is undesirable for
|
||||
// stacks related to block collections since such a stack is only
|
||||
// a meta data structure accessed no more than once every block
|
||||
// is created or destroyed.
|
||||
//
|
||||
// $Id: stdio_stack.h,v 1.7 2003/04/17 19:57:25 jan Exp $
|
||||
//
|
||||
|
||||
#ifndef _STDIO_STACK_H
|
||||
#define _STDIO_STACK_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <bte_stream_stdio.h>
|
||||
|
||||
template<class T>
|
||||
class stdio_stack : public BTE_stream_stdio<T> {
|
||||
public:
|
||||
|
||||
stdio_stack(char *path, BTE_stream_type type = BTE_WRITE_STREAM);
|
||||
|
||||
~stdio_stack(void);
|
||||
|
||||
BTE_err push(const T &t);
|
||||
|
||||
BTE_err pop(T **t);
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
stdio_stack<T>::stdio_stack(char *path,
|
||||
BTE_stream_type type) :
|
||||
BTE_stream_stdio<T>(path, type)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
stdio_stack<T>::~stdio_stack(void)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BTE_err stdio_stack<T>::push(const T &t)
|
||||
{
|
||||
BTE_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
ae = truncate((slen = stream_len())+1);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = seek(slen);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return write_item(t);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
BTE_err stdio_stack<T>::pop(T **t)
|
||||
{
|
||||
BTE_err ae;
|
||||
TPIE_OS_OFFSET slen;
|
||||
|
||||
slen = stream_len();
|
||||
ae = seek(slen-1);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
ae = read_item(t);
|
||||
if (ae != BTE_ERROR_NO_ERROR) {
|
||||
return ae;
|
||||
}
|
||||
|
||||
return truncate(slen-1);
|
||||
}
|
||||
|
||||
#endif // _stdio_stack_H
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 1995 Darren Vengroff
|
||||
//
|
||||
// File: timer.h
|
||||
// Author: Darren Vengroff <darrenv@eecs.umich.edu>
|
||||
// Created: 1/11/95
|
||||
//
|
||||
// $Id: timer.h,v 1.2 2003/04/17 19:58:26 jan Exp $
|
||||
//
|
||||
// General definition of a virtual timer class.
|
||||
//
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
class timer {
|
||||
public:
|
||||
virtual void start(void) = 0;
|
||||
virtual void stop(void) = 0;
|
||||
virtual void reset(void) = 0;
|
||||
};
|
||||
|
||||
#endif // _TIMER_H
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: tpie_assert.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/12/94
|
||||
//
|
||||
// $Id: tpie_assert.h,v 1.10 2005/07/07 20:38:07 adanner Exp $
|
||||
//
|
||||
|
||||
#ifndef _TPIE_ASSERT_H
|
||||
#define _TPIE_ASSERT_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <tpie_log.h>
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
|
||||
#if DEBUG_ASSERTIONS
|
||||
|
||||
#define tp_assert(condition,message) { \
|
||||
if (!(condition)) { \
|
||||
TP_LOG_FATAL_ID("Assertion failed:"); \
|
||||
TP_LOG_FATAL_ID(message); \
|
||||
cerr << "Assertion failed: " << message << "\n"; \
|
||||
assert(condition); \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
#define tp_assert(condition,message)
|
||||
#endif
|
||||
|
||||
#endif // _TPIE_ASSERT_H
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// File: tpie_log.cpp
|
||||
// Authors: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
// Created: 5/12/94
|
||||
//
|
||||
|
||||
#include <versions.h>
|
||||
VERSION(tpie_log_cpp,"$Id: tpie_log.cpp,v 1.16 2004/08/12 12:53:43 jan Exp $");
|
||||
|
||||
// We are logging
|
||||
#define TPL_LOGGING 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <tpie_tempnam.h>
|
||||
#include <tpie_log.h>
|
||||
|
||||
#define TPLOGPFX "tpielog"
|
||||
|
||||
// Local initialization function. Create a permanent repository for the log
|
||||
// file name. Should be called only once, by theLogName() below.
|
||||
static char *__tpie_log_name() {
|
||||
static char tln[128];
|
||||
TPIE_OS_SRANDOM((unsigned int)TPIE_OS_TIME(NULL));
|
||||
strncpy(tln, tpie_tempnam(TPLOGPFX, TPLOGDIR), 124);
|
||||
strcat(tln, ".txt");
|
||||
return tln;
|
||||
}
|
||||
|
||||
char *tpie_log_name() {
|
||||
static char *tln = __tpie_log_name();
|
||||
return tln;
|
||||
}
|
||||
|
||||
|
||||
logstream &tpie_log() {
|
||||
static logstream log(tpie_log_name(), TPIE_LOG_DEBUG, TPIE_LOG_DEBUG);
|
||||
return log;
|
||||
}
|
||||
|
||||
void tpie_log_init(TPIE_LOG_LEVEL level) {
|
||||
TP_LOG_SET_THRESHOLD(level);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 1994 Darren Erik Vengroff
|
||||
//
|
||||
// File: tpie_log.h
|
||||
// Author: Darren Erik Vengroff <dev@cs.duke.edu>
|
||||
// Created: 5/12/94
|
||||
//
|
||||
// $Id: tpie_log.h,v 1.25 2005/07/07 20:37:39 adanner Exp $
|
||||
//
|
||||
|
||||
#ifndef _TPIE_LOG_H
|
||||
#define _TPIE_LOG_H
|
||||
|
||||
// Logging levels, from higest priority to lowest.
|
||||
enum TPIE_LOG_LEVEL {
|
||||
TPIE_LOG_FATAL = 0, // Fatal errors are always logged no matter what;
|
||||
TPIE_LOG_WARNING, // Warning about some internal condition;
|
||||
TPIE_LOG_APP_DEBUG, // Debugging info for the application only;
|
||||
TPIE_LOG_DEBUG, // Debugging info.
|
||||
TPIE_LOG_MEM_DEBUG // Memory allocation de-allocation.
|
||||
};
|
||||
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <logstream.h>
|
||||
|
||||
// The file name of the log stream.
|
||||
char *tpie_log_name();
|
||||
|
||||
// Returns the only logstream object.
|
||||
logstream& tpie_log();
|
||||
|
||||
// Initialize the log.
|
||||
void tpie_log_init(TPIE_LOG_LEVEL level = TPIE_LOG_WARNING);
|
||||
|
||||
#if TPL_LOGGING
|
||||
|
||||
// Macros to simplify logging. The argument to the macro can be any type
|
||||
// that log streams have an output operator for.
|
||||
|
||||
#define TP_LOG_FLUSH_LOG (!logstream::log_initialized || tpie_log().flush())
|
||||
|
||||
// eg: LOG_FATAL(LOG_ID_MSG)
|
||||
#define TP_LOG_ID_MSG __FILE__ << " line " << __LINE__ << ": "
|
||||
|
||||
#define TP_LOG_FATAL(msg) \
|
||||
(!logstream::log_initialized || tpie_log() << setpriority(TPIE_LOG_FATAL) << msg)
|
||||
#define TP_LOG_WARNING(msg) \
|
||||
(!logstream::log_initialized || tpie_log() << setpriority(TPIE_LOG_WARNING) << msg)
|
||||
#define TP_LOG_APP_DEBUG(msg) \
|
||||
(!logstream::log_initialized || tpie_log() << setpriority(TPIE_LOG_APP_DEBUG) << msg)
|
||||
#define TP_LOG_DEBUG(msg) \
|
||||
(!logstream::log_initialized || tpie_log() << setpriority(TPIE_LOG_DEBUG) << msg)
|
||||
#define TP_LOG_MEM_DEBUG(msg) \
|
||||
(!logstream::log_initialized || tpie_log() << setpriority(TPIE_LOG_MEM_DEBUG) << msg)
|
||||
|
||||
#define TP_LOG_FATAL_ID(msg) \
|
||||
(TP_LOG_FATAL(TP_LOG_ID_MSG << msg << "\n"), TP_LOG_FLUSH_LOG)
|
||||
#define TP_LOG_WARNING_ID(msg) \
|
||||
(TP_LOG_WARNING(TP_LOG_ID_MSG << msg << "\n"), TP_LOG_FLUSH_LOG)
|
||||
#define TP_LOG_APP_DEBUG_ID(msg) \
|
||||
(TP_LOG_APP_DEBUG(TP_LOG_ID_MSG << msg << "\n"), TP_LOG_FLUSH_LOG)
|
||||
#define TP_LOG_DEBUG_ID(msg) \
|
||||
(TP_LOG_DEBUG(TP_LOG_ID_MSG << msg << "\n"), TP_LOG_FLUSH_LOG)
|
||||
#define TP_LOG_MEM_DEBUG_ID(msg) \
|
||||
(TP_LOG_MEM_DEBUG(TP_LOG_ID_MSG << msg << "\n"), TP_LOG_FLUSH_LOG)
|
||||
|
||||
#define TP_LOG_SET_THRESHOLD(level) (tpie_log() << setthreshold(level))
|
||||
|
||||
#else // !TPL_LOGGING
|
||||
|
||||
// We are not compiling logging.
|
||||
|
||||
#define TP_LOG_FATAL(msg)
|
||||
#define TP_LOG_WARNING(msg)
|
||||
#define TP_LOG_APP_DEBUG(msg)
|
||||
#define TP_LOG_DEBUG(msg)
|
||||
#define TP_LOG_MEM_DEBUG(msg)
|
||||
|
||||
#define TP_LOG_FATAL_ID(msg)
|
||||
#define TP_LOG_WARNING_ID(msg)
|
||||
#define TP_LOG_APP_DEBUG_ID(msg)
|
||||
#define TP_LOG_DEBUG_ID(msg)
|
||||
#define TP_LOG_MEM_DEBUG_ID(msg)
|
||||
|
||||
#define TP_LOG_SET_THRESHOLD(level)
|
||||
#define TP_LOG_FLUSH_LOG {}
|
||||
|
||||
#endif // TPL_LOGGING
|
||||
|
||||
#endif // _TPIE_LOG_H
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// File: tpie_stats.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: tpie_stats.h,v 1.5 2004/08/12 12:35:32 jan Exp $
|
||||
//
|
||||
// The tpie_stats class for recording statistics. The parameter C is
|
||||
// the number of statistics to be recorded.
|
||||
//
|
||||
#ifndef _TPIE_STATS_H
|
||||
#define _TPIE_STATS_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
template<int C>
|
||||
class tpie_stats {
|
||||
private:
|
||||
|
||||
// The array storing the C statistics.
|
||||
TPIE_OS_OFFSET stats_[C];
|
||||
|
||||
public:
|
||||
|
||||
// Reset all counts to 0.
|
||||
void reset() {
|
||||
for (int i = 0; i < C; i++)
|
||||
stats_[i] = 0;
|
||||
}
|
||||
// Default constructor. Set all counts to 0.
|
||||
tpie_stats() {
|
||||
reset();
|
||||
}
|
||||
// Copy constructor.
|
||||
tpie_stats(const tpie_stats<C>& ts) {
|
||||
for (int i = 0; i < C; i++)
|
||||
stats_[i] = ts.stats_[i];
|
||||
}
|
||||
// Record ONE event of type t.
|
||||
void record(int t) {
|
||||
stats_[t]++;
|
||||
}
|
||||
// Record k events of type t.
|
||||
void record(int t, TPIE_OS_OFFSET k) {
|
||||
stats_[t] += k;
|
||||
}
|
||||
// Record the events stored in s.
|
||||
void record(const tpie_stats<C>& s) {
|
||||
for (int i = 0; i < C; i++)
|
||||
stats_[i] += s.stats_[i];
|
||||
}
|
||||
// Set the number of type t events to k.
|
||||
void set(int t, TPIE_OS_OFFSET k) {
|
||||
stats_[t] = k;
|
||||
}
|
||||
// Inquire the number of type t events.
|
||||
TPIE_OS_OFFSET get(int t) const {
|
||||
return stats_[t];
|
||||
}
|
||||
// Destructor.
|
||||
~tpie_stats() {}
|
||||
};
|
||||
|
||||
template<int C>
|
||||
const tpie_stats<C> operator-(const tpie_stats<C> & lhs,
|
||||
const tpie_stats<C> & rhs) {
|
||||
tpie_stats<C> res;
|
||||
for (int i = 0; i < C; i++)
|
||||
res.stats_[i] = lhs.stats_[i] - rhs.stats_[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif //_TPIE_STATS_H
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: tpie_stats_coll.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: tpie_stats_coll.h,v 1.4 2003/04/17 20:05:10 jan Exp $
|
||||
//
|
||||
// Statistics for block collections.
|
||||
|
||||
#ifndef _TPIE_STATS_COLL_H
|
||||
#define _TPIE_STATS_COLL_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <tpie_stats.h>
|
||||
|
||||
#define TPIE_STATS_COLLECTION_COUNT 9
|
||||
enum TPIE_STATS_COLLECTION {
|
||||
BLOCK_GET = 0,
|
||||
BLOCK_PUT,
|
||||
BLOCK_NEW,
|
||||
BLOCK_DELETE,
|
||||
BLOCK_SYNC,
|
||||
COLLECTION_OPEN,
|
||||
COLLECTION_CLOSE,
|
||||
COLLECTION_CREATE,
|
||||
COLLECTION_DELETE
|
||||
};
|
||||
|
||||
typedef tpie_stats<TPIE_STATS_COLLECTION_COUNT> tpie_stats_collection;
|
||||
|
||||
#endif //_TPIE_STATS_COLL_H
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// File: tpie_stats_stream.h
|
||||
// Authors: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: tpie_stats_stream.h,v 1.3 2004/08/17 16:48:25 jan Exp $
|
||||
//
|
||||
// Statistics for streams.
|
||||
|
||||
#ifndef _TPIE_STATS_STREAM_H
|
||||
#define _TPIE_STATS_STREAM_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <tpie_stats.h>
|
||||
|
||||
#define TPIE_STATS_STREAM_COUNT 11
|
||||
enum TPIE_STATS_STREAM {
|
||||
BLOCK_READ = 0,
|
||||
BLOCK_WRITE,
|
||||
ITEM_READ,
|
||||
ITEM_WRITE,
|
||||
ITEM_SEEK,
|
||||
STREAM_OPEN,
|
||||
STREAM_CLOSE,
|
||||
STREAM_CREATE,
|
||||
STREAM_DELETE,
|
||||
SUBSTREAM_CREATE,
|
||||
SUBSTREAM_DELETE
|
||||
};
|
||||
|
||||
typedef tpie_stats<TPIE_STATS_STREAM_COUNT> tpie_stats_stream;
|
||||
|
||||
#endif //_TPIE_STATS_STREAM_H
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2001 Octavian Procopiuc
|
||||
//
|
||||
// File: tpie_stats_tree.h
|
||||
// Author: Octavian Procopiuc <tavi@cs.duke.edu>
|
||||
//
|
||||
// $Id: tpie_stats_tree.h,v 1.2 2003/04/17 20:07:23 jan Exp $
|
||||
//
|
||||
//
|
||||
#ifndef _TPIE_STATS_TREE_H
|
||||
#define _TPIE_STATS_TREE_H
|
||||
|
||||
// Get definitions for working with Unix and Windows
|
||||
#include <portability.h>
|
||||
|
||||
#include <tpie_stats.h>
|
||||
|
||||
#define TPIE_STATS_TREE_COUNT 14
|
||||
enum TPIE_STATS_TREE {
|
||||
LEAF_FETCH = 0,
|
||||
LEAF_RELEASE,
|
||||
LEAF_READ,
|
||||
LEAF_WRITE,
|
||||
LEAF_CREATE,
|
||||
LEAF_DELETE,
|
||||
LEAF_COUNT,
|
||||
NODE_FETCH,
|
||||
NODE_RELEASE,
|
||||
NODE_READ,
|
||||
NODE_WRITE,
|
||||
NODE_CREATE,
|
||||
NODE_DELETE,
|
||||
NODE_COUNT
|
||||
};
|
||||
|
||||
typedef tpie_stats<TPIE_STATS_TREE_COUNT> tpie_stats_tree;
|
||||
|
||||
#endif // _TPIE_STATS_TREE_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user