Part 1 changes to allow dual licensing to MPLV2.
Make external LGPL code/features disabled in MPLV2 variant. Nuke some unwanted whitespace (cstyle).
This commit is contained in:
parent
0433452b37
commit
10f40e1c6f
16 changed files with 577 additions and 326 deletions
|
@ -42,23 +42,28 @@
|
||||||
#include "pc_arc_filter.h"
|
#include "pc_arc_filter.h"
|
||||||
#include "pc_archive.h"
|
#include "pc_archive.h"
|
||||||
|
|
||||||
#define PACKJPG_DEF_BUFSIZ (512 * 1024)
|
#ifndef _MPLV2_LICENSE_
|
||||||
#define JPG_SIZE_LIMIT (8 * 1024 * 1024)
|
# define PACKJPG_DEF_BUFSIZ (512 * 1024)
|
||||||
#define PJG_APPVERSION1 (25)
|
# define JPG_SIZE_LIMIT (8 * 1024 * 1024)
|
||||||
#define PJG_APPVERSION2 (25)
|
# define PJG_APPVERSION1 (25)
|
||||||
|
# define PJG_APPVERSION2 (25)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct scratch_buffer {
|
struct scratch_buffer {
|
||||||
uchar_t *in_buff;
|
uchar_t *in_buff;
|
||||||
size_t in_bufflen;
|
size_t in_bufflen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
extern size_t packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf);
|
extern size_t packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf);
|
||||||
|
|
||||||
ssize_t packjpg_filter(struct filter_info *fi, void *filter_private);
|
ssize_t packjpg_filter(struct filter_info *fi, void *filter_private);
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||||
{
|
{
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
struct scratch_buffer *sdat;
|
struct scratch_buffer *sdat;
|
||||||
int slot;
|
int slot;
|
||||||
|
|
||||||
|
@ -72,6 +77,7 @@ add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||||
typetab[slot].filter_func = packjpg_filter;
|
typetab[slot].filter_func = packjpg_filter;
|
||||||
typetab[slot].filter_name = "packJPG";
|
typetab[slot].filter_name = "packJPG";
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -138,6 +144,7 @@ write_archive_data(struct archive *aw, uchar_t *out_buf, size_t len, int block_s
|
||||||
return (tot);
|
return (tot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
int
|
int
|
||||||
pjg_version_supported(char ver)
|
pjg_version_supported(char ver)
|
||||||
{
|
{
|
||||||
|
@ -252,4 +259,5 @@ packjpg_filter(struct filter_info *fi, void *filter_private)
|
||||||
free(out);
|
free(out);
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
#include <packjpglib.h>
|
#include <packjpglib.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -104,3 +106,4 @@ packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
31
config
31
config
|
@ -20,6 +20,8 @@
|
||||||
# moinakg@belenix.org, http://moinakg.wordpress.com/
|
# moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||||
#
|
#
|
||||||
|
|
||||||
|
my_license=LGPLv3
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
prog=$1
|
prog=$1
|
||||||
cat << _EOF
|
cat << _EOF
|
||||||
|
@ -40,9 +42,12 @@ ${prog} [<options>]
|
||||||
Enable building against an alternate Bzip2 and library installation.
|
Enable building against an alternate Bzip2 and library installation.
|
||||||
--with-libarchive=<path to libarchive installation tree> (Default: System)
|
--with-libarchive=<path to libarchive installation tree> (Default: System)
|
||||||
Enable building against an alternate libarchive installation.
|
Enable building against an alternate libarchive installation.
|
||||||
|
--with-external-libbsc=<path to libbsc source tree>
|
||||||
|
Enable building with exernal libbsc sources. Can be used to link with
|
||||||
|
ASLv2 libbsc when using MPLv2 licensed sources.
|
||||||
--no-sse-detect Do NOT attempt to probe the system's SSE capability for build flags.
|
--no-sse-detect Do NOT attempt to probe the system's SSE capability for build flags.
|
||||||
Implies '--no-avx-detect' below.
|
Implies '--no-avx-detect' below.
|
||||||
--no-avx-detect Do NOT attempt to probe the system's AVX apability for build flags.
|
--no-avx-detect Do NOT attempt to probe the system's AVX capability for build flags.
|
||||||
--no-1.3-archive-compat Disable compatibility with compressed archives created with Pcompress
|
--no-1.3-archive-compat Disable compatibility with compressed archives created with Pcompress
|
||||||
version 1.3 (default: retain compatibility). Hash formats changed from
|
version 1.3 (default: retain compatibility). Hash formats changed from
|
||||||
version 1.3 to 1.4 so this option is required if files created using
|
version 1.3 to 1.4 so this option is required if files created using
|
||||||
|
@ -60,12 +65,16 @@ debug=0
|
||||||
allocator=1
|
allocator=1
|
||||||
debug_stats=0
|
debug_stats=0
|
||||||
prefix=/usr
|
prefix=/usr
|
||||||
libbsc_dir=./bsc
|
|
||||||
libbsc_lib=${libbsc_dir}/libbsc.a
|
if [ "$my_license" = "LGPLv3" ]
|
||||||
libbsclflags='\$\(LIBBSCLFLAGS\)'
|
then
|
||||||
libbscwrapobj='\$\(LIBBSCWRAPOBJ\)'
|
libbsc_dir=./bsc
|
||||||
libbscgenopt='\$\(LIBBSCGEN_OPT\)'
|
libbsc_lib=${libbsc_dir}/libbsc.a
|
||||||
libbsccppflags='\$\(LIBBSCCPPFLAGS\)'
|
libbsclflags='\$\(LIBBSCLFLAGS\)'
|
||||||
|
libbscwrapobj='\$\(LIBBSCWRAPOBJ\)'
|
||||||
|
libbscgenopt='\$\(LIBBSCGEN_OPT\)'
|
||||||
|
libbsccppflags='\$\(LIBBSCCPPFLAGS\)'
|
||||||
|
fi
|
||||||
openssl_prefix=
|
openssl_prefix=
|
||||||
openssl_libdir=
|
openssl_libdir=
|
||||||
openssl_incdir=
|
openssl_incdir=
|
||||||
|
@ -195,6 +204,14 @@ do
|
||||||
--with-libarchive=*)
|
--with-libarchive=*)
|
||||||
libarchive_prefix=`echo ${arg1} | cut -f2 -d"="`
|
libarchive_prefix=`echo ${arg1} | cut -f2 -d"="`
|
||||||
;;
|
;;
|
||||||
|
--with-external-libbsc)
|
||||||
|
libbsc_dir=`echo ${arg1} | cut -f2 -d"="`
|
||||||
|
libbsc_lib=${libbsc_dir}/libbsc.a
|
||||||
|
libbsclflags='\$\(LIBBSCLFLAGS\)'
|
||||||
|
libbscwrapobj='\$\(LIBBSCWRAPOBJ\)'
|
||||||
|
libbscgenopt='\$\(LIBBSCGEN_OPT\)'
|
||||||
|
libbsccppflags='\$\(LIBBSCCPPFLAGS\)'
|
||||||
|
;;
|
||||||
--use-key256)
|
--use-key256)
|
||||||
keylen='-DDEFAULT_KEYLEN=16'
|
keylen='-DDEFAULT_KEYLEN=16'
|
||||||
;;
|
;;
|
||||||
|
|
14
pcompress.c
14
pcompress.c
|
@ -78,7 +78,8 @@ usage(pc_ctx_t *pctx)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\nPcompress Version %s\n\n"
|
"\nPcompress Version %s\n"
|
||||||
|
"License: %s\n\n"
|
||||||
"See README.md for detailed usage.\n\n"
|
"See README.md for detailed usage.\n\n"
|
||||||
"Standard Usage\n"
|
"Standard Usage\n"
|
||||||
"==============\n"
|
"==============\n"
|
||||||
|
@ -144,7 +145,7 @@ usage(pc_ctx_t *pctx)
|
||||||
" Default output name if omitted: <input filename>.out\n\n"
|
" Default output name if omitted: <input filename>.out\n\n"
|
||||||
" If Archiving was done then this should be the name of a directory into which\n"
|
" If Archiving was done then this should be the name of a directory into which\n"
|
||||||
" extracted files are restored. Default if omitted: Current directory.\n\n",
|
" extracted files are restored. Default if omitted: Current directory.\n\n",
|
||||||
UTILITY_VERSION, pctx->exec_name, pctx->exec_name, pctx->exec_name);
|
UTILITY_VERSION, LICENSE_STRING, pctx->exec_name, pctx->exec_name, pctx->exec_name);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" Encryption\n"
|
" Encryption\n"
|
||||||
" ----------\n"
|
" ----------\n"
|
||||||
|
@ -234,6 +235,7 @@ preproc_compress(pc_ctx_t *pctx, compress_func_ptr cmp_func, void *src, uint64_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
if (pctx->lzp_preprocess && stype != TYPE_BMP && stype != TYPE_TIFF) {
|
if (pctx->lzp_preprocess && stype != TYPE_BMP && stype != TYPE_TIFF) {
|
||||||
int hashsize;
|
int hashsize;
|
||||||
|
|
||||||
|
@ -249,6 +251,7 @@ preproc_compress(pc_ctx_t *pctx, compress_func_ptr cmp_func, void *src, uint64_t
|
||||||
type |= PREPROC_TYPE_LZP;
|
type |= PREPROC_TYPE_LZP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pctx->enable_delta2_encode && props->delta2_span > 0 &&
|
if (pctx->enable_delta2_encode && props->delta2_span > 0 &&
|
||||||
stype != TYPE_DNA_SEQ && stype != TYPE_BMP &&
|
stype != TYPE_DNA_SEQ && stype != TYPE_BMP &&
|
||||||
|
@ -349,6 +352,7 @@ preproc_decompress(pc_ctx_t *pctx, compress_func_ptr dec_func, void *src, uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & PREPROC_TYPE_LZP) {
|
if (type & PREPROC_TYPE_LZP) {
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
int hashsize;
|
int hashsize;
|
||||||
hashsize = lzp_hash_size(level);
|
hashsize = lzp_hash_size(level);
|
||||||
result = lzp_decompress((const uchar_t *)src, (uchar_t *)dst, srclen,
|
result = lzp_decompress((const uchar_t *)src, (uchar_t *)dst, srclen,
|
||||||
|
@ -362,6 +366,10 @@ preproc_decompress(pc_ctx_t *pctx, compress_func_ptr dec_func, void *src, uint64
|
||||||
log_msg(LOG_ERR, 0, "LZP decompression failed.");
|
log_msg(LOG_ERR, 0, "LZP decompression failed.");
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
log_msg(LOG_ERR, 0, "LZP feature not available in this build (MPLv2). Aborting.");
|
||||||
|
return (-1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type & PREPROC_TYPE_DISPACK) {
|
if (type & PREPROC_TYPE_DISPACK) {
|
||||||
|
@ -2960,10 +2968,12 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
pctx->enable_rabin_split = 0;
|
pctx->enable_rabin_split = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
case 'L':
|
case 'L':
|
||||||
pctx->advanced_opts = 1;
|
pctx->advanced_opts = 1;
|
||||||
pctx->lzp_preprocess = 1;
|
pctx->lzp_preprocess = 1;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'P':
|
case 'P':
|
||||||
pctx->advanced_opts = 1;
|
pctx->advanced_opts = 1;
|
||||||
|
|
|
@ -49,6 +49,12 @@ extern "C" {
|
||||||
#define MASK_CRYPTO_ALG 0x30
|
#define MASK_CRYPTO_ALG 0x30
|
||||||
#define MAX_LEVEL 14
|
#define MAX_LEVEL 14
|
||||||
|
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
|
#define LICENSE_STRING "LGPLv3"
|
||||||
|
#else
|
||||||
|
#define LICENSE_STRING "MPLv2"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define COMPRESSED 1
|
#define COMPRESSED 1
|
||||||
#define UNCOMPRESSED 0
|
#define UNCOMPRESSED 0
|
||||||
#define CHSIZE_MASK 0x80
|
#define CHSIZE_MASK 0x80
|
||||||
|
|
|
@ -76,9 +76,12 @@ init_global_db(char *configfile)
|
||||||
int
|
int
|
||||||
init_on_disk_index(archive_config_t *cfg)
|
init_on_disk_index(archive_config_t *cfg)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
if (file_exists()) {
|
if (file_exists()) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <heap.h>
|
#include <heap.h>
|
||||||
#include <xxhash.h>
|
#include <xxhash.h>
|
||||||
|
|
||||||
|
#define QSORT_LT(a, b) ((*a)<(*b))
|
||||||
|
#define QSORT_TYPE uint64_t
|
||||||
#include <qsort.h>
|
#include <qsort.h>
|
||||||
|
|
||||||
#include "rabin_dedup.h"
|
#include "rabin_dedup.h"
|
||||||
|
@ -445,11 +448,10 @@ isort_uint64(uint64_t *ary, uint32_t nitems)
|
||||||
* Sort an array of 64-bit unsigned integers. The QSORT macro provides an
|
* Sort an array of 64-bit unsigned integers. The QSORT macro provides an
|
||||||
* inline quicksort routine that does not use a callback function.
|
* inline quicksort routine that does not use a callback function.
|
||||||
*/
|
*/
|
||||||
#define int_lt(a,b) ((*a)<(*b))
|
|
||||||
static void
|
static void
|
||||||
do_qsort(uint64_t *arr, uint32_t len)
|
do_qsort(uint64_t *arr, uint32_t len)
|
||||||
{
|
{
|
||||||
QSORT(uint64_t, arr, len, int_lt);
|
QSORT(arr, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
|
295
utils/qsort.h
295
utils/qsort.h
|
@ -22,293 +22,8 @@
|
||||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: qsort.h,v 1.5 2008-01-28 18:16:49 mjt Exp $
|
#ifndef _MPLV2_LICENSE_
|
||||||
* Adopted from GNU glibc by Mjt.
|
#include "qsort_gnu.h"
|
||||||
* See stdlib/qsort.c in glibc */
|
#else
|
||||||
|
#include "qsort_bsd.h"
|
||||||
/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
|
#endif
|
||||||
This file is part of the GNU C Library.
|
|
||||||
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
|
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with the GNU C Library; if not, write to the Free
|
|
||||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
||||||
02111-1307 USA. */
|
|
||||||
|
|
||||||
/* in-line qsort implementation. Differs from traditional qsort() routine
|
|
||||||
* in that it is a macro, not a function, and instead of passing an address
|
|
||||||
* of a comparison routine to the function, it is possible to inline
|
|
||||||
* comparison routine, thus speeding up sorting a lot.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* #include "iqsort.h"
|
|
||||||
* #define islt(a,b) (strcmp((*a),(*b))<0)
|
|
||||||
* char *arr[];
|
|
||||||
* int n;
|
|
||||||
* QSORT(char*, arr, n, islt);
|
|
||||||
*
|
|
||||||
* The "prototype" and 4 arguments are:
|
|
||||||
* QSORT(TYPE,BASE,NELT,ISLT)
|
|
||||||
* 1) type of each element, TYPE,
|
|
||||||
* 2) address of the beginning of the array, of type TYPE*,
|
|
||||||
* 3) number of elements in the array, and
|
|
||||||
* 4) comparision routine.
|
|
||||||
* Array pointer and number of elements are referenced only once.
|
|
||||||
* This is similar to a call
|
|
||||||
* qsort(BASE,NELT,sizeof(TYPE),ISLT)
|
|
||||||
* with the difference in last parameter.
|
|
||||||
* Note the islt macro/routine (it receives pointers to two elements):
|
|
||||||
* the only condition of interest is whenever one element is less than
|
|
||||||
* another, no other conditions (greather than, equal to etc) are tested.
|
|
||||||
* So, for example, to define integer sort, use:
|
|
||||||
* #define islt(a,b) ((*a)<(*b))
|
|
||||||
* QSORT(int, arr, n, islt)
|
|
||||||
*
|
|
||||||
* The macro could be used to implement a sorting function (see examples
|
|
||||||
* below), or to implement the sorting algorithm inline. That is, either
|
|
||||||
* create a sorting function and use it whenever you want to sort something,
|
|
||||||
* or use QSORT() macro directly instead a call to such routine. Note that
|
|
||||||
* the macro expands to quite some code (compiled size of int qsort on x86
|
|
||||||
* is about 700..800 bytes).
|
|
||||||
*
|
|
||||||
* Using this macro directly it isn't possible to implement traditional
|
|
||||||
* qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
|
|
||||||
* while qsort() allows element size to be different.
|
|
||||||
*
|
|
||||||
* Several ready-to-use examples:
|
|
||||||
*
|
|
||||||
* Sorting array of integers:
|
|
||||||
* void int_qsort(int *arr, unsigned n) {
|
|
||||||
* #define int_lt(a,b) ((*a)<(*b))
|
|
||||||
* QSORT(int, arr, n, int_lt);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Sorting array of string pointers:
|
|
||||||
* void str_qsort(char *arr[], unsigned n) {
|
|
||||||
* #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
|
|
||||||
* QSORT(char*, arr, n, str_lt);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Sorting array of structures:
|
|
||||||
*
|
|
||||||
* struct elt {
|
|
||||||
* int key;
|
|
||||||
* ...
|
|
||||||
* };
|
|
||||||
* void elt_qsort(struct elt *arr, unsigned n) {
|
|
||||||
* #define elt_lt(a,b) ((a)->key < (b)->key)
|
|
||||||
* QSORT(struct elt, arr, n, elt_lt);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* And so on.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Swap two items pointed to by A and B using temporary buffer t. */
|
|
||||||
#define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
|
|
||||||
|
|
||||||
/* Discontinue quicksort algorithm when partition gets below this size.
|
|
||||||
This particular magic number was chosen to work best on a Sun 4/260. */
|
|
||||||
#define _QSORT_MAX_THRESH 4
|
|
||||||
|
|
||||||
/* Stack node declarations used to store unfulfilled partition obligations
|
|
||||||
* (inlined in QSORT).
|
|
||||||
typedef struct {
|
|
||||||
QSORT_TYPE *_lo, *_hi;
|
|
||||||
} qsort_stack_node;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
|
||||||
/* The stack needs log (total_elements) entries (we could even subtract
|
|
||||||
log(MAX_THRESH)). Since total_elements has type unsigned, we get as
|
|
||||||
upper bound for log (total_elements):
|
|
||||||
bits per byte (CHAR_BIT) * sizeof(unsigned). */
|
|
||||||
#define _QSORT_STACK_SIZE (8 * sizeof(unsigned))
|
|
||||||
#define _QSORT_PUSH(top, low, high) \
|
|
||||||
(((top->_lo = (low)), (top->_hi = (high)), ++top))
|
|
||||||
#define _QSORT_POP(low, high, top) \
|
|
||||||
((--top, (low = top->_lo), (high = top->_hi)))
|
|
||||||
#define _QSORT_STACK_NOT_EMPTY (_stack < _top)
|
|
||||||
|
|
||||||
|
|
||||||
/* Order size using quicksort. This implementation incorporates
|
|
||||||
four optimizations discussed in Sedgewick:
|
|
||||||
|
|
||||||
1. Non-recursive, using an explicit stack of pointer that store the
|
|
||||||
next array partition to sort. To save time, this maximum amount
|
|
||||||
of space required to store an array of SIZE_MAX is allocated on the
|
|
||||||
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
|
|
||||||
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
|
|
||||||
Pretty cheap, actually.
|
|
||||||
|
|
||||||
2. Chose the pivot element using a median-of-three decision tree.
|
|
||||||
This reduces the probability of selecting a bad pivot value and
|
|
||||||
eliminates certain extraneous comparisons.
|
|
||||||
|
|
||||||
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
|
||||||
insertion sort to order the MAX_THRESH items within each partition.
|
|
||||||
This is a big win, since insertion sort is faster for small, mostly
|
|
||||||
sorted array segments.
|
|
||||||
|
|
||||||
4. The larger of the two sub-partitions is always pushed onto the
|
|
||||||
stack first, with the algorithm then concentrating on the
|
|
||||||
smaller partition. This *guarantees* no more than log (total_elems)
|
|
||||||
stack size is needed (actually O(1) in this case)! */
|
|
||||||
|
|
||||||
/* The main code starts here... */
|
|
||||||
#define QSORT(QSORT_TYPE,QSORT_BASE,QSORT_NELT,QSORT_LT) \
|
|
||||||
{ \
|
|
||||||
QSORT_TYPE *const _base = (QSORT_BASE); \
|
|
||||||
const unsigned _elems = (QSORT_NELT); \
|
|
||||||
QSORT_TYPE _hold; \
|
|
||||||
\
|
|
||||||
/* Don't declare two variables of type QSORT_TYPE in a single \
|
|
||||||
* statement: eg `TYPE a, b;', in case if TYPE is a pointer, \
|
|
||||||
* expands to `type* a, b;' wich isn't what we want. \
|
|
||||||
*/ \
|
|
||||||
\
|
|
||||||
if (_elems > _QSORT_MAX_THRESH) { \
|
|
||||||
QSORT_TYPE *_lo = _base; \
|
|
||||||
QSORT_TYPE *_hi = _lo + _elems - 1; \
|
|
||||||
struct { \
|
|
||||||
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
|
||||||
} _stack[_QSORT_STACK_SIZE], *_top = _stack + 1; \
|
|
||||||
\
|
|
||||||
while (_QSORT_STACK_NOT_EMPTY) { \
|
|
||||||
QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr; \
|
|
||||||
\
|
|
||||||
/* Select median value from among LO, MID, and HI. Rearrange \
|
|
||||||
LO and HI so the three values are sorted. This lowers the \
|
|
||||||
probability of picking a pathological pivot value and \
|
|
||||||
skips a comparison for both the LEFT_PTR and RIGHT_PTR in \
|
|
||||||
the while loops. */ \
|
|
||||||
\
|
|
||||||
QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1); \
|
|
||||||
\
|
|
||||||
if (QSORT_LT (_mid, _lo)) \
|
|
||||||
_QSORT_SWAP (_mid, _lo, _hold); \
|
|
||||||
if (QSORT_LT (_hi, _mid)) { \
|
|
||||||
_QSORT_SWAP (_mid, _hi, _hold); \
|
|
||||||
if (QSORT_LT (_mid, _lo)) \
|
|
||||||
_QSORT_SWAP (_mid, _lo, _hold); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
_left_ptr = _lo + 1; \
|
|
||||||
_right_ptr = _hi - 1; \
|
|
||||||
\
|
|
||||||
/* Here's the famous ``collapse the walls'' section of quicksort. \
|
|
||||||
Gotta like those tight inner loops! They are the main reason \
|
|
||||||
that this algorithm runs much faster than others. */ \
|
|
||||||
do { \
|
|
||||||
while (QSORT_LT (_left_ptr, _mid)) \
|
|
||||||
++_left_ptr; \
|
|
||||||
\
|
|
||||||
while (QSORT_LT (_mid, _right_ptr)) \
|
|
||||||
--_right_ptr; \
|
|
||||||
\
|
|
||||||
if (_left_ptr < _right_ptr) { \
|
|
||||||
_QSORT_SWAP (_left_ptr, _right_ptr, _hold); \
|
|
||||||
if (_mid == _left_ptr) \
|
|
||||||
_mid = _right_ptr; \
|
|
||||||
else if (_mid == _right_ptr) \
|
|
||||||
_mid = _left_ptr; \
|
|
||||||
++_left_ptr; \
|
|
||||||
--_right_ptr; \
|
|
||||||
} \
|
|
||||||
else if (_left_ptr == _right_ptr) { \
|
|
||||||
++_left_ptr; \
|
|
||||||
--_right_ptr; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} while (_left_ptr <= _right_ptr); \
|
|
||||||
\
|
|
||||||
/* Set up pointers for next iteration. First determine whether \
|
|
||||||
left and right partitions are below the threshold size. If so, \
|
|
||||||
ignore one or both. Otherwise, push the larger partition's \
|
|
||||||
bounds on the stack and continue sorting the smaller one. */ \
|
|
||||||
\
|
|
||||||
if (_right_ptr - _lo <= _QSORT_MAX_THRESH) { \
|
|
||||||
if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
|
||||||
/* Ignore both small partitions. */ \
|
|
||||||
_QSORT_POP (_lo, _hi, _top); \
|
|
||||||
else \
|
|
||||||
/* Ignore small left partition. */ \
|
|
||||||
_lo = _left_ptr; \
|
|
||||||
} \
|
|
||||||
else if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
|
||||||
/* Ignore small right partition. */ \
|
|
||||||
_hi = _right_ptr; \
|
|
||||||
else if (_right_ptr - _lo > _hi - _left_ptr) { \
|
|
||||||
/* Push larger left partition indices. */ \
|
|
||||||
_QSORT_PUSH (_top, _lo, _right_ptr); \
|
|
||||||
_lo = _left_ptr; \
|
|
||||||
} \
|
|
||||||
else { \
|
|
||||||
/* Push larger right partition indices. */ \
|
|
||||||
_QSORT_PUSH (_top, _left_ptr, _hi); \
|
|
||||||
_hi = _right_ptr; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* Once the BASE array is partially sorted by quicksort the rest \
|
|
||||||
is completely sorted using insertion sort, since this is efficient \
|
|
||||||
for partitions below MAX_THRESH size. BASE points to the \
|
|
||||||
beginning of the array to sort, and END_PTR points at the very \
|
|
||||||
last element in the array (*not* one beyond it!). */ \
|
|
||||||
\
|
|
||||||
{ \
|
|
||||||
QSORT_TYPE *const _end_ptr = _base + _elems - 1; \
|
|
||||||
QSORT_TYPE *_tmp_ptr = _base; \
|
|
||||||
register QSORT_TYPE *_run_ptr; \
|
|
||||||
QSORT_TYPE *_thresh; \
|
|
||||||
\
|
|
||||||
_thresh = _base + _QSORT_MAX_THRESH; \
|
|
||||||
if (_thresh > _end_ptr) \
|
|
||||||
_thresh = _end_ptr; \
|
|
||||||
\
|
|
||||||
/* Find smallest element in first threshold and place it at the \
|
|
||||||
array's beginning. This is the smallest array element, \
|
|
||||||
and the operation speeds up insertion sort's inner loop. */ \
|
|
||||||
\
|
|
||||||
for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr) \
|
|
||||||
if (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
|
||||||
_tmp_ptr = _run_ptr; \
|
|
||||||
\
|
|
||||||
if (_tmp_ptr != _base) \
|
|
||||||
_QSORT_SWAP (_tmp_ptr, _base, _hold); \
|
|
||||||
\
|
|
||||||
/* Insertion sort, running from left-hand-side \
|
|
||||||
* up to right-hand-side. */ \
|
|
||||||
\
|
|
||||||
_run_ptr = _base + 1; \
|
|
||||||
while (++_run_ptr <= _end_ptr) { \
|
|
||||||
_tmp_ptr = _run_ptr - 1; \
|
|
||||||
while (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
|
||||||
--_tmp_ptr; \
|
|
||||||
\
|
|
||||||
++_tmp_ptr; \
|
|
||||||
if (_tmp_ptr != _run_ptr) { \
|
|
||||||
QSORT_TYPE *_trav = _run_ptr + 1; \
|
|
||||||
while (--_trav >= _run_ptr) { \
|
|
||||||
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
|
||||||
_hold = *_trav; \
|
|
||||||
\
|
|
||||||
for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo) \
|
|
||||||
*_hi = *_lo; \
|
|
||||||
*_hi = _hold; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
}
|
|
||||||
|
|
173
utils/qsort_bsd.h
Normal file
173
utils/qsort_bsd.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1992, 1993
|
||||||
|
* The Regents of the University of California. 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.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(LIBC_SCCS) && !defined(lint)
|
||||||
|
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
|
||||||
|
#endif /* LIBC_SCCS and not lint */
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
/* __FBSDID("$FreeBSD: head/lib/libc/stdlib/qsort.c 175317 2008-01-14 09:21:34Z das $"); */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static inline char *med3(char *, char *, char *);
|
||||||
|
static inline void swapfunc(char *, char *, int, int);
|
||||||
|
|
||||||
|
#define min(a, b) (a) < (b) ? a : b
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QSORT routine from Bentley & McIlroy's "Engineering a Sort Function".
|
||||||
|
*/
|
||||||
|
#define swapcode(TYPE, parmi, parmj, n) { \
|
||||||
|
long i = (n) / sizeof (TYPE); \
|
||||||
|
TYPE *pi = (TYPE *) (parmi); \
|
||||||
|
TYPE *pj = (TYPE *) (parmj); \
|
||||||
|
do { \
|
||||||
|
TYPE t = *pi; \
|
||||||
|
*pi++ = *pj; \
|
||||||
|
*pj++ = t; \
|
||||||
|
} while (--i > 0); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
|
||||||
|
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
swapfunc(a, b, n, swaptype)
|
||||||
|
char *a, *b;
|
||||||
|
int n, swaptype;
|
||||||
|
{
|
||||||
|
if(swaptype <= 1)
|
||||||
|
swapcode(long, a, b, n)
|
||||||
|
else
|
||||||
|
swapcode(char, a, b, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
#define swap(a, b) \
|
||||||
|
if (swaptype == 0) { \
|
||||||
|
long t = *(long *)(a); \
|
||||||
|
*(long *)(a) = *(long *)(b); \
|
||||||
|
*(long *)(b) = t; \
|
||||||
|
} else \
|
||||||
|
swapfunc(a, b, es, swaptype)
|
||||||
|
|
||||||
|
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
|
||||||
|
|
||||||
|
static inline char *
|
||||||
|
med3(char *a, char *b, char *c)
|
||||||
|
{
|
||||||
|
return QSORT_LT(a, b) < 0 ?
|
||||||
|
(QSORT_LT(b, c) < 0 ? b : (QSORT_LT(a, c) < 0 ? c : a ))
|
||||||
|
:(QSORT_LT(b, c) > 0 ? b : (QSORT_LT(a, c) < 0 ? a : c ));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QSORT(void *arr, size_t n)
|
||||||
|
{
|
||||||
|
char *pa, *pb, *pc, *pd, *pl, *pm, *pn, *a;
|
||||||
|
size_t d, r;
|
||||||
|
int cmp_result;
|
||||||
|
int swaptype, swap_cnt;
|
||||||
|
size_t es = sizeof (QSORT_TYPE);
|
||||||
|
|
||||||
|
a = (char *)arr;
|
||||||
|
loop: SWAPINIT(a, es);
|
||||||
|
swap_cnt = 0;
|
||||||
|
if (n < 7) {
|
||||||
|
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
||||||
|
for (pl = pm;
|
||||||
|
pl > (char *)a && QSORT_LT(pl - es, pl) > 0;
|
||||||
|
pl -= es)
|
||||||
|
swap(pl, pl - es);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pm = (char *)a + (n / 2) * es;
|
||||||
|
if (n > 7) {
|
||||||
|
pl = a;
|
||||||
|
pn = (char *)a + (n - 1) * es;
|
||||||
|
if (n > 40) {
|
||||||
|
d = (n / 8) * es;
|
||||||
|
pl = med3(pl, pl + d, pl + 2 * d);
|
||||||
|
pm = med3(pm - d, pm, pm + d);
|
||||||
|
pn = med3(pn - 2 * d, pn - d, pn);
|
||||||
|
}
|
||||||
|
pm = med3(pl, pm, pn);
|
||||||
|
}
|
||||||
|
swap(a, pm);
|
||||||
|
pa = pb = (char *)a + es;
|
||||||
|
|
||||||
|
pc = pd = (char *)a + (n - 1) * es;
|
||||||
|
for (;;) {
|
||||||
|
while (pb <= pc && (cmp_result = QSORT_LT(pb, a)) <= 0) {
|
||||||
|
if (cmp_result == 0) {
|
||||||
|
swap_cnt = 1;
|
||||||
|
swap(pa, pb);
|
||||||
|
pa += es;
|
||||||
|
}
|
||||||
|
pb += es;
|
||||||
|
}
|
||||||
|
while (pb <= pc && (cmp_result = QSORT_LT(pc, a)) >= 0) {
|
||||||
|
if (cmp_result == 0) {
|
||||||
|
swap_cnt = 1;
|
||||||
|
swap(pc, pd);
|
||||||
|
pd -= es;
|
||||||
|
}
|
||||||
|
pc -= es;
|
||||||
|
}
|
||||||
|
if (pb > pc)
|
||||||
|
break;
|
||||||
|
swap(pb, pc);
|
||||||
|
swap_cnt = 1;
|
||||||
|
pb += es;
|
||||||
|
pc -= es;
|
||||||
|
}
|
||||||
|
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||||
|
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
|
||||||
|
for (pl = pm;
|
||||||
|
pl > (char *)a && QSORT_LT(pl - es, pl) > 0;
|
||||||
|
pl -= es)
|
||||||
|
swap(pl, pl - es);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn = (char *)a + n * es;
|
||||||
|
r = min(pa - (char *)a, pb - pa);
|
||||||
|
vecswap(a, pb - r, r);
|
||||||
|
r = min(pd - pc, pn - pd - es);
|
||||||
|
vecswap(pb, pn - r, r);
|
||||||
|
if ((r = pb - pa) > es)
|
||||||
|
QSORT(a, r / es);
|
||||||
|
if ((r = pd - pc) > es) {
|
||||||
|
/* Iterate rather than recurse to save stack space */
|
||||||
|
a = pn - r;
|
||||||
|
n = r / es;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
/* QSORT(pn - r, r / es);*/
|
||||||
|
}
|
||||||
|
|
314
utils/qsort_gnu.h
Normal file
314
utils/qsort_gnu.h
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* This file is a part of Pcompress, a chunked parallel multi-
|
||||||
|
* algorithm lossless compression and decompression program.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this program.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id: qsort.h,v 1.5 2008-01-28 18:16:49 mjt Exp $
|
||||||
|
* Adopted from GNU glibc by Mjt.
|
||||||
|
* See stdlib/qsort.c in glibc */
|
||||||
|
|
||||||
|
/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
/* in-line qsort implementation. Differs from traditional qsort() routine
|
||||||
|
* in that it is a macro, not a function, and instead of passing an address
|
||||||
|
* of a comparison routine to the function, it is possible to inline
|
||||||
|
* comparison routine, thus speeding up sorting a lot.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* #include "iqsort.h"
|
||||||
|
* #define islt(a,b) (strcmp((*a),(*b))<0)
|
||||||
|
* char *arr[];
|
||||||
|
* int n;
|
||||||
|
* QSORT(char*, arr, n, islt);
|
||||||
|
*
|
||||||
|
* The "prototype" and 4 arguments are:
|
||||||
|
* QSORT(TYPE,BASE,NELT,ISLT)
|
||||||
|
* 1) type of each element, TYPE,
|
||||||
|
* 2) address of the beginning of the array, of type TYPE*,
|
||||||
|
* 3) number of elements in the array, and
|
||||||
|
* 4) comparision routine.
|
||||||
|
* Array pointer and number of elements are referenced only once.
|
||||||
|
* This is similar to a call
|
||||||
|
* qsort(BASE,NELT,sizeof(TYPE),ISLT)
|
||||||
|
* with the difference in last parameter.
|
||||||
|
* Note the islt macro/routine (it receives pointers to two elements):
|
||||||
|
* the only condition of interest is whenever one element is less than
|
||||||
|
* another, no other conditions (greather than, equal to etc) are tested.
|
||||||
|
* So, for example, to define integer sort, use:
|
||||||
|
* #define islt(a,b) ((*a)<(*b))
|
||||||
|
* QSORT(int, arr, n, islt)
|
||||||
|
*
|
||||||
|
* The macro could be used to implement a sorting function (see examples
|
||||||
|
* below), or to implement the sorting algorithm inline. That is, either
|
||||||
|
* create a sorting function and use it whenever you want to sort something,
|
||||||
|
* or use QSORT() macro directly instead a call to such routine. Note that
|
||||||
|
* the macro expands to quite some code (compiled size of int qsort on x86
|
||||||
|
* is about 700..800 bytes).
|
||||||
|
*
|
||||||
|
* Using this macro directly it isn't possible to implement traditional
|
||||||
|
* qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
|
||||||
|
* while qsort() allows element size to be different.
|
||||||
|
*
|
||||||
|
* Several ready-to-use examples:
|
||||||
|
*
|
||||||
|
* Sorting array of integers:
|
||||||
|
* void int_qsort(int *arr, unsigned n) {
|
||||||
|
* #define int_lt(a,b) ((*a)<(*b))
|
||||||
|
* QSORT(int, arr, n, int_lt);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Sorting array of string pointers:
|
||||||
|
* void str_qsort(char *arr[], unsigned n) {
|
||||||
|
* #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
|
||||||
|
* QSORT(char*, arr, n, str_lt);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Sorting array of structures:
|
||||||
|
*
|
||||||
|
* struct elt {
|
||||||
|
* int key;
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
* void elt_qsort(struct elt *arr, unsigned n) {
|
||||||
|
* #define elt_lt(a,b) ((a)->key < (b)->key)
|
||||||
|
* QSORT(struct elt, arr, n, elt_lt);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* And so on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Swap two items pointed to by A and B using temporary buffer t. */
|
||||||
|
#define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
|
||||||
|
|
||||||
|
/* Discontinue quicksort algorithm when partition gets below this size.
|
||||||
|
This particular magic number was chosen to work best on a Sun 4/260. */
|
||||||
|
#define _QSORT_MAX_THRESH 4
|
||||||
|
|
||||||
|
/* Stack node declarations used to store unfulfilled partition obligations
|
||||||
|
* (inlined in QSORT).
|
||||||
|
typedef struct {
|
||||||
|
QSORT_TYPE *_lo, *_hi;
|
||||||
|
} qsort_stack_node;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
||||||
|
/* The stack needs log (total_elements) entries (we could even subtract
|
||||||
|
log(MAX_THRESH)). Since total_elements has type unsigned, we get as
|
||||||
|
upper bound for log (total_elements):
|
||||||
|
bits per byte (CHAR_BIT) * sizeof(unsigned). */
|
||||||
|
#define _QSORT_STACK_SIZE (8 * sizeof(unsigned))
|
||||||
|
#define _QSORT_PUSH(top, low, high) \
|
||||||
|
(((top->_lo = (low)), (top->_hi = (high)), ++top))
|
||||||
|
#define _QSORT_POP(low, high, top) \
|
||||||
|
((--top, (low = top->_lo), (high = top->_hi)))
|
||||||
|
#define _QSORT_STACK_NOT_EMPTY (_stack < _top)
|
||||||
|
|
||||||
|
|
||||||
|
/* Order size using quicksort. This implementation incorporates
|
||||||
|
four optimizations discussed in Sedgewick:
|
||||||
|
|
||||||
|
1. Non-recursive, using an explicit stack of pointer that store the
|
||||||
|
next array partition to sort. To save time, this maximum amount
|
||||||
|
of space required to store an array of SIZE_MAX is allocated on the
|
||||||
|
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
|
||||||
|
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
|
||||||
|
Pretty cheap, actually.
|
||||||
|
|
||||||
|
2. Chose the pivot element using a median-of-three decision tree.
|
||||||
|
This reduces the probability of selecting a bad pivot value and
|
||||||
|
eliminates certain extraneous comparisons.
|
||||||
|
|
||||||
|
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
||||||
|
insertion sort to order the MAX_THRESH items within each partition.
|
||||||
|
This is a big win, since insertion sort is faster for small, mostly
|
||||||
|
sorted array segments.
|
||||||
|
|
||||||
|
4. The larger of the two sub-partitions is always pushed onto the
|
||||||
|
stack first, with the algorithm then concentrating on the
|
||||||
|
smaller partition. This *guarantees* no more than log (total_elems)
|
||||||
|
stack size is needed (actually O(1) in this case)! */
|
||||||
|
|
||||||
|
/* The main code starts here... */
|
||||||
|
#define QSORT(QSORT_BASE,QSORT_NELT) \
|
||||||
|
{ \
|
||||||
|
QSORT_TYPE *const _base = (QSORT_BASE); \
|
||||||
|
const unsigned _elems = (QSORT_NELT); \
|
||||||
|
QSORT_TYPE _hold; \
|
||||||
|
\
|
||||||
|
/* Don't declare two variables of type QSORT_TYPE in a single \
|
||||||
|
* statement: eg `TYPE a, b;', in case if TYPE is a pointer, \
|
||||||
|
* expands to `type* a, b;' wich isn't what we want. \
|
||||||
|
*/ \
|
||||||
|
\
|
||||||
|
if (_elems > _QSORT_MAX_THRESH) { \
|
||||||
|
QSORT_TYPE *_lo = _base; \
|
||||||
|
QSORT_TYPE *_hi = _lo + _elems - 1; \
|
||||||
|
struct { \
|
||||||
|
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
||||||
|
} _stack[_QSORT_STACK_SIZE], *_top = _stack + 1; \
|
||||||
|
\
|
||||||
|
while (_QSORT_STACK_NOT_EMPTY) { \
|
||||||
|
QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr; \
|
||||||
|
\
|
||||||
|
/* Select median value from among LO, MID, and HI. Rearrange \
|
||||||
|
LO and HI so the three values are sorted. This lowers the \
|
||||||
|
probability of picking a pathological pivot value and \
|
||||||
|
skips a comparison for both the LEFT_PTR and RIGHT_PTR in \
|
||||||
|
the while loops. */ \
|
||||||
|
\
|
||||||
|
QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1); \
|
||||||
|
\
|
||||||
|
if (QSORT_LT (_mid, _lo)) \
|
||||||
|
_QSORT_SWAP (_mid, _lo, _hold); \
|
||||||
|
if (QSORT_LT (_hi, _mid)) { \
|
||||||
|
_QSORT_SWAP (_mid, _hi, _hold); \
|
||||||
|
if (QSORT_LT (_mid, _lo)) \
|
||||||
|
_QSORT_SWAP (_mid, _lo, _hold); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
_left_ptr = _lo + 1; \
|
||||||
|
_right_ptr = _hi - 1; \
|
||||||
|
\
|
||||||
|
/* Here's the famous ``collapse the walls'' section of quicksort. \
|
||||||
|
Gotta like those tight inner loops! They are the main reason \
|
||||||
|
that this algorithm runs much faster than others. */ \
|
||||||
|
do { \
|
||||||
|
while (QSORT_LT (_left_ptr, _mid)) \
|
||||||
|
++_left_ptr; \
|
||||||
|
\
|
||||||
|
while (QSORT_LT (_mid, _right_ptr)) \
|
||||||
|
--_right_ptr; \
|
||||||
|
\
|
||||||
|
if (_left_ptr < _right_ptr) { \
|
||||||
|
_QSORT_SWAP (_left_ptr, _right_ptr, _hold); \
|
||||||
|
if (_mid == _left_ptr) \
|
||||||
|
_mid = _right_ptr; \
|
||||||
|
else if (_mid == _right_ptr) \
|
||||||
|
_mid = _left_ptr; \
|
||||||
|
++_left_ptr; \
|
||||||
|
--_right_ptr; \
|
||||||
|
} \
|
||||||
|
else if (_left_ptr == _right_ptr) { \
|
||||||
|
++_left_ptr; \
|
||||||
|
--_right_ptr; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} while (_left_ptr <= _right_ptr); \
|
||||||
|
\
|
||||||
|
/* Set up pointers for next iteration. First determine whether \
|
||||||
|
left and right partitions are below the threshold size. If so, \
|
||||||
|
ignore one or both. Otherwise, push the larger partition's \
|
||||||
|
bounds on the stack and continue sorting the smaller one. */ \
|
||||||
|
\
|
||||||
|
if (_right_ptr - _lo <= _QSORT_MAX_THRESH) { \
|
||||||
|
if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
||||||
|
/* Ignore both small partitions. */ \
|
||||||
|
_QSORT_POP (_lo, _hi, _top); \
|
||||||
|
else \
|
||||||
|
/* Ignore small left partition. */ \
|
||||||
|
_lo = _left_ptr; \
|
||||||
|
} \
|
||||||
|
else if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
||||||
|
/* Ignore small right partition. */ \
|
||||||
|
_hi = _right_ptr; \
|
||||||
|
else if (_right_ptr - _lo > _hi - _left_ptr) { \
|
||||||
|
/* Push larger left partition indices. */ \
|
||||||
|
_QSORT_PUSH (_top, _lo, _right_ptr); \
|
||||||
|
_lo = _left_ptr; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
/* Push larger right partition indices. */ \
|
||||||
|
_QSORT_PUSH (_top, _left_ptr, _hi); \
|
||||||
|
_hi = _right_ptr; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Once the BASE array is partially sorted by quicksort the rest \
|
||||||
|
is completely sorted using insertion sort, since this is efficient \
|
||||||
|
for partitions below MAX_THRESH size. BASE points to the \
|
||||||
|
beginning of the array to sort, and END_PTR points at the very \
|
||||||
|
last element in the array (*not* one beyond it!). */ \
|
||||||
|
\
|
||||||
|
{ \
|
||||||
|
QSORT_TYPE *const _end_ptr = _base + _elems - 1; \
|
||||||
|
QSORT_TYPE *_tmp_ptr = _base; \
|
||||||
|
register QSORT_TYPE *_run_ptr; \
|
||||||
|
QSORT_TYPE *_thresh; \
|
||||||
|
\
|
||||||
|
_thresh = _base + _QSORT_MAX_THRESH; \
|
||||||
|
if (_thresh > _end_ptr) \
|
||||||
|
_thresh = _end_ptr; \
|
||||||
|
\
|
||||||
|
/* Find smallest element in first threshold and place it at the \
|
||||||
|
array's beginning. This is the smallest array element, \
|
||||||
|
and the operation speeds up insertion sort's inner loop. */ \
|
||||||
|
\
|
||||||
|
for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr) \
|
||||||
|
if (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
||||||
|
_tmp_ptr = _run_ptr; \
|
||||||
|
\
|
||||||
|
if (_tmp_ptr != _base) \
|
||||||
|
_QSORT_SWAP (_tmp_ptr, _base, _hold); \
|
||||||
|
\
|
||||||
|
/* Insertion sort, running from left-hand-side \
|
||||||
|
* up to right-hand-side. */ \
|
||||||
|
\
|
||||||
|
_run_ptr = _base + 1; \
|
||||||
|
while (++_run_ptr <= _end_ptr) { \
|
||||||
|
_tmp_ptr = _run_ptr - 1; \
|
||||||
|
while (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
||||||
|
--_tmp_ptr; \
|
||||||
|
\
|
||||||
|
++_tmp_ptr; \
|
||||||
|
if (_tmp_ptr != _run_ptr) { \
|
||||||
|
QSORT_TYPE *_trav = _run_ptr + 1; \
|
||||||
|
while (--_trav >= _run_ptr) { \
|
||||||
|
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
||||||
|
_hold = *_trav; \
|
||||||
|
\
|
||||||
|
for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo) \
|
||||||
|
*_hi = *_lo; \
|
||||||
|
*_hi = _hold; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
}
|
Loading…
Reference in a new issue