Files
mlpack/fastlib2/fastlib/base/common.h
T

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 */