356 lines
10 KiB
C
356 lines
10 KiB
C
// Copyright 2007 Georgia Institute of Technology. All rights reserved.
|
|
/**
|
|
* @file common.h
|
|
*
|
|
* The bare necessities of FASTlib programming in C, including
|
|
* standard types, formatted messages to stderr, and useful libraries
|
|
* and compiler directives.
|
|
*
|
|
* This file should be included before all built-in libraries because
|
|
* it includes the _REENTRANT definition needed for thread-safety.
|
|
* Files base.h or fastlib.h include this file first and may serve as
|
|
* surrogates.
|
|
*
|
|
* @see compiler.h
|
|
*/
|
|
|
|
#ifndef BASE_COMMON_H
|
|
#define BASE_COMMON_H
|
|
|
|
#ifndef _REENTRANT
|
|
#define _REENTRANT
|
|
#endif
|
|
|
|
#include "base/basic_types.h"
|
|
#include "compiler.h"
|
|
#include "ansi_colors.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
#include <float.h>
|
|
|
|
EXTERN_C_BEGIN
|
|
|
|
/** A no-op used in some macros. */
|
|
#define NOP ((void)0)
|
|
|
|
/** Potentially useful for nasty macro expansion. */
|
|
#define COMMA ,
|
|
|
|
|
|
|
|
/* Types and definitions to assist managment of problem scale. */
|
|
|
|
/* Ensure that one and only one problem scale is selected. */
|
|
#if defined(SCALE_MASSIVE)
|
|
#if defined(SCALE_LARGE) || defined(SCALE_NORMAL)
|
|
#error Only one of SCALE_MASSIVE, SCALE_LARGE, or SCALE_NORMAL may be defined.
|
|
#endif
|
|
#elif defined(SCALE_LARGE)
|
|
#if defined(SCALE_NORMAL)
|
|
#error Only one of SCALE_MASSIVE, SCALE_LARGE, or SCALE_NORMAL may be defined.
|
|
#endif
|
|
#elif !defined(SCALE_NORMAL)
|
|
#define SCALE_NORMAL
|
|
#endif
|
|
|
|
/**
|
|
* Index type used in FASTlib for array sizes, etc.
|
|
*
|
|
* Define one of the following (default SCALE_NORMAL):
|
|
*
|
|
* SCALE_NORMAL - Problems are as large can be indexed with your
|
|
* machine's standard integers. As of 2007, this is 32 bits.
|
|
*
|
|
* SCALE_LARGE - Problems are as large as your machine's architecture
|
|
* can support. Unless you have more than 2 billion data points,
|
|
* this will waste some space and reduce cache efficiency.
|
|
*
|
|
* SCALE_MASSIVE - Problems are 64-bit indexed even on 32-bit
|
|
* machines, rendering them larger than RAM.
|
|
*
|
|
* Values are signed to allow uninitialized indices of -1 as well as
|
|
* consideration of potentially negative differences between indices.
|
|
*/
|
|
#if defined(SCALE_MASSIVE)
|
|
typedef int64 index_t; /* For larger than RAM data sets. */
|
|
#elif defined(SCALE_LARGE)
|
|
typedef ssize_t index_t; /* As large as this machine can handle. */
|
|
#elif defined(SCALE_NORMAL)
|
|
typedef int index_t; /* Normal sized data; usually 32-bit. */
|
|
#endif
|
|
|
|
/**
|
|
* Length modifier for emitting index_t with printf.
|
|
*
|
|
* Example:
|
|
* @code
|
|
* index_t i = 42;
|
|
* printf("%"LI"d\n", i);
|
|
* @endcode
|
|
*/
|
|
#if defined(SCALE_MASSIVE)
|
|
#define LI L64
|
|
#elif defined(SCALE_LARGE)
|
|
#define LI "l" /* TODO: confirm correct. */
|
|
#elif defined(SCALE_NORMAL)
|
|
#define LI ""
|
|
#endif
|
|
|
|
/** Size of a kilobyte in bytes. */
|
|
#define KILOBYTE (((size_t)1) << 10)
|
|
/** Size of a megabyte in bytes. */
|
|
#define MEGABYTE (((size_t)1) << 20)
|
|
/** Size of a gigabyte in bytes. */
|
|
#define GIGABYTE (((size_t)1) << 30)
|
|
/* Add more of these as necessary. */
|
|
|
|
|
|
|
|
/* Tools for FASTlib stderr messages, warnings, and errors. */
|
|
|
|
/** Whether to segfault instead of calling C's abort(). */
|
|
extern int segfault_on_abort;
|
|
/** Whether to treat nonfatal warnings as fatal. */
|
|
extern int abort_on_nonfatal;
|
|
/** Whether to wait for user input after nonfatal warnings. */
|
|
extern int pause_on_nonfatal;
|
|
/** Whether to print call locations for notifications. */
|
|
extern int print_notify_locs;
|
|
|
|
/** Different types of messages FASTlib prints to stderr. */
|
|
typedef enum {
|
|
/** Message for an unrecoverable error. */
|
|
FL_MSG_FATAL = 0,
|
|
/** Message for a potentially recoverable warning. */
|
|
FL_MSG_NONFATAL = 1,
|
|
/** Message for a significant but non-problematic event. */
|
|
FL_MSG_NOTIFY_STAR = 2,
|
|
/** Message for a standard, non-problematic event. */
|
|
FL_MSG_NOTIFY = 3
|
|
} fl_msg_t;
|
|
|
|
/** Default markers for FASTlib messages. */
|
|
extern char fl_msg_marker[];
|
|
/** Default colors for FASTlib message markers. */
|
|
extern const char *fl_msg_color[];
|
|
|
|
/**
|
|
* Terminates with an error, flushing all streams.
|
|
*
|
|
* Behavior adjustable with segfault_on_abort, which may be handy for
|
|
* valgrind or other debuggers.
|
|
*/
|
|
COMPILER_NO_RETURN
|
|
void fl_abort(void);
|
|
|
|
/**
|
|
* Waits for the user to press return.
|
|
*
|
|
* This function will obliterate anything in the stdin buffer.
|
|
*/
|
|
void fl_pause(void);
|
|
|
|
/** Prints a colored message header. */
|
|
void fl_print_msg_header(char marker, const char *color);
|
|
|
|
/** Print a location in code. */
|
|
void fl_print_msg_loc(const char *file, const char *func, int line);
|
|
|
|
/** Implementation for FATAL. */
|
|
COMPILER_NO_RETURN
|
|
COMPILER_PRINTF(4, 5)
|
|
void fl_print_fatal_msg(const char *file, const char *func, int line,
|
|
const char* format, ...);
|
|
|
|
/** Implementation for NONFATAL, NOTIFY_STAR, and NOTIFY. */
|
|
COMPILER_PRINTF(5, 6)
|
|
void fl_print_msg(const char *file, const char *func, int line,
|
|
fl_msg_t msg_type, const char* format, ...);
|
|
|
|
/**
|
|
* Aborts, printing call location and a message to stderr.
|
|
*
|
|
* @param msg_params format string and variables, as in printf
|
|
*/
|
|
#define FATAL(msg_params...) (fl_print_fatal_msg( \
|
|
__FILE__, __FUNCTION__, __LINE__, msg_params))
|
|
|
|
/**
|
|
* (Possibly) aborts or pauses, printing call location and a message
|
|
* to stderr.
|
|
*
|
|
* @param msg_params format string and variables, as in printf
|
|
*/
|
|
#define NONFATAL(msg_params...) (fl_print_msg( \
|
|
__FILE__, __FUNCTION__, __LINE__, FL_MSG_NONFATAL, msg_params))
|
|
|
|
/**
|
|
* Prints (possibly) call location and a message with special marker
|
|
* to stderr.
|
|
*
|
|
* @param msg_params format string and variables, as in printf
|
|
*/
|
|
#define NOTIFY_STAR(msg_params...) (fl_print_msg( \
|
|
__FILE__, __FUNCTION__, __LINE__, FL_MSG_NOTIFY_STAR, msg_params))
|
|
|
|
/**
|
|
* Prints (possibly) call location and a message with standard marker
|
|
* to stderr.
|
|
*
|
|
* @param msg_params format string and variables, as in printf
|
|
*/
|
|
#define NOTIFY(msg_params...) (fl_print_msg( \
|
|
__FILE__, __FUNCTION__, __LINE__, FL_MSG_NOTIFY, msg_params))
|
|
|
|
/**
|
|
* Prints a progress bar using ANSI commands to stay in place.
|
|
*
|
|
* For proper formatting, desc should be 22 characters or fewer and
|
|
* the program should avoid output of other text while emitting a
|
|
* progress bar. When finished with a progress bar, emit a newline
|
|
* ('\n') to keep the bar on screen or a line of spaces followed by a
|
|
* carriage return ('\r') to clear it.
|
|
*
|
|
* @param name printed next to the progress bar; max 22 characters
|
|
* @param perc percentage of bar filled; should range from 0 to 100
|
|
*/
|
|
void fl_print_progress(const char *name, int perc);
|
|
|
|
|
|
|
|
/**
|
|
* Writes a string to a stream, converting non-alphanumeric characters
|
|
* other than those found in ok_char to format '%XX', where XX is the
|
|
* hexadecimal ASCII value.
|
|
*
|
|
* @param stream an output stream
|
|
* @param src the string to be written, hexed
|
|
* @param ok_char characters not converted to '%XX'
|
|
*/
|
|
void hex_to_stream(FILE *stream, const char *src, const char *ok_char);
|
|
|
|
/**
|
|
* Writes a source string to a given destination, converting
|
|
* non-alphanumeric characters other than those found in ok_char to
|
|
* format '%XX', where XX is the hexadecimal ASCII value.
|
|
*
|
|
* The destination is assumed large enough to store the hexed string,
|
|
* which may at most tripple in size. The destination should not
|
|
* overlap with the source.
|
|
*
|
|
* @param dest a memory location to receive the copy
|
|
* @param src the string to be copied, hexed
|
|
* @param ok_char characters not converted to '%XX'
|
|
* @returns a pointer to the null-character terminating dest
|
|
*/
|
|
char *hex_to_string(char *dest, const char *src, const char *ok_char);
|
|
|
|
/**
|
|
* Replaces substrings '%XX' with the ASCII character represented by
|
|
* hexadecimal XX. Percent signs with non-hexadecimal trailing
|
|
* characters are unchanged.
|
|
*
|
|
* This function may be paired with fgets or other stream input to
|
|
* invert the hex_to_stream operation.
|
|
*
|
|
* @param str the string to be modified
|
|
* @returns a pointer to the null-character terminating str
|
|
*/
|
|
char *unhex_in_place(char *str);
|
|
|
|
|
|
|
|
/* Tools for expressing success or failure of FASTlib functions. */
|
|
|
|
/**
|
|
* Type for indicating success or failure.
|
|
*
|
|
* Return these rather than ints to indicate your functions' results;
|
|
* ints are interchangeably interpreted with either zero or nonzero
|
|
* for success, but values of this type have fixed meaning.
|
|
*
|
|
* You may extend the meaning of this type in your code by returning
|
|
* integer values other than SUCCESS_FAIL or SUCCESS_PASS, but ensure
|
|
* that failure values are in the range SUCCESS_FAIL-[0,31], success
|
|
* values are in the range SUCCESS_PASS+[0,31], and warning values are
|
|
* in the range SUCCESS_WARN+[-16,15].
|
|
*
|
|
* You may combine error codes with bit-wise & and |. These result in
|
|
* success values equal in rank to the lesser or greater of the two
|
|
* inputs, respectively. Extended information (recorded in the least
|
|
* significant bits) will likely be lost, but PASSED and FAILED checks
|
|
* will work as perscribed.
|
|
*/
|
|
typedef enum {
|
|
/** Upper-bound value indicating failed operation. */
|
|
SUCCESS_FAIL = 31,
|
|
/** A generic warning value. */
|
|
SUCCESS_WARN = 48,
|
|
/** Lower-bound value indicating successful operation. */
|
|
SUCCESS_PASS = 96
|
|
} success_t;
|
|
|
|
/**
|
|
* True on SUCCESS_PASS or greater; false otherwise.
|
|
*
|
|
* Distinct from !FAILED(x). Optimized for the passing case.
|
|
*/
|
|
#define PASSED(x) (likely((x) >= SUCCESS_PASS))
|
|
|
|
/**
|
|
* True on SUCCESS_FAIL or less; false otherwise.
|
|
*
|
|
* Distinct from !PASSED(x). Optimized for the non-failing case.
|
|
*/
|
|
#define FAILED(x) (unlikely((x) <= SUCCESS_FAIL))
|
|
|
|
/**
|
|
* Asserts that an operation passes; otherwise, aborts with a given
|
|
* message.
|
|
*
|
|
* This optimized check occurs regardless of debug mode.
|
|
*/
|
|
#define MUST_PASS_MSG(x, msg_params...) \
|
|
(likely(x >= SUCCESS_PASS) ? NOP : FATAL(msg_params))
|
|
|
|
/**
|
|
* Asserts that an operation passes; otherwise, aborts with a standard
|
|
* message.
|
|
*
|
|
* This optimized check occurs regardless of debug mode.
|
|
*/
|
|
#define MUST_PASS(x) \
|
|
MUST_PASS_MSG(x, "MUST_PASS failed: %s", #x)
|
|
|
|
/**
|
|
* Asserts that an operation does not fail; otherwise, aborts with a
|
|
* given message.
|
|
*
|
|
* This optimized check occurs regardless of debug mode.
|
|
*/
|
|
#define MUST_NOT_FAIL_MSG(x, msg_params...) \
|
|
(likely(x > SUCCESS_FAIL) ? NOP : FATAL(msg_params))
|
|
|
|
/**
|
|
* Asserts that an operation does not fail; otherwise, aborts with a
|
|
* standard message.
|
|
*
|
|
* This optimized check occurs regardless of debug mode.
|
|
*/
|
|
#define MUST_NOT_FAIL(x) \
|
|
MUST_NOT_FAIL_MSG(x, "MUST_NOT_FAIL failed: %s", #x)
|
|
|
|
/** Converts C library non-negative success into a success_t. */
|
|
#define SUCCESS_FROM_C(x) (unlikely((x) < 0) ? SUCCESS_FAIL : SUCCESS_PASS)
|
|
|
|
|
|
|
|
EXTERN_C_END
|
|
|
|
#endif /* BASE_COMMON_H */
|