blob: 66be8b8dde779ad49026e1d8b5854bf91d068a01 [file] [log] [blame]
/*************************************************************************
*
* PathFinder: finding a series of labeled nodes within a
* two-layer directed, cyclic graph.
* Copyright (2013) Sandia Corporation
*
* Copyright (2013) Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
* retains certain rights in this software.
*
* This file is part of PathFinder.
*
* PathFinder is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* PathFinder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PathFinder. If not, see <http://www.gnu.org/licenses/>.
*
* Questions? Contact J. Brian Rigdon (jbrigdo@sandia.gov)
*
*/
/*
* vectorUtils.c
*
* Created on: Jun 21, 2013
* Author: jbrigdo
*/
#include "vectorUtils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* --------
* IntVector Methods
*/
/* constructor */
IntVector *IntVector_new( int size )
{
IntVector *new = malloc( sizeof(IntVector) );
if ( new )
{
int *vector = malloc ( size * sizeof(int) );
if ( vector )
{
new->vector = vector;
new->size = 0;
new->allocatedSize = size;
return( new );
}
else
{
free( new );
return( NULL );
}
}
else
return( NULL );
}
/* destructor */
void IntVector_delete(IntVector *trash)
{
if ( trash )
{
if ( trash->vector )
free( trash->vector );
free( trash );
}
}
/* inserts a new integer at the tail of the vector */
bool IntVector_insertEnd(IntVector *vector, int datum)
{
int current = 0;
int max = 0;
/* some basic error checking */
if ( !vector )
return( false );
current = vector->size;
max = vector->allocatedSize;
if ( current == max ) /* we're full */
{
vector->vector = realloc( vector->vector, 2*max*sizeof(int) );
if ( vector->vector )
{
vector->allocatedSize = 2*max;
}
else
{
fprintf( stderr, "\n\nIntVector_insertEnd failed realloc size = %d\n", current*2 );
return( false );
}
}
vector->vector[current] = datum;
vector->size += 1;
return( true );
}
/*
* A utility method that takes an input string to the next number. If it currently
* points to a number, we iterate past that number, past any whitespace or non-number
* and point to the first digit character we find. If input currently points a non-
* digit character, we find the next digit character and return a pointer to it. If
* no non-digit character is found with these rules, we return null.
*/
static char *findNextNumber(char *input)
{
if ( isdigit( (int)input[0] ) )
{
/* scream through the string to find a non-digit */
++input;
while ( isdigit( (int)input[0] ) && *input != '\0' )
++input;
if ( input[0] == '\0' )
return( NULL );
else
/* now find the next digit */
while ( !isdigit( (int)input[0] ) && *input != '\0' )
++input;
if ( input[0] == '\0' )
return(NULL);
else
return(input);
}
else
{
/* find the first digit character */
do {
if ( input[0] == '\0' )
return(NULL);
++input;
} while ( !isdigit( (int)input[0] ) );
return(input);
}
}
/*
* parse space-delimited null-terminated string into an IntVector.
* Returns the number of integers collected
*/
int IntVector_createFromString(IntVector *vector, char *inputString)
{
int dataCount = 0;
int datum;
/* make sure we have valid pointers passed in*/
if ( !vector || !inputString )
return(0);
/* make sure we're pointing to a digit */
if ( !isdigit((int)inputString[0]))
{
inputString = findNextNumber(inputString);
}
/* ok, at this point, we know we're pointing at a number */
while (inputString) /* set to NULL when there are no more numbers. */
{
datum = atoi(inputString);
inputString = findNextNumber(inputString);
if ( !IntVector_insertEnd(vector, datum) )
return(0); /* realloc failure */
++dataCount;
}
return(dataCount);
}
/* constructor */
CharVector *CharVector_new(int size)
{
CharVector *new = malloc( sizeof(CharVector) );
if ( new )
{
char *string = malloc ( size * sizeof(char) );
if ( string )
{
new->string = string;
new->size = 0;
new->allocatedSize = size;
return( new );
}
else
{
free( new );
return( NULL );
}
}
else
return( NULL );
}
/* destructor */
void CharVector_delete( CharVector *trash )
{
if ( trash )
{
if ( trash->string )
free( trash->string );
free( trash );
}
}
bool CharVector_insertEnd( CharVector *vector, char c )
{
int size = 0;
int max = 0;
/* some basic error checking */
if ( !vector )
return( false );
size = vector->size;
max = vector->allocatedSize;
if ( size == max ) /* we're full */
{
vector->string = realloc( vector->string, 2*size*sizeof(char) );
if ( vector->string )
{
vector->allocatedSize = size*2;
}
else
{
fprintf( stderr, "\n\nIntVector_insertEnd failed realloc size = %d\n", size*2 );
return( false );
}
}
vector->string[size] = c;
vector->size += 1;
return( true );
}
int CharVector_getLineFromFile( CharVector *vector, FILE *input )
{
bool notDoneYet = true;
char c = '\0';
/* Some basic error checking */
if ( !vector || !input )
return( -1 );
vector->size = 0; /* reset the vector prior to filling */
/* get to the next digit */
do {
c = fgetc( input );
if ( feof( input ) || c == '\n' )
notDoneYet = false;
else
if ( ! CharVector_insertEnd( vector, c ) )
return( -1 ); /* CharVector_insertEnd reached a memory limit. Fail */
} while ( notDoneYet );
/* make the data a c-string */
if ( ! CharVector_insertEnd( vector, '\0' ) )
return( -1 ); /* CharVector_insertEnd reached a memory limit. Fail */
return( vector->size );
}
/* -------------------------------------------
* Node Pointer Vector Method Definitions
*
*/
/* create a new vector allocating specified size */
NodePtrVec *NodePtrVec_new( int initialSize )
{
NodePtrVec *newVector;
Node **vector; /* an array of pointers */
vector = malloc ( initialSize * sizeof(Node *) );
if ( !vector )
{
printf ( "Malloc failure in NodePtrVec creation\n" );
return( NULL );
}
newVector = malloc ( sizeof(NodePtrVec) );
if ( !newVector )
{
free(vector);
printf ( "Malloc failure in NodePtrVec storage creation\n" );
return( NULL );
}
newVector->allocatedSize = initialSize;
newVector->contentSize = 0;
newVector->vector = vector;
return( newVector );
}
/* destructor */
void NodePtrVec_delete( NodePtrVec *trash )
{
if ( trash )
{
if ( trash->vector )
free(trash->vector);
free(trash);
}
}
/* creates duplicate vector (not duplicate nodes!). If exact_copy is true, the
* new vector is the same size as the copied one. If false, then only enough
* room to hold the copy is allocated.
*/
NodePtrVec *NodePtrVec_copy(NodePtrVec *from, bool exact_copy)
{
int i;
if ( !from )
return NULL;
NodePtrVec *to = exact_copy ? NodePtrVec_new(from->allocatedSize)
: NodePtrVec_new(from->contentSize);
if ( !to )
return NULL;
for ( i = 0; i < from->contentSize; ++i )
to->vector[i] = from->vector[i];
to->contentSize = from->contentSize;
return to;
}
/* pushes the element if it can. If a memory allocation is required but
* fails - false is returned
*/
bool NodePtrVec_push( NodePtrVec *vector, Node *node )
{
int current;
int max;
/* some basic error checking */
if ( !vector ) return false;
current = vector->contentSize;
max = vector->allocatedSize;
/* see if our vector is full */
if ( current == max )
{
vector->vector = realloc( vector->vector, 2*max * sizeof(Node *) );
if ( vector->vector )
{
vector->allocatedSize = 2*max;
}
else
{
printf ( "\n\nNodePtrVec_push failed malloc(%d). Node: %d", 2*max, node->id );
if ( node->label )
printf ( ", label: %s\n", node->label );
else
printf ( "\n\n" );
return false;
}
}
/* do the actual pushing */
vector->vector[current] = node;
vector->contentSize += 1;
return true;
}
/* returns the top item and decrements. What do we do to define empty? */
Node * NodePtrVec_pop( NodePtrVec *vector )
{
Node *top = NULL;
/* some basic error checking */
if ( !vector ) return NULL;
if ( vector->contentSize > 0 )
{
vector->contentSize -= 1;
top = vector->vector[vector->contentSize];
}
return top;
}
/* Screams through the vector from bottom to top to find the specified element. If found,
* returns true.
*/
bool NodePtrVec_find( NodePtrVec *vector, Node *node )
{
int i;
/* some basic error checking */
if ( !vector ) return false;
for ( i = 0; i < vector->contentSize; ++i )
if ( vector->vector[i] == node )
return true;
return false;
}
/* Screams through the vector from top to bottom to find the specified element. If found,
* returns true. */
bool NodePtrVec_findReverse( NodePtrVec *vector, Node *node )
{
int i;
/* some basic error checking */
if ( !vector || !vector->vector || !node ) return false;
for ( i = vector->contentSize-1; i >= 0; --i )
if ( vector->vector[i] == node )
return true;
return false;
}
/* Appends the second vector to the first. If the "keepFirst" flag is set, the
* entire second vector is appended to the first. Otherwise, the [0] element of
* the second vector is skipped. This is useful when the last element of the
* first vector is identical to the first element of the second vector, and
* we don't want duplication. (And who, really, wants duplication? Really, who
* wants duplication?)
*/
void NodePtrVec_appendVectors ( NodePtrVec *first, NodePtrVec *second, bool keepFirst )
{
int i;
/* Some basic error checking */
if ( !first || !second )
return;
if ( keepFirst )
i = 0;
else
i = 1;
for ( ; i < second->contentSize; ++i )
NodePtrVec_push( first, second->vector[i] );
}
/* -------------------------------------------
* Node Vec Vec Method definitions
*
* (vector of Node Pointer Vectors )
*/
/* create a new vector allocating specified size */
NodeVecVec *NodeVecVec_new( int initialSize )
{
NodeVecVec *newVector;
NodePtrVec **vector; /* an array of pointers */
vector = malloc ( initialSize * sizeof(NodePtrVec *) );
if ( !vector )
{
printf ( "Malloc failure in NodeVecVec storage creation\n" );
fflush(stdout);
return( NULL );
}
newVector = malloc ( sizeof(NodeVecVec) );
if ( !newVector )
{
free(vector);
printf ( "Malloc failure in NodeVecVec creation\n" );
fflush(stdout);
return( NULL );
}
newVector->allocatedSize = initialSize;
newVector->contentSize = 0;
newVector->vector = vector;
return( newVector );
}
/* destructor */
void NodeVecVec_delete( NodeVecVec *trash )
{
int i;
if ( trash )
{
for ( i = 0; i < trash->contentSize; ++i )
NodePtrVec_delete(trash->vector[i]);
if ( trash->vector )
free(trash->vector);
free(trash);
}
}
/* pushes a copy of the element if it can. If a memory allocation is required but
* fails - false is returned
*/
bool NodeVecVec_insert( NodeVecVec *vector, NodePtrVec *path )
{
int current;
int max;
NodePtrVec *copy = NodePtrVec_copy(path,false);
/* some basic error checking */
if ( !vector || !path || !copy ) return false;
current = vector->contentSize;
max = vector->allocatedSize;
/* see if our vector is full */
if ( current == max )
{
vector->vector = realloc( vector->vector, 2*max * sizeof(Node *) );
if ( vector->vector )
{
vector->allocatedSize = 2*max;
}
else
{
printf ( "\n\nNodeVecVec_push failed malloc\n" );
fflush(stdout);
return false;
}
}
/* do the actual pushing */
vector->vector[current] = copy;
vector->contentSize += 1;
return true;
}