Skip to content

Commit

Permalink
Replace pointer arrays by std::vector (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-andre authored Aug 26, 2024
1 parent 198e5dc commit 81c370f
Show file tree
Hide file tree
Showing 19 changed files with 351 additions and 1,198 deletions.
214 changes: 38 additions & 176 deletions src/CoinAdjacencyVector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,62 +22,36 @@
#include <vector>
#include <cassert>
#include <algorithm>
#include <limits>
#include "CoinAdjacencyVector.hpp"

static void *xmalloc( const size_t size );
static void *xrealloc( void *ptr, const size_t size );
#include "CoinAdjacencyVector.hpp"

#define KEEP_SORTED

#define NEW_VECTOR(type, size) ((type *) xmalloc((sizeof(type))*(size)))

CoinAdjacencyVector::CoinAdjacencyVector( size_t _nRows, size_t _iniRowSize )
: nRows_( _nRows )
, rows_( NEW_VECTOR( size_t *, (nRows_*2) ) )
, expandedRows_( rows_ + nRows_ )
, iniRowSpace_( NEW_VECTOR( size_t, ((nRows_ * _iniRowSize) + (3 * nRows_)) ) )
, rowSize_( iniRowSpace_ + (nRows_ * _iniRowSize) )
, rowCap_( rowSize_+nRows_ )
, notUpdated_( rowCap_+nRows_ )
: rows_(std::vector<std::vector<size_t> >(_nRows))
, notUpdated_(std::vector<size_t>(_nRows, 0))
{
rows_[0] = iniRowSpace_;
for ( size_t i=1 ; (i<nRows_) ; ++i )
rows_[i] = rows_[i-1] + _iniRowSize;

std::fill( rowCap_, rowCap_+nRows_, _iniRowSize );
std::fill( notUpdated_, notUpdated_+nRows_, 0);
memset( rowSize_, 0, sizeof(size_t)*nRows_ );
std::fill( expandedRows_, expandedRows_+nRows_, (size_t *)NULL);
for (size_t i=0; i < rows_.size(); ++i)
rows_[i].reserve(_iniRowSize);
}

CoinAdjacencyVector::~CoinAdjacencyVector()
{
for ( size_t i=0 ; (i<nRows_) ; ++i )
if (expandedRows_[i])
free(expandedRows_[i]);

// grouped allocation, not all vectors need to be freed
free(rows_);
free(iniRowSpace_);
}

const size_t *CoinAdjacencyVector::getRow ( size_t idxRow ) const
{
assert(idxRow<this->nRows_);
assert(idxRow<this->rows_.size());

return rows_[idxRow];
return rows_[idxRow].data();
}

bool CoinAdjacencyVector::isNeighbor(size_t idxNode, size_t idxNeigh) const {
size_t *r = rows_[idxNode];
size_t *endR = rows_[idxNode] + rowSize_[idxNode];

#ifdef KEEP_SORTED
return std::binary_search(r, endR, idxNeigh);
return std::binary_search(rows_[idxNode].begin(), rows_[idxNode].end(), idxNeigh);
#else
for ( ; (r<endR) ; ++r )
if (*r == idxNeigh)
for (std::vector<size_t>::const_iterator i=rows_[idxNode].begin(); i != rows_[idxNode].end(); ++i)
if (*i == idxNeigh)
return true;
#endif

Expand All @@ -87,15 +61,13 @@ bool CoinAdjacencyVector::isNeighbor(size_t idxNode, size_t idxNeigh) const {
void CoinAdjacencyVector::addNeighbor( size_t idxNode, size_t idxNeigh, bool addReverse ) {
checkCapNode(idxNode);
#ifdef KEEP_SORTED
char res = CoinAdjacencyVector::tryAddElementSortedVector( this->rows_[idxNode], this->rowSize_[idxNode], idxNeigh );
bool res = tryAddElementSortedVector(rows_[idxNode], idxNeigh);
if (res) {
rowSize_[idxNode]++;
if (addReverse)
addNeighbor( idxNeigh, idxNode, false );
}
#else
rows_[idxNode][rowSize_[idxNode]] = idxNeigh;
rowSize_[idxNode]++;
rows_[idxNode].push_back(idxNeigh);
if (addReverse)
this->addNeighbor(idxNeigh, idxNode, false);
#endif
Expand All @@ -104,179 +76,69 @@ void CoinAdjacencyVector::addNeighbor( size_t idxNode, size_t idxNeigh, bool add

size_t CoinAdjacencyVector::rowSize( size_t idxRow ) const
{
assert(idxRow<this->nRows_);

return rowSize_[idxRow];
}

static void *xmalloc( const size_t size )
{
void *result = malloc( size );
if (!result)
{
fprintf(stderr, "No more memory available. Trying to allocate %zu bytes.", size);
abort();
}
assert(idxRow<this->rows_.size());

return result;
return rows_[idxRow].size();
}

static void *xrealloc( void *ptr, const size_t size )
{
void * res = realloc( ptr, size );
if (!res)
{
fprintf(stderr, "No more memory available. Trying to allocate %zu bytes.", size);
abort();
}

return res;
}


void CoinAdjacencyVector::checkCapNode( const size_t idxNode, const size_t newEl )
{
assert( idxNode < nRows_ );
size_t currCap = rowCap_[idxNode];
size_t currSize = rowSize_[idxNode];
assert( idxNode < rows_.size() );

size_t currCap = rows_[idxNode].capacity();
size_t currSize = rows_[idxNode].size();

// no need to resize
if ( currSize + newEl <= currCap )
return;

// for resizing
const size_t newIdxNodeCap = std::max( rowCap_[idxNode]*2, currSize+newEl );

if ( expandedRows_[idxNode] ) {
// already outside initial vector
rowCap_[idxNode] = newIdxNodeCap;
rows_[idxNode] = expandedRows_[idxNode] = (size_t *)xrealloc(expandedRows_[idxNode], sizeof(size_t)*rowCap_[idxNode] );
return;
}
/*
// node still in the otiginal vector
{
// check extension down, if the capacity
// of the node in the border of the current
// node tight to the border of idxNode (iNode) is available and capacity is enough to
// accomodate required increase in the capacity of idxNode
size_t iNode = idxNode;
size_t accCap = 0;
while (accCap < rowCap_[idxNode]) {
accCap += rowCap_[iNode];
++iNode;
if ( iNode == nRows_ )
break;
}
assert( accCap == rowCap_[idxNode] );
if ( iNode < nRows_ && expandedRows_[iNode]==NULL && currCap + rowCap_[iNode] >= currSize + newEl ) {
expandedRows_[iNode] = (size_t *) xmalloc( sizeof(size_t)*rowCap_[iNode] );
memcpy( expandedRows_[iNode], rows_[iNode], sizeof(size_t)*rowSize_[iNode] );
rows_[iNode] = expandedRows_[iNode];
rowCap_[idxNode] += rowCap_[iNode];
return;
}
}
*/

// will be moved outside the vector, checking if space can be used
// by some node before
{
size_t iNode = idxNode;
while (iNode >= 1) {
--iNode;
if (expandedRows_[iNode] == NULL)
break;
}

if ( iNode != idxNode && (expandedRows_[iNode] == NULL) )
rowCap_[iNode] += rowCap_[idxNode];

// allocating outside and moving
rowCap_[idxNode] = newIdxNodeCap;
expandedRows_[idxNode] = (size_t *) xmalloc( sizeof(size_t)*rowCap_[idxNode] );
memcpy(expandedRows_[idxNode], rows_[idxNode], sizeof(size_t)*currSize );
rows_[idxNode] = expandedRows_[idxNode];
}
const size_t newIdxNodeCap = std::max(currCap*2, currSize+newEl);
rows_[idxNode].reserve(newIdxNodeCap);
}

void CoinAdjacencyVector::fastAddNeighbor( size_t idxNode, size_t idxNeigh )
{
//printf("adding to %zu %zu currCap: %zu currSize: %zu at %p\n", idxNode, idxNeigh, rowCap_[idxNode], rowSize_[idxNode], expandedRows_[idxNode] ); fflush(stdout);
//printf("adding to %zu %zu currCap: %zu currSize: %zu\n", idxNode, idxNeigh, rows_[idxNode].capacity(), rows_[idxNode].size()); fflush(stdout);

checkCapNode(idxNode);

rows_[idxNode][rowSize_[idxNode]++] = idxNeigh;
rows_[idxNode].push_back(idxNeigh);
notUpdated_[idxNode]++;
}

void CoinAdjacencyVector::sort()
{
for ( size_t i=0 ; (i<nRows_) ; ++i )
std::sort(rows_[i], rows_[i]+rowSize_[i]);
for ( size_t i=0 ; i<rows_.size() ; ++i )
std::sort(rows_[i].begin(), rows_[i].end());
}

char CoinAdjacencyVector::tryAddElementSortedVector(size_t* el, size_t n, size_t newEl)
bool CoinAdjacencyVector::tryAddElementSortedVector(std::vector<size_t> &el, size_t newEl)
{
/* doing a binary search */
int l = 0;
int r = n - 1;
int m;
int ip = std::numeric_limits<int>::max(); /* insertion pos */

while (l <= r) {
m = (l + r) / 2;

if (el[m] == newEl) {
return 0;
} else {
if (newEl < el[m]) {
if (m > 0) {
r = m - 1;
} else {
break;
}
} else {
l = m + 1;
}
}
}

if (ip == std::numeric_limits<int>::max()) {
ip = l;
}

assert(ip <= (int)n);

if (ip < (int)n)
memmove( el + ip + 1, el + ip, sizeof(size_t)*(n-ip) );

el[ip] = newEl;
std::vector<size_t>::iterator pos = std::lower_bound(el.begin(), el.end(), newEl);
if (*pos == newEl)
return false;

return 1;
el.insert(pos, newEl);
return true;
}

size_t CoinAdjacencyVector::totalElements() const
{
size_t res = 0;

for ( size_t i=0 ; (i<nRows_) ; ++i )
res += rowSize_[i];
for ( size_t i=0 ; i<rows_.size() ; ++i )
res += rows_[i].size();

return res;
}

void CoinAdjacencyVector::flush() {
for ( size_t i=0 ; (i<this->nRows_) ; ++i ) {
for ( size_t i=0 ; i<this->rows_.size() ; ++i ) {
if (notUpdated_[i]) {
std::sort(rows_[i], rows_[i]+rowSize_[i]);
const size_t *newEnd = std::unique(rows_[i], rows_[i]+rowSize_[i]);
rowSize_[i] = newEnd - rows_[i];
std::sort(rows_[i].begin(), rows_[i].end());
std::vector<size_t>::iterator newEnd = std::unique(rows_[i].begin(), rows_[i].end());
rows_[i].erase(newEnd, rows_[i].end());
notUpdated_[i] = 0;
}
}
Expand All @@ -286,13 +148,13 @@ void CoinAdjacencyVector::addNeighborsBuffer( size_t idxNode, size_t n, const si
checkCapNode(idxNode, n);
for ( size_t i=0 ; (i<n) ; ++i )
if (elements[i] != idxNode) {
rows_[idxNode][rowSize_[idxNode]++] = elements[i];
rows_[idxNode].push_back(elements[i]);
notUpdated_[idxNode]++;
}
}

void CoinAdjacencyVector::sort(size_t idxRow) {
std::sort( this->rows_[idxRow], this->rows_[idxRow] + this->rowSize(idxRow) );
std::sort(rows_[idxRow].begin(), rows_[idxRow].end());
}

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
Expand Down
36 changes: 5 additions & 31 deletions src/CoinAdjacencyVector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define COINADJACENCYVECTOR_H

#include <cstddef>
#include <vector>
#include "CoinUtilsConfig.h"

/**
Expand Down Expand Up @@ -107,55 +108,28 @@ class COINUTILSLIB_EXPORT CoinAdjacencyVector

/**
* Try to add an element to a sorted vector, keeping it sorted.
* Return 1 if element was added and 0 if it was already there.
* Return `true` if element was added and `false` if it was already there.
*
* @param el sorted vector
* @param n size of the sorted vector
* @param newEl element to be added to the sorted vector
**/
static char tryAddElementSortedVector( size_t *el, size_t n, size_t newEl );
static bool tryAddElementSortedVector(std::vector<size_t> &el, size_t newEl);

/**
* Return the total number of elements.
**/
size_t totalElements() const;

private:
/**
* Number of nodes
**/
size_t nRows_;

/**
* Pointers to the current neighbor vector of each node
**/
size_t **rows_;

/**
* Pointers to additional memory allocated
* to neigbors that don't fit in the initial space.
**/
size_t **expandedRows_;

/**
* Initial memory allocated to lines of rows_
**/
size_t *iniRowSpace_;

/**
* Size of each neighbor vector
**/
size_t *rowSize_;

/**
* Current capacity of each neighbor vector
**/
size_t *rowCap_;
std::vector<std::vector<size_t> > rows_;

/**
* Elements added that need to be sorted later
**/
size_t *notUpdated_;
std::vector<size_t> notUpdated_;

/**
* Check if a node can receive a new neighbor
Expand Down
Loading

0 comments on commit 81c370f

Please sign in to comment.