Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace more pointer arrays by std::vector #240

Merged
merged 10 commits into from
Aug 26, 2024
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