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
|
@ -223,7 +223,7 @@ BASE_CPPFLAGS = -I. -I./lzma -I./lzfx -I./lz4 -I./rabin -I./bsdiff -DNODEFAULT_P
|
|||
-I./crypto/xsalsa20 -I./archive -pedantic -Wall -I./filters -fno-strict-aliasing \
|
||||
-Wno-unused-but-set-variable -Wno-enum-compare \
|
||||
@COMPAT_CPPFLAGS@ @XSALSA20_DEBUG@ @LIBARCHIVE_INC@ -I./filters/packjpg
|
||||
COMMON_CPPFLAGS = $(BASE_CPPFLAGS) -std=gnu99
|
||||
COMMON_CPPFLAGS = $(BASE_CPPFLAGS) -std=gnu99
|
||||
COMMON_CPPFLAGS_cpp = $(BASE_CPPFLAGS)
|
||||
COMMON_VEC_FLAGS = -ftree-vectorize
|
||||
COMMON_LOOP_OPTFLAGS = $(VEC_FLAGS) -floop-interchange -floop-block
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -42,23 +42,28 @@
|
|||
#include "pc_arc_filter.h"
|
||||
#include "pc_archive.h"
|
||||
|
||||
#define PACKJPG_DEF_BUFSIZ (512 * 1024)
|
||||
#define JPG_SIZE_LIMIT (8 * 1024 * 1024)
|
||||
#define PJG_APPVERSION1 (25)
|
||||
#define PJG_APPVERSION2 (25)
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
# define PACKJPG_DEF_BUFSIZ (512 * 1024)
|
||||
# define JPG_SIZE_LIMIT (8 * 1024 * 1024)
|
||||
# define PJG_APPVERSION1 (25)
|
||||
# define PJG_APPVERSION2 (25)
|
||||
#endif
|
||||
|
||||
struct scratch_buffer {
|
||||
uchar_t *in_buff;
|
||||
size_t in_bufflen;
|
||||
};
|
||||
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
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);
|
||||
#endif
|
||||
|
||||
void
|
||||
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||
{
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
struct scratch_buffer *sdat;
|
||||
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_name = "packJPG";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -138,6 +144,7 @@ write_archive_data(struct archive *aw, uchar_t *out_buf, size_t len, int block_s
|
|||
return (tot);
|
||||
}
|
||||
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
int
|
||||
pjg_version_supported(char ver)
|
||||
{
|
||||
|
@ -252,4 +259,5 @@ packjpg_filter(struct filter_info *fi, void *filter_private)
|
|||
free(out);
|
||||
return (rv);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PC_ARCHIVE_FILTER_H
|
||||
|
@ -67,4 +67,4 @@ void add_filters_by_type(struct type_data *typetab, struct filter_flags *ff);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -32,6 +32,8 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <utils.h>
|
||||
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
#include <packjpglib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -104,3 +106,4 @@ packjpg_filter_process(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
31
config
31
config
|
@ -20,6 +20,8 @@
|
|||
# moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
#
|
||||
|
||||
my_license=LGPLv3
|
||||
|
||||
usage() {
|
||||
prog=$1
|
||||
cat << _EOF
|
||||
|
@ -40,9 +42,12 @@ ${prog} [<options>]
|
|||
Enable building against an alternate Bzip2 and library installation.
|
||||
--with-libarchive=<path to libarchive installation tree> (Default: System)
|
||||
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.
|
||||
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
|
||||
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
|
||||
|
@ -60,12 +65,16 @@ debug=0
|
|||
allocator=1
|
||||
debug_stats=0
|
||||
prefix=/usr
|
||||
libbsc_dir=./bsc
|
||||
libbsc_lib=${libbsc_dir}/libbsc.a
|
||||
libbsclflags='\$\(LIBBSCLFLAGS\)'
|
||||
libbscwrapobj='\$\(LIBBSCWRAPOBJ\)'
|
||||
libbscgenopt='\$\(LIBBSCGEN_OPT\)'
|
||||
libbsccppflags='\$\(LIBBSCCPPFLAGS\)'
|
||||
|
||||
if [ "$my_license" = "LGPLv3" ]
|
||||
then
|
||||
libbsc_dir=./bsc
|
||||
libbsc_lib=${libbsc_dir}/libbsc.a
|
||||
libbsclflags='\$\(LIBBSCLFLAGS\)'
|
||||
libbscwrapobj='\$\(LIBBSCWRAPOBJ\)'
|
||||
libbscgenopt='\$\(LIBBSCGEN_OPT\)'
|
||||
libbsccppflags='\$\(LIBBSCCPPFLAGS\)'
|
||||
fi
|
||||
openssl_prefix=
|
||||
openssl_libdir=
|
||||
openssl_incdir=
|
||||
|
@ -195,6 +204,14 @@ do
|
|||
--with-libarchive=*)
|
||||
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)
|
||||
keylen='-DDEFAULT_KEYLEN=16'
|
||||
;;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -150,7 +150,7 @@ int
|
|||
libbsc_deinit(void **data)
|
||||
{
|
||||
struct libbsc_params *bscdat = (struct libbsc_params *)(*data);
|
||||
|
||||
|
||||
if (bscdat) {
|
||||
slab_free(NULL, bscdat);
|
||||
}
|
||||
|
|
18
pcompress.c
18
pcompress.c
|
@ -78,7 +78,8 @@ usage(pc_ctx_t *pctx)
|
|||
{
|
||||
|
||||
fprintf(stderr,
|
||||
"\nPcompress Version %s\n\n"
|
||||
"\nPcompress Version %s\n"
|
||||
"License: %s\n\n"
|
||||
"See README.md for detailed usage.\n\n"
|
||||
"Standard Usage\n"
|
||||
"==============\n"
|
||||
|
@ -144,7 +145,7 @@ usage(pc_ctx_t *pctx)
|
|||
" 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"
|
||||
" 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,
|
||||
" Encryption\n"
|
||||
" ----------\n"
|
||||
|
@ -187,10 +188,10 @@ show_compression_stats(pc_ctx_t *pctx)
|
|||
/*
|
||||
* Wrapper functions to pre-process the buffer and then call the main compression routine.
|
||||
* At present only LZP pre-compression is used below. Some extra metadata is added:
|
||||
*
|
||||
*
|
||||
* Byte 0: A flag to indicate which pre-processor was used.
|
||||
* Byte 1 - Byte 8: Size of buffer after pre-processing
|
||||
*
|
||||
*
|
||||
* It is possible for a buffer to be only pre-processed and not compressed by the final
|
||||
* algorithm if the final one fails to compress for some reason. However the vice versa
|
||||
* is not allowed.
|
||||
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pctx->enable_delta2_encode && props->delta2_span > 0 &&
|
||||
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) {
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
int hashsize;
|
||||
hashsize = lzp_hash_size(level);
|
||||
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.");
|
||||
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) {
|
||||
|
@ -2960,10 +2968,12 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
|||
pctx->enable_rabin_split = 0;
|
||||
break;
|
||||
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
case 'L':
|
||||
pctx->advanced_opts = 1;
|
||||
pctx->lzp_preprocess = 1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'P':
|
||||
pctx->advanced_opts = 1;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PCOMPRESS_H
|
||||
|
@ -49,6 +49,12 @@ extern "C" {
|
|||
#define MASK_CRYPTO_ALG 0x30
|
||||
#define MAX_LEVEL 14
|
||||
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
#define LICENSE_STRING "LGPLv3"
|
||||
#else
|
||||
#define LICENSE_STRING "MPLv2"
|
||||
#endif
|
||||
|
||||
#define COMPRESSED 1
|
||||
#define UNCOMPRESSED 0
|
||||
#define CHSIZE_MASK 0x80
|
||||
|
|
|
@ -76,9 +76,12 @@ init_global_db(char *configfile)
|
|||
int
|
||||
init_on_disk_index(archive_config_t *cfg)
|
||||
{
|
||||
#if 0
|
||||
if (file_exists()) {
|
||||
|
||||
}
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
/*
|
||||
* The rabin polynomial computation is derived from:
|
||||
* http://code.google.com/p/rabin-fingerprint-c/
|
||||
*
|
||||
*
|
||||
* originally created by Joel Lawrence Tucci on 09-March-2011.
|
||||
*
|
||||
*
|
||||
* Rabin polynomial portions Copyright (c) 2011 Joel Lawrence Tucci
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Neither the name of the project's author 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
|
@ -58,7 +58,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
|
@ -75,6 +75,9 @@
|
|||
#include <pthread.h>
|
||||
#include <heap.h>
|
||||
#include <xxhash.h>
|
||||
|
||||
#define QSORT_LT(a, b) ((*a)<(*b))
|
||||
#define QSORT_TYPE uint64_t
|
||||
#include <qsort.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
|
||||
* inline quicksort routine that does not use a callback function.
|
||||
*/
|
||||
#define int_lt(a,b) ((*a)<(*b))
|
||||
static void
|
||||
do_qsort(uint64_t *arr, uint32_t len)
|
||||
{
|
||||
QSORT(uint64_t, arr, len, int_lt);
|
||||
QSORT(arr, len);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
|
295
utils/qsort.h
295
utils/qsort.h
|
@ -22,293 +22,8 @@
|
|||
* 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_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; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
}
|
||||
#ifndef _MPLV2_LICENSE_
|
||||
#include "qsort_gnu.h"
|
||||
#else
|
||||
#include "qsort_bsd.h"
|
||||
#endif
|
||||
|
|
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; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* moinakg@belenix.org, http://moinakg.wordpress.com/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue