diff --git a/CMakeLists.txt b/CMakeLists.txt index a47c2f0..cb7a1e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,4 +8,5 @@ cmake_minimum_required(VERSION 2.6) add_subdirectory(bin) add_subdirectory(cpu) -add_subdirectory(toolbox) \ No newline at end of file +add_subdirectory(toolbox) +add_subdirectory(mplite) \ No newline at end of file diff --git a/mplite/CMakeLists.txt b/mplite/CMakeLists.txt new file mode 100644 index 0000000..9a0ae2e --- /dev/null +++ b/mplite/CMakeLists.txt @@ -0,0 +1,5 @@ +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(MPLITE_SRC mplite.c) + +add_library(MPLITE_LIB ${MPLITE_SRC}) \ No newline at end of file diff --git a/mplite/mplite.c b/mplite/mplite.c new file mode 100644 index 0000000..7e21524 --- /dev/null +++ b/mplite/mplite.c @@ -0,0 +1,455 @@ +#include "mplite.h" + +#include +#include +#include +#include + +/* + ** A minimum allocation is an instance of the following structure. + ** Larger allocations are an array of these structures where the + ** size of the array is a power of 2. + ** + ** The size of this object must be a power of two. That fact is + ** verified in mplite_init(). + */ +typedef struct mplite_link mplite_link_t; + +struct mplite_link { + int next; /* Index of next free chunk */ + int prev; /* Index of previous free chunk */ +}; + +/* + ** Masks used for mplite_t.aCtrl[] elements. + */ +#define MPLITE_CTRL_LOGSIZE 0x1f /* Log2 Size of this block */ +#define MPLITE_CTRL_FREE 0x20 /* True if not checked out */ + +#ifdef _WIN32 +#define snprintf(buf, buf_size, format, ...) \ + _snprintf(buf, buf_size, format, ## __VA_ARGS__) +#endif /* #ifdef _WIN32 */ + +/* + ** Assuming mplite_t.zPool is divided up into an array of mplite_link_t + ** structures, return a pointer to the idx-th such lik. + */ +#define mplite_getlink(handle, idx) ((mplite_link_t *) \ + (&handle->zPool[(idx) * handle->szAtom])) + +#define mplite_enter(handle) if((handle != NULL) && \ + ((handle)->lock.acquire != NULL)) \ + { (handle)->lock.acquire((handle)->lock.arg); } +#define mplite_leave(handle) if((handle != NULL) && \ + ((handle)->lock.release != NULL)) \ + { (handle)->lock.release((handle)->lock.arg); } + +static int mplite_logarithm(const int iValue); +static int mplite_size(const mplite_t *handle, const void *p); +static void mplite_link(mplite_t *handle, const int i, const int iLogsize); +static void mplite_unlink(mplite_t *handle, const int i, const int iLogsize); +static int mplite_unlink_first(mplite_t *handle, const int iLogsize); +static void *mplite_malloc_unsafe(mplite_t *handle, const int nByte); +static void mplite_free_unsafe(mplite_t *handle, const void *pOld); + +MPLITE_API int mplite_init(mplite_t *handle, const void *buf, + const int buf_size, const int min_alloc, + const mplite_lock_t *lock) +{ + int ii; /* Loop counter */ + int nByte; /* Number of bytes of memory available to this allocator */ + uint8_t *zByte; /* Memory usable by this allocator */ + int nMinLog; /* Log base 2 of minimum allocation size in bytes */ + int iOffset; /* An offset into handle->aCtrl[] */ + + /* Check the parameters */ + if ((NULL == handle) || (NULL == buf) || (buf_size <= 0) || + (min_alloc <= 0)) { + return MPLITE_ERR_INVPAR; + } + + /* Initialize the mplite_t object */ + memset(handle, 0, sizeof (*handle)); + + /* Copy the lock if it is not NULL */ + if (lock != NULL) { + memcpy(&handle->lock, lock, sizeof (handle->lock)); + } + + /* The size of a mplite_link_t object must be a power of two. Verify that + ** this is case. + */ + assert((sizeof (mplite_link_t)&(sizeof (mplite_link_t) - 1)) == 0); + + nByte = buf_size; + zByte = (uint8_t*) buf; + + nMinLog = mplite_logarithm(min_alloc); + handle->szAtom = (1 << nMinLog); + while ((int) sizeof (mplite_link_t) > handle->szAtom) { + handle->szAtom = handle->szAtom << 1; + } + + handle->nBlock = (nByte / (handle->szAtom + sizeof (uint8_t))); + handle->zPool = zByte; + handle->aCtrl = (uint8_t *) & handle->zPool[handle->nBlock * handle->szAtom]; + + for (ii = 0; ii <= MPLITE_LOGMAX; ii++) { + handle->aiFreelist[ii] = -1; + } + + iOffset = 0; + for (ii = MPLITE_LOGMAX; ii >= 0; ii--) { + int nAlloc = (1 << ii); + if ((iOffset + nAlloc) <= handle->nBlock) { + handle->aCtrl[iOffset] = (uint8_t) (ii | MPLITE_CTRL_FREE); + mplite_link(handle, iOffset, ii); + iOffset += nAlloc; + } + assert((iOffset + nAlloc) > handle->nBlock); + } + + return MPLITE_OK; +} + +MPLITE_API void *mplite_malloc(mplite_t *handle, const int nBytes) +{ + int64_t *p = 0; + + /* Check the parameters */ + if ((NULL == handle) || (nBytes <= 0)) { + return NULL; + } + + mplite_enter(handle); + p = mplite_malloc_unsafe(handle, nBytes); + mplite_leave(handle); + + return (void*) p; +} + +MPLITE_API void mplite_free(mplite_t *handle, const void *pPrior) +{ + /* Check the parameters */ + if ((NULL == handle) || (NULL == pPrior)) { + return; + } + + mplite_enter(handle); + mplite_free_unsafe(handle, pPrior); + mplite_leave(handle); +} + +MPLITE_API void *mplite_realloc(mplite_t *handle, const void *pPrior, + const int nBytes) +{ + int nOld; + void *p; + + /* Check the parameters */ + if ((NULL == handle) || (NULL == pPrior) || (nBytes <= 0) || + (nBytes & (nBytes - 1))) { + return NULL; + } + + nOld = mplite_size(handle, pPrior); + if (nBytes <= nOld) { + return (void *) pPrior; + } + mplite_enter(handle); + p = mplite_malloc_unsafe(handle, nBytes); + if (p) { + memcpy(p, pPrior, nOld); + mplite_free_unsafe(handle, pPrior); + } + mplite_leave(handle); + + return p; +} + +MPLITE_API int mplite_roundup(mplite_t *handle, const int n) +{ + int iFullSz; + + /* Check the parameters */ + if ((NULL == handle) || (n > MPLITE_MAX_ALLOC_SIZE)) { + return 0; + } + + for (iFullSz = handle->szAtom; iFullSz < n; iFullSz *= 2); + + return iFullSz; +} + +MPLITE_API void mplite_print_stats(const mplite_t * const handle, + const mplite_putsfunc_t putsfunc) +{ + if ((handle != NULL) && (putsfunc != NULL)) { + char zStats[256]; + snprintf(zStats, sizeof (zStats), "Total number of calls to malloc: %u", + (unsigned) handle->nAlloc); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Total of all malloc calls - includes " + "internal fragmentation: %u", (unsigned) handle->totalAlloc); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Total internal fragmentation: %u", + (unsigned) handle->totalExcess); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Current checkout, including internal " + "fragmentation: %u", handle->currentOut); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Current number of distinct checkouts: %u", + handle->currentCount); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Maximum instantaneous currentOut: %u", + handle->maxOut); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Maximum instantaneous currentCount: %u", + handle->maxCount); + putsfunc(zStats); + + snprintf(zStats, sizeof (zStats), "Largest allocation (exclusive of " + "internal frag): %u", handle->maxRequest); + putsfunc(zStats); + } +} + +/* + ** Return the ceiling of the logarithm base 2 of iValue. + ** + ** Examples: mplite_logarithm(1) -> 0 + ** mplite_logarithm(2) -> 1 + ** mplite_logarithm(4) -> 2 + ** mplite_logarithm(5) -> 3 + ** mplite_logarithm(8) -> 3 + ** mplite_logarithm(9) -> 4 + */ +static int mplite_logarithm(const int iValue) +{ + int iLog; + for (iLog = 0; (1 << iLog) < iValue; iLog++); + return iLog; +} + +/* + ** Return the size of an outstanding allocation, in bytes. The + ** size returned omits the 8-byte header overhead. This only + ** works for chunks that are currently checked out. + */ +static int mplite_size(const mplite_t *handle, const void *p) +{ + int iSize = 0; + if (p) { + int i = ((uint8_t *) p - handle->zPool) / handle->szAtom; + assert(i >= 0 && i < handle->nBlock); + iSize = handle->szAtom * + (1 << (handle->aCtrl[i] & MPLITE_CTRL_LOGSIZE)); + } + return iSize; +} + +/* + ** Link the chunk at handle->aPool[i] so that is on the iLogsize + ** free list. + */ +static void mplite_link(mplite_t *handle, const int i, const int iLogsize) +{ + int x; + assert(i >= 0 && i < handle->nBlock); + assert(iLogsize >= 0 && iLogsize <= MPLITE_LOGMAX); + assert((handle->aCtrl[i] & MPLITE_CTRL_LOGSIZE) == iLogsize); + + x = mplite_getlink(handle, i)->next = handle->aiFreelist[iLogsize]; + mplite_getlink(handle, i)->prev = -1; + if (x >= 0) { + assert(x < handle->nBlock); + mplite_getlink(handle, x)->prev = i; + } + handle->aiFreelist[iLogsize] = i; +} + +/* + ** Unlink the chunk at handle->aPool[i] from list it is currently + ** on. It should be found on handle->aiFreelist[iLogsize]. + */ +static void mplite_unlink(mplite_t *handle, const int i, const int iLogsize) +{ + int next, prev; + assert(i >= 0 && i < handle->nBlock); + assert(iLogsize >= 0 && iLogsize <= MPLITE_LOGMAX); + assert((handle->aCtrl[i] & MPLITE_CTRL_LOGSIZE) == iLogsize); + + next = mplite_getlink(handle, i)->next; + prev = mplite_getlink(handle, i)->prev; + if (prev < 0) { + handle->aiFreelist[iLogsize] = next; + } + else { + mplite_getlink(handle, prev)->next = next; + } + if (next >= 0) { + mplite_getlink(handle, next)->prev = prev; + } +} + +/* + ** Find the first entry on the freelist iLogsize. Unlink that + ** entry and return its index. + */ +static int mplite_unlink_first(mplite_t *handle, const int iLogsize) +{ + int i; + int iFirst; + + assert(iLogsize >= 0 && iLogsize <= MPLITE_LOGMAX); + i = iFirst = handle->aiFreelist[iLogsize]; + assert(iFirst >= 0); + while (i > 0) { + if (i < iFirst) iFirst = i; + i = mplite_getlink(handle, i)->next; + } + mplite_unlink(handle, iFirst, iLogsize); + return iFirst; +} + +/* + ** Return a block of memory of at least nBytes in size. + ** Return NULL if unable. Return NULL if nBytes==0. + ** + ** The caller guarantees that nByte positive. + ** + ** The caller has obtained a lock prior to invoking this + ** routine so there is never any chance that two or more + ** threads can be in this routine at the same time. + */ +static void *mplite_malloc_unsafe(mplite_t *handle, const int nByte) +{ + int i; /* Index of a handle->aPool[] slot */ + int iBin; /* Index into handle->aiFreelist[] */ + int iFullSz; /* Size of allocation rounded up to power of 2 */ + int iLogsize; /* Log2 of iFullSz/POW2_MIN */ + + /* nByte must be a positive */ + assert(nByte > 0); + + /* Keep track of the maximum allocation request. Even unfulfilled + ** requests are counted */ + if ((uint32_t) nByte > handle->maxRequest) { + handle->maxRequest = nByte; + } + + /* Abort if the requested allocation size is larger than the largest + ** power of two that we can represent using 32-bit signed integers. + */ + if (nByte > MPLITE_MAX_ALLOC_SIZE) { + return NULL; + } + + /* Round nByte up to the next valid power of two */ + for (iFullSz = handle->szAtom, iLogsize = 0; iFullSz < nByte; iFullSz *= 2, + iLogsize++) { + } + + /* Make sure handle->aiFreelist[iLogsize] contains at least one free + ** block. If not, then split a block of the next larger power of + ** two in order to create a new free block of size iLogsize. + */ + for (iBin = iLogsize; handle->aiFreelist[iBin] < 0 && iBin <= MPLITE_LOGMAX; + iBin++) { + } + if (iBin > MPLITE_LOGMAX) { + return NULL; + } + i = mplite_unlink_first(handle, iBin); + while (iBin > iLogsize) { + int newSize; + + iBin--; + newSize = 1 << iBin; + handle->aCtrl[i + newSize] = (uint8_t) (MPLITE_CTRL_FREE | iBin); + mplite_link(handle, i + newSize, iBin); + } + handle->aCtrl[i] = (uint8_t) iLogsize; + + /* Update allocator performance statistics. */ + handle->nAlloc++; + handle->totalAlloc += iFullSz; + handle->totalExcess += iFullSz - nByte; + handle->currentCount++; + handle->currentOut += iFullSz; + if (handle->maxCount < handle->currentCount) { + handle->maxCount = handle->currentCount; + } + if (handle->maxOut < handle->currentOut) { + handle->maxOut = handle->currentOut; + } + + /* Return a pointer to the allocated memory. */ + return (void*) &handle->zPool[i * handle->szAtom]; +} + +/* + ** Free an outstanding memory allocation. + */ +static void mplite_free_unsafe(mplite_t *handle, const void *pOld) +{ + uint32_t size, iLogsize; + int iBlock; + + /* Set iBlock to the index of the block pointed to by pOld in + ** the array of handle->szAtom byte blocks pointed to by handle->zPool. + */ + iBlock = ((uint8_t *) pOld - handle->zPool) / handle->szAtom; + + /* Check that the pointer pOld points to a valid, non-free block. */ + assert(iBlock >= 0 && iBlock < handle->nBlock); + assert(((uint8_t *) pOld - handle->zPool) % handle->szAtom == 0); + assert((handle->aCtrl[iBlock] & MPLITE_CTRL_FREE) == 0); + + iLogsize = handle->aCtrl[iBlock] & MPLITE_CTRL_LOGSIZE; + size = 1 << iLogsize; + assert(iBlock + size - 1 < (uint32_t) handle->nBlock); + + handle->aCtrl[iBlock] |= MPLITE_CTRL_FREE; + handle->aCtrl[iBlock + size - 1] |= MPLITE_CTRL_FREE; + assert(handle->currentCount > 0); + assert(handle->currentOut >= (size * handle->szAtom)); + handle->currentCount--; + handle->currentOut -= size * handle->szAtom; + assert(handle->currentOut > 0 || handle->currentCount == 0); + assert(handle->currentCount > 0 || handle->currentOut == 0); + + handle->aCtrl[iBlock] = (uint8_t) (MPLITE_CTRL_FREE | iLogsize); + while (iLogsize < MPLITE_LOGMAX) { + int iBuddy; + if ((iBlock >> iLogsize) & 1) { + iBuddy = iBlock - size; + } + else { + iBuddy = iBlock + size; + } + assert(iBuddy >= 0); + if ((iBuddy + (1 << iLogsize)) > handle->nBlock) break; + if (handle->aCtrl[iBuddy] != (MPLITE_CTRL_FREE | iLogsize)) break; + mplite_unlink(handle, iBuddy, iLogsize); + iLogsize++; + if (iBuddy < iBlock) { + handle->aCtrl[iBuddy] = (uint8_t) (MPLITE_CTRL_FREE | iLogsize); + handle->aCtrl[iBlock] = 0; + iBlock = iBuddy; + } + else { + handle->aCtrl[iBlock] = (uint8_t) (MPLITE_CTRL_FREE | iLogsize); + handle->aCtrl[iBuddy] = 0; + } + size *= 2; + } + mplite_link(handle, iBlock, iLogsize); +} diff --git a/mplite/mplite.h b/mplite/mplite.h new file mode 100644 index 0000000..34e3980 --- /dev/null +++ b/mplite/mplite.h @@ -0,0 +1,222 @@ +/** + * The author disclaims copyright to this source code. In place of + * a legal notice, here is a blessing: + * + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + * + * This file contains the APIs that implement a memory allocation subsystem + * based on SQLite's memsys5 memory subsystem. Refer to + * http://www.sqlite.org/malloc.html for more info. + * + * This version of the memory allocation subsystem omits all + * use of malloc(). The application gives a block of memory + * from which allocations are made and returned by the mplite_malloc() + * and mplite_realloc() implementations. + * + * This memory allocator uses the following algorithm: + * + * 1. All memory allocations sizes are rounded up to a power of 2. + * + * 2. If two adjacent free blocks are the halves of a larger block, + * then the two blocks are coalesed into the single larger block. + * + * 3. New memory is allocated from the first available free block. + * + * This algorithm is described in: J. M. Robson. "Bounds for Some Functions + * Concerning Dynamic Storage Allocation". Journal of the Association for + * Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. + * + * Let n be the size of the largest allocation divided by the minimum + * allocation size (after rounding all sizes up to a power of 2.) Let M + * be the maximum amount of memory ever outstanding at one time. Let + * N be the total amount of memory available for allocation. Robson + * proved that this memory allocator will never breakdown due to + * fragmentation as long as the following constraint holds: + * + * N >= M*(1 + log2(n)/2) - n + 1 + */ +#ifndef MPLITE_H +#define MPLITE_H + +#ifdef _WIN32 +#include "pstdint.h" +#else +#include +#endif /* #ifdef _WIN32 */ + +/** + * @brief The function call returns success + */ +#define MPLITE_OK 0 +/** + * @brief Invalid parameters are passed to a function + */ +#define MPLITE_ERR_INVPAR -1 +/** + * @brief Macro to fix unused parameter compiler warning + */ +#define MPLITE_UNUSED_PARAM(param) (void)(param) +/** + * @brief Maximum size of any allocation is ((1 << @ref MPLITE_LOGMAX) * + * mplite_t.szAtom). Since mplite_t.szAtom is always at least 8 and + * 32-bit integers are used, it is not actually possible to reach this + * limit. + */ +#define MPLITE_LOGMAX 30 +/** + * @brief Maximum allocation size of this memory pool library. All allocations + * must be a power of two and must be expressed by a 32-bit signed + * integer. Hence the largest allocation is 0x40000000 or 1073741824. + */ +#define MPLITE_MAX_ALLOC_SIZE 0x40000000 +/** + * @brief An indicator that a function is a public API + */ +#define MPLITE_API + +/** + * @brief Lock object to be used in a threadsafe memory pool + */ +typedef struct mplite_lock { + void *arg; /**< Argument to be passed to acquire and release function + pointers */ + int (*acquire)(void *arg); /**< Function pointer to acquire a lock */ + int (*release)(void *arg); /**< Function pointer to release a lock */ +} mplite_lock_t; + +/** + * @brief Memory pool object + */ +typedef struct mplite { + /*------------------------------- + Memory available for allocation + -------------------------------*/ + int szAtom; /**< Smallest possible allocation in bytes */ + int nBlock; /**< Number of szAtom sized blocks in zPool */ + uint8_t *zPool; /**< Memory available to be allocated */ + + mplite_lock_t lock; /**< Lock to control access to the memory allocation + subsystem. */ + + /*---------------------- + Performance statistics + ----------------------*/ + uint64_t nAlloc; /**< Total number of calls to malloc */ + uint64_t totalAlloc; /**< Total of all malloc calls - includes internal + fragmentation */ + uint64_t totalExcess; /**< Total internal fragmentation */ + uint32_t currentOut; /**< Current checkout, including internal + fragmentation */ + uint32_t currentCount; /**< Current number of distinct checkouts */ + uint32_t maxOut; /**< Maximum instantaneous currentOut */ + uint32_t maxCount; /**< Maximum instantaneous currentCount */ + uint32_t maxRequest; /**< Largest allocation (exclusive of internal frag) */ + + int aiFreelist[MPLITE_LOGMAX + 1]; /**< List of free blocks. aiFreelist[0] + is a list of free blocks of size mplite_t.szAtom. aiFreelist[1] holds + blocks of size szAtom * 2 and so forth.*/ + + uint8_t *aCtrl; /**< Space for tracking which blocks are checked out and the + size of each block. One byte per block. */ +} mplite_t; + +/** + * @brief Print string function pointer to be passed to @ref mplite_print_stats + * function. This must be same as stdio's puts function mechanism which + * automatically appends a new line character in every call. + */ +typedef int (*mplite_putsfunc_t)(const char* stats); + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the memory pool object. + * @param[in,out] handle Pointer to a @ref mplite_t object which is allocated + * by the caller either from stack, heap, or application's + * memory space. + * @param[in] buf Pointer to a large, contiguous chunk of memory space that + * @ref mplite_t will use to satisfy all of its memory + * allocation needs. This might point to a static array or it + * might be memory obtained from some other application-specific + * mechanism. + * @param[in] buf_size The number of bytes of memory space pointed to by @ref + * buf + * @param[in] min_alloc Minimum size of an allocation. Any call to @ref + * mplite_malloc where nBytes is less than min_alloc will + * be rounded up to min_alloc. min_alloc must be a power of + * two. + * @param[in] lock Pointer to a lock object to control access to the memory + * allocation subsystem of @ref mplite_t object. If this is + * @ref NULL, @ref mplite_t will be non-threadsafe and can only + * be safely used by a single thread. It is safe to allocate + * this in stack because it will be copied to @ref mplite_t + * object. + * @return @ref MPLITE_OK on success and @ref MPLITE_ERR_INVPAR on invalid + * parameters error. + */ +MPLITE_API int mplite_init(mplite_t *handle, const void *buf, + const int buf_size, const int min_alloc, + const mplite_lock_t *lock); + +/** + * @brief Allocate bytes of memory + * @param[in,out] handle Pointer to an initialized @ref mplite_t object + * @param[in] nBytes Number of bytes to allocate + * @return Non-NULL on success, NULL otherwise + */ +MPLITE_API void *mplite_malloc(mplite_t *handle, const int nBytes); + +/** + * @brief Free memory + * @param[in,out] handle Pointer to an initialized @ref mplite_t object + * @param[in] pPrior Allocated buffer + */ +MPLITE_API void mplite_free(mplite_t *handle, const void *pPrior); + +/** + * @brief Change the size of an existing memory allocation. + * @param[in,out] handle Pointer to an initialized @ref mplite_t object + * @param[in] pPrior Existing allocated memory + * @param[in] nBytes Size of the new memory allocation. This is always a value + * obtained from a prior call to mplite_roundup(). Hence, + * this is always a non-negative power of two. If nBytes == 0 + * that means that an oversize allocation (an allocation + * larger than @ref MPLITE_MAX_ALLOC_SIZE) was requested and + * this routine should return NULL without freeing pPrior. + * @return Non-NULL on success, NULL otherwise + */ +MPLITE_API void *mplite_realloc(mplite_t *handle, const void *pPrior, + const int nBytes); + +/** + * @brief Round up a request size to the next valid allocation size. + * @param[in,out] handle Pointer to an initialized @ref mplite_t object + * @param[in] n Request size + * @return Positive non-zero value if the size can be allocated or zero if the + * allocation is too large to be handled. + */ +MPLITE_API int mplite_roundup(mplite_t *handle, const int n); + +/** + * @brief Print the statistics of the memory pool object + * @param[in,out] handle Pointer to an initialized @ref mplite_t object + * @param[in] logfunc Non-NULL log function of the caller. Refer to + * @ref mplite_logfunc_t for the prototype of this function. + */ +MPLITE_API void mplite_print_stats(const mplite_t * const handle, + const mplite_putsfunc_t logfunc); + +/** + * @brief Macro to return the number of times mplite_malloc() has been called. + */ +#define mplite_alloc_count(handle) (((handle) != NULL)? (handle)->nAlloc : 0) + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef MPLITE_H */ diff --git a/mplite/pstdint.h b/mplite/pstdint.h new file mode 100644 index 0000000..12c108a --- /dev/null +++ b/mplite/pstdint.h @@ -0,0 +1,799 @@ +/* A portable stdint.h + **************************************************************************** + * BSD License: + **************************************************************************** + * + * Copyright (c) 2005-2007 Paul Hsieh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************** + * + * Version 0.1.11 + * + * The ANSI C standard committee, for the C99 standard, specified the + * inclusion of a new standard include file called stdint.h. This is + * a very useful and long desired include file which contains several + * very precise definitions for integer scalar types that is + * critically important for making portable several classes of + * applications including cryptography, hashing, variable length + * integer libraries and so on. But for most developers its likely + * useful just for programming sanity. + * + * The problem is that most compiler vendors have decided not to + * implement the C99 standard, and the next C++ language standard + * (which has a lot more mindshare these days) will be a long time in + * coming and its unknown whether or not it will include stdint.h or + * how much adoption it will have. Either way, it will be a long time + * before all compilers come with a stdint.h and it also does nothing + * for the extremely large number of compilers available today which + * do not include this file, or anything comparable to it. + * + * So that's what this file is all about. Its an attempt to build a + * single universal include file that works on as many platforms as + * possible to deliver what stdint.h is supposed to. A few things + * that should be noted about this file: + * + * 1) It is not guaranteed to be portable and/or present an identical + * interface on all platforms. The extreme variability of the + * ANSI C standard makes this an impossibility right from the + * very get go. Its really only meant to be useful for the vast + * majority of platforms that possess the capability of + * implementing usefully and precisely defined, standard sized + * integer scalars. Systems which are not intrinsically 2s + * complement may produce invalid constants. + * + * 2) There is an unavoidable use of non-reserved symbols. + * + * 3) Other standard include files are invoked. + * + * 4) This file may come in conflict with future platforms that do + * include stdint.h. The hope is that one or the other can be + * used with no real difference. + * + * 5) In the current verison, if your platform can't represent + * int32_t, int16_t and int8_t, it just dumps out with a compiler + * error. + * + * 6) 64 bit integers may or may not be defined. Test for their + * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX. + * Note that this is different from the C99 specification which + * requires the existence of 64 bit support in the compiler. If + * this is not defined for your platform, yet it is capable of + * dealing with 64 bits then it is because this file has not yet + * been extended to cover all of your system's capabilities. + * + * 7) (u)intptr_t may or may not be defined. Test for its presence + * with the test: #ifdef PTRDIFF_MAX. If this is not defined + * for your platform, then it is because this file has not yet + * been extended to cover all of your system's capabilities, not + * because its optional. + * + * 8) The following might not been defined even if your platform is + * capable of defining it: + * + * WCHAR_MIN + * WCHAR_MAX + * (u)int64_t + * PTRDIFF_MIN + * PTRDIFF_MAX + * (u)intptr_t + * + * 9) The following have not been defined: + * + * WINT_MIN + * WINT_MAX + * + * 10) The criteria for defining (u)int_least(*)_t isn't clear, + * except for systems which don't have a type that precisely + * defined 8, 16, or 32 bit types (which this include file does + * not support anyways). Default definitions have been given. + * + * 11) The criteria for defining (u)int_fast(*)_t isn't something I + * would trust to any particular compiler vendor or the ANSI C + * committee. It is well known that "compatible systems" are + * commonly created that have very different performance + * characteristics from the systems they are compatible with, + * especially those whose vendors make both the compiler and the + * system. Default definitions have been given, but its strongly + * recommended that users never use these definitions for any + * reason (they do *NOT* deliver any serious guarantee of + * improved performance -- not in this file, nor any vendor's + * stdint.h). + * + * 12) The following macros: + * + * PRINTF_INTMAX_MODIFIER + * PRINTF_INT64_MODIFIER + * PRINTF_INT32_MODIFIER + * PRINTF_INT16_MODIFIER + * PRINTF_LEAST64_MODIFIER + * PRINTF_LEAST32_MODIFIER + * PRINTF_LEAST16_MODIFIER + * PRINTF_INTPTR_MODIFIER + * + * are strings which have been defined as the modifiers required + * for the "d", "u" and "x" printf formats to correctly output + * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t, + * (u)least32_t, (u)least16_t and (u)intptr_t types respectively. + * PRINTF_INTPTR_MODIFIER is not defined for some systems which + * provide their own stdint.h. PRINTF_INT64_MODIFIER is not + * defined if INT64_MAX is not defined. These are an extension + * beyond what C99 specifies must be in stdint.h. + * + * In addition, the following macros are defined: + * + * PRINTF_INTMAX_HEX_WIDTH + * PRINTF_INT64_HEX_WIDTH + * PRINTF_INT32_HEX_WIDTH + * PRINTF_INT16_HEX_WIDTH + * PRINTF_INT8_HEX_WIDTH + * PRINTF_INTMAX_DEC_WIDTH + * PRINTF_INT64_DEC_WIDTH + * PRINTF_INT32_DEC_WIDTH + * PRINTF_INT16_DEC_WIDTH + * PRINTF_INT8_DEC_WIDTH + * + * Which specifies the maximum number of characters required to + * print the number of that type in either hexadecimal or decimal. + * These are an extension beyond what C99 specifies must be in + * stdint.h. + * + * Compilers tested (all with 0 warnings at their highest respective + * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32 + * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio + * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3 + * + * This file should be considered a work in progress. Suggestions for + * improvements, especially those which increase coverage are strongly + * encouraged. + * + * Acknowledgements + * + * The following people have made significant contributions to the + * development and testing of this file: + * + * Chris Howie + * John Steele Scott + * Dave Thorup + * + */ + +#include +#include +#include + +/* + * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and + * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. + */ + +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED) +#include +#define _PSTDINT_H_INCLUDED +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +# endif +# ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +# endif +# ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +# endif +# ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +# endif +# ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +# endif +# ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +# endif +# ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +# endif +# ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif + +/* + * Something really weird is going on with Open Watcom. Just pull some of + * these duplicated definitions from Open Watcom's stdint.h file for now. + */ + +# if defined (__WATCOMC__) && __WATCOMC__ >= 1250 +# if !defined (INT64_C) +# define INT64_C(x) (x + (INT64_MAX - INT64_MAX)) +# endif +# if !defined (UINT64_C) +# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) +# endif +# if !defined (INT32_C) +# define INT32_C(x) (x + (INT32_MAX - INT32_MAX)) +# endif +# if !defined (UINT32_C) +# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX)) +# endif +# if !defined (INT16_C) +# define INT16_C(x) (x) +# endif +# if !defined (UINT16_C) +# define UINT16_C(x) (x) +# endif +# if !defined (INT8_C) +# define INT8_C(x) (x) +# endif +# if !defined (UINT8_C) +# define UINT8_C(x) (x) +# endif +# if !defined (UINT64_MAX) +# define UINT64_MAX 18446744073709551615ULL +# endif +# if !defined (INT64_MAX) +# define INT64_MAX 9223372036854775807LL +# endif +# if !defined (UINT32_MAX) +# define UINT32_MAX 4294967295UL +# endif +# if !defined (INT32_MAX) +# define INT32_MAX 2147483647L +# endif +# if !defined (INTMAX_MAX) +# define INTMAX_MAX INT64_MAX +# endif +# if !defined (INTMAX_MIN) +# define INTMAX_MIN INT64_MIN +# endif +# endif +#endif + +#ifndef _PSTDINT_H_INCLUDED +#define _PSTDINT_H_INCLUDED + +#ifndef SIZE_MAX +# define SIZE_MAX (~(size_t)0) +#endif + +/* + * Deduce the type assignments from limits.h under the assumption that + * integer sizes in bits are powers of 2, and follow the ANSI + * definitions. + */ + +#ifndef UINT8_MAX +# define UINT8_MAX 0xff +#endif +#ifndef uint8_t +# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) + typedef unsigned char uint8_t; +# define UINT8_C(v) ((uint8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef INT8_MAX +# define INT8_MAX 0x7f +#endif +#ifndef INT8_MIN +# define INT8_MIN INT8_C(0x80) +#endif +#ifndef int8_t +# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) + typedef signed char int8_t; +# define INT8_C(v) ((int8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef UINT16_MAX +# define UINT16_MAX 0xffff +#endif +#ifndef uint16_t +#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S) + typedef unsigned int uint16_t; +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +# define UINT16_C(v) ((uint16_t) (v)) +#elif (USHRT_MAX == UINT16_MAX) + typedef unsigned short uint16_t; +# define UINT16_C(v) ((uint16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT16_MAX +# define INT16_MAX 0x7fff +#endif +#ifndef INT16_MIN +# define INT16_MIN INT16_C(0x8000) +#endif +#ifndef int16_t +#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) + typedef signed int int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +#elif (SHRT_MAX == INT16_MAX) + typedef signed short int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef UINT32_MAX +# define UINT32_MAX (0xffffffffUL) +#endif +#ifndef uint32_t +#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) + typedef unsigned long uint32_t; +# define UINT32_C(v) v ## UL +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (UINT_MAX == UINT32_MAX) + typedef unsigned int uint32_t; +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +# define UINT32_C(v) v ## U +#elif (USHRT_MAX == UINT32_MAX) + typedef unsigned short uint32_t; +# define UINT32_C(v) ((unsigned short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT32_MAX +# define INT32_MAX (0x7fffffffL) +#endif +#ifndef INT32_MIN +# define INT32_MIN INT32_C(0x80000000) +#endif +#ifndef int32_t +#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) + typedef signed long int32_t; +# define INT32_C(v) v ## L +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (INT_MAX == INT32_MAX) + typedef signed int int32_t; +# define INT32_C(v) v +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#elif (SHRT_MAX == INT32_MAX) + typedef signed short int32_t; +# define INT32_C(v) ((short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +/* + * The macro stdint_int64_defined is temporarily used to record + * whether or not 64 integer support is available. It must be + * defined for any 64 integer extensions for new platforms that are + * added. + */ + +#undef stdint_int64_defined +#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) +# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# endif +#endif + +#if !defined (stdint_int64_defined) +# if defined(__GNUC__) +# define stdint_int64_defined + __extension__ typedef long long int64_t; + __extension__ typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) +# define stdint_int64_defined + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# define UINT64_C(v) v ## UI64 +# define INT64_C(v) v ## I64 +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "I64" +# endif +# endif +#endif + +#if !defined (LONG_LONG_MAX) && defined (INT64_C) +# define LONG_LONG_MAX INT64_C (9223372036854775807) +#endif +#ifndef ULONG_LONG_MAX +# define ULONG_LONG_MAX UINT64_C (18446744073709551615) +#endif + +#if !defined (INT64_MAX) && defined (INT64_C) +# define INT64_MAX INT64_C (9223372036854775807) +#endif +#if !defined (INT64_MIN) && defined (INT64_C) +# define INT64_MIN INT64_C (-9223372036854775808) +#endif +#if !defined (UINT64_MAX) && defined (INT64_C) +# define UINT64_MAX UINT64_C (18446744073709551615) +#endif + +/* + * Width of hexadecimal for number field. + */ + +#ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +#endif +#ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +#endif +#ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +#endif +#ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +#endif + +#ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +#endif +#ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +#endif +#ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +#endif +#ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +#endif + +/* + * Ok, lets not worry about 128 bit integers for now. Moore's law says + * we don't need to worry about that until about 2040 at which point + * we'll have bigger things to worry about. + */ + +#ifdef stdint_int64_defined + typedef int64_t intmax_t; + typedef uint64_t uintmax_t; +# define INTMAX_MAX INT64_MAX +# define INTMAX_MIN INT64_MIN +# define UINTMAX_MAX UINT64_MAX +# define UINTMAX_C(v) UINT64_C(v) +# define INTMAX_C(v) INT64_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif +#else + typedef int32_t intmax_t; + typedef uint32_t uintmax_t; +# define INTMAX_MAX INT32_MAX +# define UINTMAX_MAX UINT32_MAX +# define UINTMAX_C(v) UINT32_C(v) +# define INTMAX_C(v) INT32_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH +# endif +#endif + +/* + * Because this file currently only supports platforms which have + * precise powers of 2 as bit sizes for the default integers, the + * least definitions are all trivial. Its possible that a future + * version of this file could have different definitions. + */ + +#ifndef stdint_least_defined + typedef int8_t int_least8_t; + typedef uint8_t uint_least8_t; + typedef int16_t int_least16_t; + typedef uint16_t uint_least16_t; + typedef int32_t int_least32_t; + typedef uint32_t uint_least32_t; +# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER +# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER +# define UINT_LEAST8_MAX UINT8_MAX +# define INT_LEAST8_MAX INT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define INT_LEAST16_MAX INT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# ifdef stdint_int64_defined + typedef int64_t int_least64_t; + typedef uint64_t uint_least64_t; +# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER +# define UINT_LEAST64_MAX UINT64_MAX +# define INT_LEAST64_MAX INT64_MAX +# define INT_LEAST64_MIN INT64_MIN +# endif +#endif +#undef stdint_least_defined + +/* + * The ANSI C committee pretending to know or specify anything about + * performance is the epitome of misguided arrogance. The mandate of + * this file is to *ONLY* ever support that absolute minimum + * definition of the fast integer types, for compatibility purposes. + * No extensions, and no attempt to suggest what may or may not be a + * faster integer type will ever be made in this file. Developers are + * warned to stay away from these types when using this or any other + * stdint.h. + */ + +typedef int_least8_t int_fast8_t; +typedef uint_least8_t uint_fast8_t; +typedef int_least16_t int_fast16_t; +typedef uint_least16_t uint_fast16_t; +typedef int_least32_t int_fast32_t; +typedef uint_least32_t uint_fast32_t; +#define UINT_FAST8_MAX UINT_LEAST8_MAX +#define INT_FAST8_MAX INT_LEAST8_MAX +#define UINT_FAST16_MAX UINT_LEAST16_MAX +#define INT_FAST16_MAX INT_LEAST16_MAX +#define UINT_FAST32_MAX UINT_LEAST32_MAX +#define INT_FAST32_MAX INT_LEAST32_MAX +#define INT_FAST8_MIN INT_LEAST8_MIN +#define INT_FAST16_MIN INT_LEAST16_MIN +#define INT_FAST32_MIN INT_LEAST32_MIN +#ifdef stdint_int64_defined + typedef int_least64_t int_fast64_t; + typedef uint_least64_t uint_fast64_t; +# define UINT_FAST64_MAX UINT_LEAST64_MAX +# define INT_FAST64_MAX INT_LEAST64_MAX +# define INT_FAST64_MIN INT_LEAST64_MIN +#endif + +#undef stdint_int64_defined + +/* + * Whatever piecemeal, per compiler thing we can do about the wchar_t + * type limits. + */ + +#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) +# include +# ifndef WCHAR_MIN +# define WCHAR_MIN 0 +# endif +# ifndef WCHAR_MAX +# define WCHAR_MAX ((wchar_t)-1) +# endif +#endif + +/* + * Whatever piecemeal, per compiler/platform thing we can do about the + * (u)intptr_t types and limits. + */ + +#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED) +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +#ifndef STDINT_H_UINTPTR_T_DEFINED +# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) +# define stdint_intptr_bits 64 +# elif defined (__WATCOMC__) || defined (__TURBOC__) +# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) +# define stdint_intptr_bits 16 +# else +# define stdint_intptr_bits 32 +# endif +# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) +# define stdint_intptr_bits 32 +# elif defined (__INTEL_COMPILER) +/* TODO -- what will Intel do about x86-64? */ +# endif + +# ifdef stdint_intptr_bits +# define stdint_intptr_glue3_i(a,b,c) a##b##c +# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c) +# ifndef PRINTF_INTPTR_MODIFIER +# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER) +# endif +# ifndef PTRDIFF_MAX +# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef PTRDIFF_MIN +# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef UINTPTR_MAX +# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MAX +# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MIN +# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef INTPTR_C +# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x) +# endif +# ifndef UINTPTR_C +# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) +# endif + typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; + typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; +# else +/* TODO -- This following is likely wrong for some platforms, and does + nothing for the definition of uintptr_t. */ + typedef ptrdiff_t intptr_t; +# endif +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +/* + * Assumes sig_atomic_t is signed and we have a 2s complement machine. + */ + +#ifndef SIG_ATOMIC_MAX +# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1) +#endif + +#endif + +#if defined (__TEST_PSTDINT_FOR_CORRECTNESS) + +/* + * Please compile with the maximum warning settings to make sure macros are not + * defined more than once. + */ + +#include +#include +#include + +#define glue3_aux(x,y,z) x ## y ## z +#define glue3(x,y,z) glue3_aux(x,y,z) + +#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0); +#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0); + +#define DECL(us,bits) glue3(DECL,us,) (bits) + +#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits) + +int main () { + DECL(I,8) + DECL(U,8) + DECL(I,16) + DECL(U,16) + DECL(I,32) + DECL(U,32) +#ifdef INT64_MAX + DECL(I,64) + DECL(U,64) +#endif + intmax_t imax = INTMAX_C(0); + uintmax_t umax = UINTMAX_C(0); + char str0[256], str1[256]; + + sprintf (str0, "%d %x\n", 0, ~0); + + sprintf (str1, "%d %x\n", i8, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1); + sprintf (str1, "%u %x\n", u8, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1); + sprintf (str1, "%d %x\n", i16, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1); + sprintf (str1, "%u %x\n", u16, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1); + sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1); + sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1); +#ifdef INT64_MAX + sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1); +#endif + sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1); + sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0); + if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1); + + TESTUMAX(8); + TESTUMAX(16); + TESTUMAX(32); +#ifdef INT64_MAX + TESTUMAX(64); +#endif + + return EXIT_SUCCESS; +} + +#endif