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:
Moinak Ghosh 2014-07-24 22:20:30 +05:30
parent 0433452b37
commit 10f40e1c6f
16 changed files with 577 additions and 326 deletions

View file

@ -42,23 +42,28 @@
#include "pc_arc_filter.h"
#include "pc_archive.h"
#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

View file

@ -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

19
config
View file

@ -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
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'
;;

View file

@ -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"
@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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
View 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; \
} \
} \
} \
} \
\
}