blob: 67096941a9e4cb67a37792ab50b9c46d1d50c12b [file] [log] [blame] [edit]
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include "util.h"
#include "log.h"
/* This file contains utility functions widely used in *
* my programs. Many are simply versions of file and *
* memory grabbing routines that take the same *
* arguments as the standard library ones, but exit *
* the program if they find an error condition. */
static int file_line_number = 0; /* file in line number being parsed */
char *out_file_prefix = NULL;
vpr_PrintHandlerInfo vpr_printf_info = log_print_info;
vpr_PrintHandlerWarning vpr_printf_warning = log_print_warning;
vpr_PrintHandlerError vpr_printf_error = log_print_error;
vpr_PrintHandlerDirect vpr_printf_direct = log_print_direct;
static int cont; /* line continued? */
/* Returns the min of cur and max. If cur > max, a warning
* is emitted. */
int limit_value(int cur, int max, const char *name) {
if (cur > max) {
vpr_printf_warning(__FILE__, __LINE__,
"%s is being limited from [%d] to [%d]\n", name, cur, max);
return max;
}
return cur;
}
/* An alternate for strncpy since strncpy doesn't work as most
* people would expect. This ensures null termination */
char *my_strncpy(char *dest, const char *src, size_t size) {
/* Find string's length */
size_t len = strlen(src);
/* Cap length at (num - 1) to leave room for \0 */
if (size <= len)
len = (size - 1);
/* Copy as much of string as we can fit */
memcpy(dest, src, len);
/* explicit null termination */
dest[len] = '\0';
return dest;
}
/* Uses global var 'out_file_prefix' */
FILE *my_fopen(const char *fname, const char *flag, int prompt) {
FILE *fp;
size_t Len;
char *new_fname = NULL;
char prompt_filename[256];
file_line_number = 0;
/* Appends a prefix string for output files */
if (out_file_prefix) {
if (strchr(flag, 'w')) {
Len = 1; /* NULL char */
Len += strlen(out_file_prefix);
Len += strlen(fname);
new_fname = (char *) my_malloc(Len * sizeof(char));
strcpy(new_fname, out_file_prefix);
strcat(new_fname, fname);
fname = new_fname;
}
}
if (prompt) {
int check_num_of_entered_values = scanf("%s", prompt_filename);
while (getchar() != '\n')
;
while (check_num_of_entered_values != 1) {
vpr_printf_error(__FILE__, __LINE__,
"Was expecting one file name to be entered, with no spaces. You have entered %d parameters. Please try again: \n",
check_num_of_entered_values);
check_num_of_entered_values = scanf("%s", prompt_filename);
}
fname = prompt_filename;
}
if (NULL == (fp = fopen(fname, flag))) {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"Error opening file %s for %s access: %s.\n", fname, flag, strerror(errno));
}
if (new_fname)
free(new_fname);
return (fp);
}
char *my_strdup(const char *str) {
size_t Len;
char *Dst;
if (str == NULL ) {
return NULL ;
}
Len = 1 + strlen(str);
Dst = (char *) my_malloc(Len * sizeof(char));
memcpy(Dst, str, Len);
return Dst;
}
int my_atoi(const char *str) {
/* Returns the integer represented by the first part of the character *
* string. */
if (str[0] < '0' || str[0] > '9') {
if (!(str[0] == '-' && str[1] >= '0' && str[1] <= '9')) {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"expected number instead of '%s'.\n", str);
}
}
return (atoi(str));
}
void *my_calloc_impl(size_t nelem, size_t size, const char* const file, const int line) {
void *ret;
if (nelem == 0) {
return NULL ;
}
if ((ret = calloc(nelem, size)) == NULL ) {
vpr_throw(VPR_ERROR_UNKNOWN, file, line,
"Error: Unable to calloc memory. Aborting.\n");
}
return (ret);
}
void *my_malloc_impl(size_t size, const char* const file, const int line) {
void *ret;
if (size == 0) {
return NULL ;
}
if ((ret = malloc(size)) == NULL ) {
vpr_throw(VPR_ERROR_UNKNOWN, file, line,
"Error: Unable to malloc memory. Aborting.\n");
}
return (ret);
}
void *my_realloc_impl(void *ptr, size_t size, const char* const file, const int line) {
void *ret;
if (size <= 0) {
vpr_printf_warning(file, line,
"reallocating of size <= 0.\n");
}
ret = realloc(ptr, size);
if (NULL == ret) {
vpr_printf_error(file, line,
"Unable to realloc memory. Aborting. "
"ptr=%p, Size=%d.\n", ptr, (int) size);
if (ptr == NULL ) {
vpr_printf_error(file, line,
"my_realloc: ptr == NULL. Aborting.\n");
}
vpr_throw(VPR_ERROR_UNKNOWN, file, line,
"Unable to realloc memory. Aborting. ptr=%p, Size=%d.\n", ptr, (int) size);
}
return (ret);
}
void *my_chunk_malloc(size_t size, t_chunk *chunk_info) {
/* This routine should be used for allocating fairly small data *
* structures where memory-efficiency is crucial. This routine allocates *
* large "chunks" of data, and parcels them out as requested. Whenever *
* it mallocs a new chunk it adds it to the linked list pointed to by *
* chunk_info->chunk_ptr_head. This list can be used to free the *
* chunked memory. *
* Information about the currently open "chunk" must be stored by the *
* user program. chunk_info->mem_avail_ptr points to an int storing *
* how many bytes are left in the current chunk, while *
* chunk_info->next_mem_loc_ptr is the address of a pointer to the *
* next free bytes in the chunk. To start a new chunk, simply set *
* chunk_info->mem_avail_ptr = 0. Each independent set of data *
* structures should use a new chunk. */
/* To make sure the memory passed back is properly aligned, I must *
* only send back chunks in multiples of the worst-case alignment *
* restriction of the machine. On most machines this should be *
* a long, but on 64-bit machines it might be a long long or a *
* double. Change the typedef below if this is the case. */
typedef long Align;
#define CHUNK_SIZE 32768
#define FRAGMENT_THRESHOLD 100
char *tmp_ptr;
int aligned_size;
assert(chunk_info->mem_avail >= 0);
if ((size_t) (chunk_info->mem_avail) < size) { /* Need to malloc more memory. */
if (size > CHUNK_SIZE) { /* Too big, use standard routine. */
tmp_ptr = (char *) my_malloc(size);
/* When debugging, uncomment the code below to see if memory allocation size */
/* makes sense */
/*#ifdef DEBUG
vpr_printf("NB: my_chunk_malloc got a request for %d bytes.\n", size);
vpr_printf("You should consider using my_malloc for such big requests.\n");
#endif */
assert(chunk_info != NULL);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, tmp_ptr);
return (tmp_ptr);
}
if (chunk_info->mem_avail < FRAGMENT_THRESHOLD) { /* Only a small scrap left. */
chunk_info->next_mem_loc_ptr = (char *) my_malloc(CHUNK_SIZE);
chunk_info->mem_avail = CHUNK_SIZE;
assert(chunk_info != NULL);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, chunk_info->next_mem_loc_ptr);
}
/* Execute else clause only when the chunk we want is pretty big, *
* and would leave too big an unused fragment. Then we use malloc *
* to allocate normally. */
else {
tmp_ptr = (char *) my_malloc(size);
assert(chunk_info != NULL);
chunk_info->chunk_ptr_head = insert_in_vptr_list(
chunk_info->chunk_ptr_head, tmp_ptr);
return (tmp_ptr);
}
}
/* Find the smallest distance to advance the memory pointer and keep *
* everything aligned. */
if (size % sizeof(Align) == 0) {
aligned_size = size;
} else {
aligned_size = size + sizeof(Align) - size % sizeof(Align);
}
tmp_ptr = chunk_info->next_mem_loc_ptr;
chunk_info->next_mem_loc_ptr += aligned_size;
chunk_info->mem_avail -= aligned_size;
return (tmp_ptr);
}
void free_chunk_memory(t_chunk *chunk_info) {
/* Frees the memory allocated by a sequence of calls to my_chunk_malloc. */
struct s_linked_vptr *curr_ptr, *prev_ptr;
curr_ptr = chunk_info->chunk_ptr_head;
while (curr_ptr != NULL ) {
free(curr_ptr->data_vptr); /* Free memory "chunk". */
prev_ptr = curr_ptr;
curr_ptr = curr_ptr->next;
free(prev_ptr); /* Free memory used to track "chunk". */
}
chunk_info->chunk_ptr_head = NULL;
chunk_info->mem_avail = 0;
chunk_info->next_mem_loc_ptr = NULL;
}
struct s_linked_vptr *insert_in_vptr_list(struct s_linked_vptr *head, void *vptr_to_add) {
/* Inserts a new element at the head of a linked list of void pointers. *
* Returns the new head of the list. */
struct s_linked_vptr *linked_vptr;
linked_vptr = (struct s_linked_vptr *) my_malloc(
sizeof(struct s_linked_vptr));
linked_vptr->data_vptr = vptr_to_add;
linked_vptr->next = head;
return (linked_vptr); /* New head of the list */
}
/* Deletes the element at the head of a linked list of void pointers. *
* Returns the new head of the list. */
struct s_linked_vptr *delete_in_vptr_list(struct s_linked_vptr *head) {
struct s_linked_vptr *linked_vptr;
if (head == NULL )
return NULL ;
linked_vptr = head->next;
free(head);
return linked_vptr; /* New head of the list */
}
t_linked_int *insert_in_int_list(t_linked_int * head, int data,
t_linked_int ** free_list_head_ptr) {
/* Inserts a new element at the head of a linked list of integers. Returns *
* the new head of the list. One argument is the address of the head of *
* a list of free ilist elements. If there are any elements on this free *
* list, the new element is taken from it. Otherwise a new one is malloced. */
t_linked_int *linked_int;
if (*free_list_head_ptr != NULL ) {
linked_int = *free_list_head_ptr;
*free_list_head_ptr = linked_int->next;
} else {
linked_int = (t_linked_int *) my_malloc(sizeof(t_linked_int));
}
linked_int->data = data;
linked_int->next = head;
return (linked_int);
}
void free_int_list(t_linked_int ** int_list_head_ptr) {
/* This routine truly frees (calls free) all the integer list elements *
* on the linked list pointed to by *head, and sets head = NULL. */
t_linked_int *linked_int, *next_linked_int;
linked_int = *int_list_head_ptr;
while (linked_int != NULL ) {
next_linked_int = linked_int->next;
free(linked_int);
linked_int = next_linked_int;
}
*int_list_head_ptr = NULL;
}
void alloc_ivector_and_copy_int_list(t_linked_int ** list_head_ptr,
int num_items, struct s_ivec *ivec, t_linked_int ** free_list_head_ptr) {
/* Allocates an integer vector with num_items elements and copies the *
* integers from the list pointed to by list_head (of which there must be *
* num_items) over to it. The int_list is then put on the free list, and *
* the list_head_ptr is set to NULL. */
t_linked_int *linked_int, *list_head;
int i, *list;
list_head = *list_head_ptr;
if (num_items == 0) { /* Empty list. */
ivec->nelem = 0;
ivec->list = NULL;
if (list_head != NULL ) {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"alloc_ivector_and_copy_int_list: Copied %d elements, "
"but list at %p contains more.\n", num_items,
(void *) list_head);
}
return;
}
ivec->nelem = num_items;
list = (int *) my_malloc(num_items * sizeof(int));
ivec->list = list;
linked_int = list_head;
for (i = 0; i < num_items - 1; i++) {
list[i] = linked_int->data;
linked_int = linked_int->next;
}
list[num_items - 1] = linked_int->data;
if (linked_int->next != NULL ) {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"Error in alloc_ivector_and_copy_int_list:\n Copied %d elements, "
"but list at %p contains more.\n", num_items,
(void *) list_head);
}
linked_int->next = *free_list_head_ptr;
*free_list_head_ptr = list_head;
*list_head_ptr = NULL;
}
char *my_fgets(char *buf, int max_size, FILE * fp) {
/* Get an input line, update the line number and cut off *
* any comment part. A \ at the end of a line with no *
* comment part (#) means continue. my_fgets should give *
* identical results for Windows (\r\n) and Linux (\n) *
* newlines, since it replaces each carriage return \r *
* by a newline character \n. Returns NULL after EOF. */
char ch;
int i;
cont = 0; /* line continued? */
file_line_number++; /* global variable */
for (i = 0; i < max_size - 1; i++) { /* Keep going until the line finishes or the buffer is full */
ch = fgetc(fp);
if (feof(fp)) { /* end of file */
if (i == 0) {
return NULL ; /* required so we can write while (my_fgets(...) != NULL) */
} else { /* no newline before end of file - last line must be returned */
buf[i] = '\0';
return buf;
}
}
if (ch == '#') { /* comment */
buf[i] = '\0';
while ((ch = fgetc(fp)) != '\n' && !feof(fp))
; /* skip the rest of the line */
return buf;
}
if (ch == '\r' || ch == '\n') { /* newline (cross-platform) */
if (i != 0 && buf[i - 1] == '\\') { /* if \ at end of line, line continued */
cont = 1;
buf[i - 1] = '\n'; /* May need this for tokens */
buf[i] = '\0';
} else {
buf[i] = '\n';
buf[i + 1] = '\0';
}
return buf;
}
buf[i] = ch; /* copy character into the buffer */
}
/* Buffer is full but line has not terminated, so error */
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"Error on line %d -- line is too long for input buffer.\n"
"All lines must be at most %d characters long.\n",
file_line_number, BUFSIZE - 2);
return NULL;
}
char *my_strtok(char *ptr, const char *tokens, FILE * fp, char *buf) {
/* Get next token, and wrap to next line if \ at end of line. *
* There is a bit of a "gotcha" in strtok. It does not make a *
* copy of the character array which you pass by pointer on the *
* first call. Thus, you must make sure this array exists for *
* as long as you are using strtok to parse that line. Don't *
* use local buffers in a bunch of subroutines calling each *
* other; the local buffer may be overwritten when the stack is *
* restored after return from the subroutine. */
char *val;
val = strtok(ptr, tokens);
for (;;) {
if (val != NULL || cont == 0)
return (val);
/* return unless we have a null value and a continuation line */
if (my_fgets(buf, BUFSIZE, fp) == NULL )
return (NULL );
val = strtok(buf, tokens);
}
}
void free_ivec_vector(struct s_ivec *ivec_vector, int nrmin, int nrmax) {
/* Frees a 1D array of integer vectors. */
int i;
for (i = nrmin; i <= nrmax; i++)
if (ivec_vector[i].nelem != 0)
free(ivec_vector[i].list);
free(ivec_vector + nrmin);
}
void free_ivec_matrix(struct s_ivec **ivec_matrix, int nrmin, int nrmax,
int ncmin, int ncmax) {
/* Frees a 2D matrix of integer vectors (ivecs). */
int i, j;
for (i = nrmin; i <= nrmax; i++) {
for (j = ncmin; j <= ncmax; j++) {
if (ivec_matrix[i][j].nelem != 0) {
free(ivec_matrix[i][j].list);
}
}
}
free_matrix(ivec_matrix, nrmin, nrmax, ncmin, sizeof(struct s_ivec));
}
void free_ivec_matrix3(struct s_ivec ***ivec_matrix3, int nrmin, int nrmax,
int ncmin, int ncmax, int ndmin, int ndmax) {
/* Frees a 3D matrix of integer vectors (ivecs). */
int i, j, k;
for (i = nrmin; i <= nrmax; i++) {
for (j = ncmin; j <= ncmax; j++) {
for (k = ndmin; k <= ndmax; k++) {
if (ivec_matrix3[i][j][k].nelem != 0) {
free(ivec_matrix3[i][j][k].list);
}
}
}
}
free_matrix3(ivec_matrix3, nrmin, nrmax, ncmin, ncmax, ndmin,
sizeof(struct s_ivec));
}
void **alloc_matrix(int nrmin, int nrmax, int ncmin, int ncmax, size_t elsize) {
/* allocates an generic matrix with nrmax-nrmin + 1 rows and ncmax - *
* ncmin + 1 columns, with each element of size elsize. i.e. *
* returns a pointer to a storage block [nrmin..nrmax][ncmin..ncmax].*
* Simply cast the returned array pointer to the proper type. */
int i;
char **cptr;
cptr = (char **) my_malloc((nrmax - nrmin + 1) * sizeof(char *));
cptr -= nrmin;
for (i = nrmin; i <= nrmax; i++) {
cptr[i] = (char *) my_malloc((ncmax - ncmin + 1) * elsize);
cptr[i] -= ncmin * elsize / sizeof(char); /* sizeof(char) = 1 */
}
return ((void **) cptr);
}
void ***alloc_matrix3(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax,
size_t elsize) {
/* allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax - *
* ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each *
* element of size elsize. i.e. returns a pointer to a storage block *
* [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax]. Simply cast the *
* returned array pointer to the proper type. */
int i, j;
char ***cptr;
cptr = (char ***) my_malloc((nrmax - nrmin + 1) * sizeof(char **));
cptr -= nrmin;
for (i = nrmin; i <= nrmax; i++) {
cptr[i] = (char **) my_malloc((ncmax - ncmin + 1) * sizeof(char *));
cptr[i] -= ncmin;
for (j = ncmin; j <= ncmax; j++) {
cptr[i][j] = (char *) my_malloc((ndmax - ndmin + 1) * elsize);
cptr[i][j] -= ndmin * elsize / sizeof(char); /* sizeof(char) = 1) */
}
}
return ((void ***) cptr);
}
void ****alloc_matrix4(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax,
int nemin, int nemax, size_t elsize) {
/* allocates a 3D generic matrix with nrmax-nrmin + 1 rows, ncmax - *
* ncmin + 1 columns, and a depth of ndmax-ndmin + 1, with each *
* element of size elsize. i.e. returns a pointer to a storage block *
* [nrmin..nrmax][ncmin..ncmax][ndmin..ndmax]. Simply cast the *
* returned array pointer to the proper type. */
int i;
char ****cptr;
cptr = (char ****) my_malloc((nrmax - nrmin + 1) * sizeof(char ***));
cptr -= nrmin;
for (i = nrmin; i <= nrmax; i++) {
cptr[i] = (char ***) alloc_matrix3 (ncmin, ncmax, ndmin, ndmax, nemin, nemax, elsize);
}
return ((void ****) cptr);
}
void *****alloc_matrix5(int nrmin, int nrmax, int ncmin, int ncmax, int ndmin, int ndmax,
int nemin, int nemax, int nfmin, int nfmax, size_t elsize) {
int i;
char *****cptr;
cptr = (char *****) my_malloc((nrmax - nrmin + 1) * sizeof(char ***));
cptr -= nrmin;
for (i = nrmin; i <= nrmax; i++) {
cptr[i] = (char ****) alloc_matrix4 (ncmin, ncmax, ndmin, ndmax, nemin, nemax, nfmin, nfmax, elsize);
}
return ((void *****) cptr);
}
void print_int_matrix3(int ***vptr, int nrmin, int nrmax, int ncmin, int ncmax,
int ndmin, int ndmax, char *file) {
FILE *outfile;
int i, j, k;
outfile = my_fopen(file, "w", 0);
for (k = nrmin; k <= nrmax; ++k) {
fprintf(outfile, "Plane %d\n", k);
for (j = ncmin; j <= ncmax; ++j) {
for (i = ndmin; i <= ndmax; ++i) {
fprintf(outfile, "%d ", vptr[k][j][i]);
}
fprintf(outfile, "\n");
}
fprintf(outfile, "\n");
}
fclose(outfile);
}
/* NB: need to make the pointer type void * instead of void ** to allow *
* any pointer to be passed in without a cast. */
void free_matrix(void *vptr, int nrmin, int nrmax, int ncmin, size_t elsize) {
int i;
char **cptr;
cptr = (char **) vptr;
for (i = nrmin; i <= nrmax; i++)
free(cptr[i] + ncmin * elsize / sizeof(char));
free(cptr + nrmin);
}
void free_matrix3(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax,
int ndmin, size_t elsize) {
int i, j;
char ***cptr;
cptr = (char ***) vptr;
for (i = nrmin; i <= nrmax; i++) {
for (j = ncmin; j <= ncmax; j++)
free(cptr[i][j] + ndmin * elsize / sizeof(char));
free(cptr[i] + ncmin);
}
free(cptr + nrmin);
}
void free_matrix4(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax,
int ndmin, int ndmax, int nemin, size_t elsize) {
int i;
char ****cptr;
cptr = (char ****) vptr;
for (i = nrmin; i <= nrmax; i++) {
free_matrix3 (cptr[i], ncmin, ncmax, ndmin, ndmax, nemin, elsize);
}
free(cptr + nrmin);
}
void free_matrix5(void *vptr, int nrmin, int nrmax, int ncmin, int ncmax,
int ndmin, int ndmax, int nemin, int nemax, int nfmin, size_t elsize) {
int i;
char ****cptr;
cptr = (char ****) vptr;
for (i = nrmin; i <= nrmax; i++) {
free_matrix4 (cptr[i], ncmin, ncmax, ndmin, ndmax, nemin, nemax, nfmin, elsize);
}
free(cptr + nrmin);
}
/* Portable random number generator defined below. Taken from ANSI C by *
* K & R. Not a great generator, but fast, and good enough for my needs. */
#define IA 1103515245u
#define IC 12345u
#define IM 2147483648u
#define CHECK_RAND
static unsigned int current_random = 0;
void my_srandom(int seed) {
current_random = (unsigned int) seed;
}
/* returns the current_random value */
unsigned int get_current_random(){
unsigned int result = current_random;
return result;
}
int my_irand(int imax) {
/* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */
int ival;
/* current_random = (current_random * IA + IC) % IM; */
current_random = current_random * IA + IC; /* Use overflow to wrap */
ival = current_random & (IM - 1); /* Modulus */
ival = (int) ((float) ival * (float) (imax + 0.999) / (float) IM);
#ifdef CHECK_RAND
if ((ival < 0) || (ival > imax)) {
if (ival == imax + 1) {
/* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
ival = imax;
} else {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"Bad value in my_irand, imax = %d ival = %d\n", imax, ival);
}
}
#endif
return (ival);
}
float my_frand(void) {
/* Creates a random float between 0 and 1. i.e. [0..1). */
float fval;
int ival;
current_random = current_random * IA + IC; /* Use overflow to wrap */
ival = current_random & (IM - 1); /* Modulus */
fval = (float) ival / (float) IM;
#ifdef CHECK_RAND
if ((fval < 0) || (fval > 1.)) {
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"Bad value in my_frand, fval = %g\n", fval);
}
#endif
return (fval);
}
bool file_exists(const char * filename) {
FILE * file;
if (filename == NULL ) {
return false;
}
file = fopen(filename, "r");
if (file) {
fclose(file);
return true;
}
return false;
}
int ipow(int base, int exp) {
int result = 1;
assert(exp >= 0);
while (exp) {
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
/* Author: Daniel Chen */
/* Allocate and load partial data into t_vpr_error structure */
/* Note: can also set breakpoint in this function to view callstack prior *
* to VPR failure */
t_vpr_error* alloc_and_load_vpr_error(enum e_vpr_error type, unsigned int line, char* file_name){
t_vpr_error* vpr_error;
vpr_error = (t_vpr_error*)my_calloc(1, sizeof(t_vpr_error));
vpr_error->file_name = (char*)my_calloc(strlen(file_name) + 1, sizeof(char));
vpr_error->message = (char*)my_calloc(1000, sizeof(char));
sprintf(vpr_error->file_name, "%s", file_name);
vpr_error->line_num = line;
vpr_error->type = type;
return vpr_error;
}
/* Date:June 15th, 2013
* Author: Daniel Chen
* Purpose: Used to throw any internal VPR error or architecture
* file error and output the appropriate file name,
* line number, and the error message. Does not return
* anything but throw an exception which will be caught
* main.c.
*/
void vpr_throw(enum e_vpr_error type,
const char* psz_file_name,
unsigned int line_num,
const char* psz_message,
...) {
// Make a variable argument list
va_list va_args;
// Initialize variable argument list
va_start( va_args, psz_message );
// Generate the actual error object and throw it
vvpr_throw(type, psz_file_name, line_num, psz_message, va_args);
// Reset variable argument list
va_end( va_args );
}
/*
* Version of vpr_throw that takes an explicit va_list.
*
* This allows functions that have variable numbers of
* inputs to throw t_vpr_error objects.
*/
void vvpr_throw(enum e_vpr_error type,
const char* psz_file_name,
unsigned int line_num,
const char* psz_message,
va_list args) {
// Allocate the error struct
t_vpr_error* vpr_error = alloc_and_load_vpr_error(type,
line_num, const_cast<char*>(psz_file_name));
// Extract and format message based on variable argument list
vsprintf(vpr_error->message, psz_message, args );
throw vpr_error;
}
/* Date:July 17th, 2013
* Author: Daniel Chen
* Purpose: Checks the file extension of an file to ensure
* correct file format. Returns true if format is
* correct, and false otherwise.
* Note: This is probably a fragile check, but at least
* should prevent common problems such as swapping
* architecture file and blif file on the VPR
* command line.
*/
bool check_file_name_extension(INP const char* file_name,
INP const char* file_extension){
const char* str;
int len_extension;
len_extension = strlen(file_extension);
str = strstr(file_name, file_extension);
if(str == NULL || (*(str + len_extension) != '\0')){
return false;
}
return true;
}
/*
* Returns line number of last opened and read file
*/
int get_file_line_number_of_last_opened_file() {
return file_line_number;
}
/* Performs linear interpolation or extrapolation on the set of (x,y) values specified by the xy_map.
A requested x value is passed in, and we return the interpolated/extrapolated y value at this requested value of x.
Meant for maps where both key and element are numbers.
This is specifically enforced by the explicit instantiations below this function. i.e. only templates
using those types listed in the explicit instantiations below are allowed */
template<typename X, typename Y> Y linear_interpolate_or_extrapolate(INP std::map<X,Y> *xy_map, INP X requested_x){
Y result;
/* the intention of this function is to interpolate/extrapolate. we can't do so with less than 2 values in the xy_map */
if (xy_map->size() < 2){
vpr_throw(VPR_ERROR_UNKNOWN, __FILE__, __LINE__,
"linear_interpolate_or_extrapolate: cannot interpolate/extrapolate based on less than 2 (x,y) pairs");
}
if (xy_map->count(requested_x) == 1){
/* requested x already exists in the x,y map */
result = (*xy_map)[requested_x];
} else {
/* requested x does not exist in the x,y map. need to interpolate/extrapolate */
typename std::map<X,Y>::const_iterator it;
double x_low, x_high, y_low, y_high;
double slope, reference_y, delta_x;
/* get first x greater than the one requested */
it = xy_map->upper_bound(requested_x);
if(it == xy_map->end()){
/* need to extrapolate to higher x. based on the y values at the two largest x values */
it--;
x_high = (double)it->first;
y_high = (double)it->second;
it--;
x_low = (double)it->first;
y_low = (double)it->second;
} else if (it == xy_map->begin()){
/* need to extrapolate to lower x. based on the y values at the two smallest x */
x_low = (double)it->first;
y_low = (double)it->second;
it++;
x_high = (double)it->first;
y_high = (double)it->second;
} else {
/* need to interpolate. based on y values at x just above/below
the one we want */
x_high = (double)it->first;
y_high = (double)it->second;
it--;
x_low = (double)it->first;
y_low = (double)it->second;
}
slope = (y_high - y_low) / (x_high - x_low);
reference_y = y_low;
delta_x = (double)requested_x - x_low;
result = (Y)(reference_y + (slope * delta_x));
}
return result;
}
template double linear_interpolate_or_extrapolate(std::map<int,double> *xy_map, int requested_x); /* (int,double) */
template double linear_interpolate_or_extrapolate(std::map<double,double> *xy_map, double requested_x); /* (double,double) */