1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Postgres95 1.01 Distribution - Virgin Sources

This commit is contained in:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

View File

@ -0,0 +1,20 @@
#-------------------------------------------------------------------------
#
# Makefile.inc--
# Makefile for the lib module (miscellaneous stuff)
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/lib/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:28 scrappy Exp $
#
#-------------------------------------------------------------------------
VPATH:=$(VPATH):$(CURDIR)/lib
SRCS_LIB= bit.c fstack.c hasht.c lispsort.c qsort.c stringinfo.c dllist.c
HEADERS+= fstack.h hasht.h lispsort.h qsort.h stringinfo.h dllist.h

45
src/backend/lib/bit.c Normal file
View File

@ -0,0 +1,45 @@
/*-------------------------------------------------------------------------
*
* bit.c--
* Standard bit array code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/bit.c,v 1.1.1.1 1996/07/09 06:21:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* utils/memutils.h contains declarations of the functions in this file
*/
#include "utils/memutils.h"
void
BitArraySetBit(BitArray bitArray, BitIndex bitIndex)
{
bitArray[bitIndex/BitsPerByte]
|= (1 << (BitsPerByte - (bitIndex % BitsPerByte) - 1));
return;
}
void
BitArrayClearBit(BitArray bitArray, BitIndex bitIndex)
{
bitArray[bitIndex/BitsPerByte]
&= ~(1 << (BitsPerByte - (bitIndex % BitsPerByte) - 1));
return;
}
bool
BitArrayBitIsSet(BitArray bitArray, BitIndex bitIndex)
{
return( (bool) (((bitArray[bitIndex / BitsPerByte] &
(1 << (BitsPerByte - (bitIndex % BitsPerByte)
- 1)
)
) != 0 ) ? 1 : 0) );
}

204
src/backend/lib/dllist.c Normal file
View File

@ -0,0 +1,204 @@
/*-------------------------------------------------------------------------
*
* dllist.c--
* this is a simple doubly linked list implementation
* replaces the old simplelists stuff
* the elements of the lists are void*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/dllist.c,v 1.1.1.1 1996/07/09 06:21:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include "lib/dllist.h"
Dllist*
DLNewList()
{
Dllist* l;
l = malloc(sizeof(Dllist));
l->dll_head = 0;
l->dll_tail = 0;
return l;
}
/* free up a list and all the nodes in it*/
void
DLFreeList(Dllist* l)
{
Dlelem* curr;
while ( (curr = DLRemHead(l)) != 0)
free(curr);
free(l);
}
Dlelem*
DLNewElem(void* val)
{
Dlelem* e;
e = malloc(sizeof(Dlelem));
e->dle_next = 0;
e->dle_prev = 0;
e->dle_val = val;
e->dle_list = 0;
return e;
}
void
DLFreeElem(Dlelem* e)
{
free(e);
}
Dlelem*
DLGetHead(Dllist* l)
{
return (l ? l->dll_head : 0);
}
/* get the value stored in the first element */
void*
DLGetHeadVal(Dllist* l)
{
Dlelem* e = DLGetHead(l);
return (e ? e->dle_val : 0);
}
Dlelem*
DLGetTail(Dllist* l)
{
return (l ? l->dll_tail : 0);
}
/* get the value stored in the first element */
void*
DLGetTailVal(Dllist* l)
{
Dlelem* e = DLGetTail(l);
return (e ? e->dle_val : 0);
}
Dlelem*
DLGetPred(Dlelem* e) /* get predecessor */
{
return (e ? e->dle_prev : 0);
}
Dlelem*
DLGetSucc(Dlelem* e) /* get successor */
{
return (e ? e->dle_next : 0);
}
void
DLRemove(Dlelem* e)
{
Dllist* l;
if (e->dle_prev)
e->dle_prev->dle_next = e->dle_next;
if (e->dle_next)
e->dle_next->dle_prev = e->dle_prev;
/* check to see if we're removing the head or tail */
l = e->dle_list;
if (e == l->dll_head)
DLRemHead(l);
if (e == l->dll_tail)
DLRemTail(l);
}
void
DLAddHead(Dllist* l, Dlelem* e)
{
e->dle_list = l;
if (l->dll_head) {
l->dll_head->dle_prev = e;
e->dle_next = l->dll_head;
}
e->dle_prev = 0;
l->dll_head = e;
if (l->dll_tail == 0) /* if this is first element added */
l->dll_tail = l->dll_head;
}
void
DLAddTail(Dllist* l, Dlelem* e)
{
e->dle_list = l;
if (l->dll_tail) {
l->dll_tail->dle_next = e;
e->dle_prev = l->dll_tail;
}
e->dle_next = 0;
l->dll_tail = e;
if (l->dll_head == 0) /* if this is first element added */
l->dll_head = l->dll_tail;
}
Dlelem*
DLRemHead(Dllist* l)
{
/* remove and return the head */
Dlelem* result;
if (l->dll_head == 0)
return 0;
result = l->dll_head;
if (l->dll_head->dle_next) {
l->dll_head->dle_next->dle_prev = 0;
}
l->dll_head = l->dll_head->dle_next;
result->dle_next = 0;
result->dle_list = 0;
if (result == l->dll_tail) /* if the head is also the tail */
l->dll_tail = 0;
return result;
}
Dlelem*
DLRemTail(Dllist* l)
{
/* remove and return the tail */
Dlelem* result;
if (l->dll_tail == 0 )
return 0;
result = l->dll_tail;
if (l->dll_tail->dle_prev) {
l->dll_tail->dle_prev->dle_next = 0;
}
l->dll_tail = l->dll_tail->dle_prev;
result->dle_prev = 0;
result->dle_list = 0;
if (result == l->dll_head) /* if the tail is also the head */
l->dll_head = 0;
return result;
}

72
src/backend/lib/dllist.h Normal file
View File

@ -0,0 +1,72 @@
/*-------------------------------------------------------------------------
*
* dllist.h--
* simple doubly linked list primitives
* the elements of the list are void* so the lists can contain
* anything
* Dlelem can only be in one list at a time
*
*
* Here's a small example of how to use Dllist's :
*
* Dllist *lst;
* Dlelem *elt;
* void *in_stuff; -- stuff to stick in the list
* void *out_stuff
*
* lst = DLNewList(); -- make a new dllist
* DLAddHead(lst, DLNewElem(in_stuff)); -- add a new element to the list
* with in_stuff as the value
* ...
* elt = DLGetHead(lst); -- retrieve the head element
* out_stuff = (void*)DLE_VAL(elt); -- get the stuff out
* DLRemove(elt); -- removes the element from its list
* DLFreeElem(elt); -- free the element since we don't
* use it anymore
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: dllist.h,v 1.1.1.1 1996/07/09 06:21:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef DLLIST_H
#define DLLIST_H
#include "c.h"
struct Dllist;
struct Dlelem;
typedef struct Dlelem {
struct Dlelem *dle_next; /* next element */
struct Dlelem *dle_prev; /* previous element */
void *dle_val; /* value of the element */
struct Dllist *dle_list; /* what list this element is in */
} Dlelem;
typedef struct Dllist {
Dlelem *dll_head;
Dlelem *dll_tail;
} Dllist;
extern Dllist* DLNewList(); /* initialize a new list */
extern void DLFreeList(Dllist*); /* free up a list and all the nodes in it*/
extern Dlelem* DLNewElem(void* val);
extern void DLFreeElem(Dlelem*);
extern Dlelem* DLGetHead(Dllist*);
extern Dlelem* DLGetTail(Dllist*);
extern void* DLGetHeadVal(Dllist*);
extern void* DLGetTailVal(Dllist*);
extern Dlelem* DLGetPred(Dlelem*); /* get predecessor */
extern Dlelem* DLGetSucc(Dlelem*); /* get successor */
extern void DLRemove(Dlelem*); /* removes node from list*/
extern void DLAddHead(Dllist* list, Dlelem* node);
extern void DLAddTail(Dllist* list, Dlelem* node);
extern Dlelem* DLRemHead(Dllist* list); /* remove and return the head */
extern Dlelem* DLRemTail(Dllist* list); /* remove and return the tail */
#define DLE_VAL(x) (x->dle_val)
#endif /* DLLIST_H */

153
src/backend/lib/fstack.c Normal file
View File

@ -0,0 +1,153 @@
/*-------------------------------------------------------------------------
*
* fstack.c--
* Fixed format stack definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.1.1.1 1996/07/09 06:21:28 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include "lib/fstack.h"
/*
* Internal function definitions
*/
/*
* FixedItemIsValid --
* True iff item is valid.
*/
#define FixedItemIsValid(item) PointerIsValid(item)
/*
* FixedStackGetItemBase --
* Returns base of enclosing structure.
*/
#define FixedStackGetItemBase(stack, item) \
((Pointer)((char *)(item) - (stack)->offset))
/*
* FixedStackGetItem --
* Returns item of given pointer to enclosing structure.
*/
#define FixedStackGetItem(stack, pointer) \
((FixedItem)((char *)(pointer) + (stack)->offset))
/*
* External functions
*/
/*
* FixedStackIsValid --
* True iff stack is valid.
*/
static bool
FixedStackIsValid(FixedStack stack)
{
return ((bool)PointerIsValid(stack));
}
void
FixedStackInit(FixedStack stack, Offset offset)
{
AssertArg(PointerIsValid(stack));
stack->top = NULL;
stack->offset = offset;
}
Pointer
FixedStackPop(FixedStack stack)
{
Pointer pointer;
AssertArg(FixedStackIsValid(stack));
if (!PointerIsValid(stack->top)) {
return (NULL);
}
pointer = FixedStackGetItemBase(stack, stack->top);
stack->top = stack->top->next;
return (pointer);
}
void
FixedStackPush(FixedStack stack, Pointer pointer)
{
FixedItem item = FixedStackGetItem(stack, pointer);
AssertArg(FixedStackIsValid(stack));
AssertArg(PointerIsValid(pointer));
item->next = stack->top;
stack->top = item;
}
/*
* FixedStackContains --
* True iff ordered stack contains given element.
*
* Note:
* This is inefficient. It is intended for debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
*/
static bool
FixedStackContains(FixedStack stack, Pointer pointer)
{
FixedItem next;
FixedItem item;
AssertArg(FixedStackIsValid(stack));
AssertArg(PointerIsValid(pointer));
item = FixedStackGetItem(stack, pointer);
for (next = stack->top; FixedItemIsValid(next); next = next->next) {
if (next == item) {
return (true);
}
}
return (false);
}
Pointer
FixedStackGetTop(FixedStack stack)
{
AssertArg(FixedStackIsValid(stack));
if (!PointerIsValid(stack->top)) {
return (NULL);
}
return (FixedStackGetItemBase(stack, stack->top));
}
Pointer
FixedStackGetNext(FixedStack stack, Pointer pointer)
{
FixedItem item;
/* AssertArg(FixedStackIsValid(stack)); */
/* AssertArg(PointerIsValid(pointer)); */
AssertArg(FixedStackContains(stack, pointer));
item = FixedStackGetItem(stack, pointer)->next;
if (!PointerIsValid(item)) {
return (NULL);
}
return(FixedStackGetItemBase(stack, item));
}

113
src/backend/lib/fstack.h Normal file
View File

@ -0,0 +1,113 @@
/*-------------------------------------------------------------------------
*
* fstack.h--
* Fixed format stack definitions.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: fstack.h,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Note:
* Fixed format stacks assist in the construction of FIFO stacks of
* fixed format structures. Structures which are to be stackable
* should contain a FixedItemData component. A stack is initilized
* with the offset of the FixedItemData component of the structure
* it will hold. By doing so, push and pop operations are simplified
* for the callers. All references to stackable items are pointers
* to the base of the structure instead of pointers to the
* FixedItemData component.
*
*/
#ifndef FSTACK_H
#define FSTACK_H
#include "c.h"
/*
* FixedItem --
* Fixed format stackable item chain component.
*
* Note:
* Structures must contain one FixedItemData component per stack in
* which it will be an item.
*/
typedef struct FixedItemData FixedItemData;
typedef FixedItemData *FixedItem;
struct FixedItemData {
FixedItem next; /* next item or NULL */
};
/*
* FixedStack --
* Fixed format stack.
*/
typedef struct FixedStackData {
FixedItem top; /* Top item on the stack or NULL */
Offset offset; /* Offset from struct base to item */
/* this could be signed short int! */
} FixedStackData;
typedef FixedStackData *FixedStack;
/*
* FixedStackInit --
* Iniitializes stack for structures with given fixed component offset.
*
* Exceptions:
* BadArg if stack is invalid pointer.
*/
extern void FixedStackInit(FixedStack stack, Offset offset);
/*
* FixedStackPop --
* Returns pointer to top structure on stack or NULL if empty stack.
*
* Exceptions:
* BadArg if stack is invalid.
*/
Pointer FixedStackPop(FixedStack stack);
/*
* FixedStackPush --
* Places structure associated with pointer onto top of stack.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
*/
extern void FixedStackPush(FixedStack stack, Pointer pointer);
/*
* FixedStackGetTop --
* Returns pointer to top structure of a stack. This item is not poped.
*
* Note:
* This is not part of the normal stack interface. It is intended for
* debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
*/
extern Pointer FixedStackGetTop(FixedStack stack);
/*
* FixedStackGetNext --
* Returns pointer to next structure after pointer of a stack.
*
* Note:
* This is not part of the normal stack interface. It is intended for
* debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
* BadArg if stack does not contain pointer.
*/
extern Pointer FixedStackGetNext(FixedStack stack, Pointer pointer);
#endif /* FSTACK_H */

47
src/backend/lib/hasht.c Normal file
View File

@ -0,0 +1,47 @@
/*-------------------------------------------------------------------------
*
* hasht.c--
* hash table related functions that are not directly supported
* by the hashing packages under utils/hash.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/hasht.c,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include "utils/memutils.h"
#include "utils/elog.h"
#include "utils/hsearch.h"
#include "lib/hasht.h"
/* -----------------------------------
* HashTableWalk
*
* call function on every element in hashtable
* one extra argument, arg may be supplied
* -----------------------------------
*/
void
HashTableWalk(HTAB *hashtable, HashtFunc function, int arg)
{
long *hashent;
long *data;
int keysize;
keysize = hashtable->hctl->keysize;
(void)hash_seq((HTAB *)NULL);
while ((hashent = hash_seq(hashtable)) != (long *) TRUE) {
if (hashent == NULL)
elog(FATAL, "error in HashTableWalk.");
/*
* XXX the corresponding hash table insertion does NOT
* LONGALIGN -- make sure the keysize is ok
*/
data = (long *) LONGALIGN((char*) hashent + keysize);
(*function)(data, arg);
}
}

23
src/backend/lib/hasht.h Normal file
View File

@ -0,0 +1,23 @@
/*-------------------------------------------------------------------------
*
* hasht.h--
* hash table related functions that are not directly supported
* under utils/hash.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: hasht.h,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef HASHT_H
#define HASHT_H
#include "utils/hsearch.h"
typedef void (*HashtFunc)();
extern void HashTableWalk(HTAB *hashtable, HashtFunc function, int arg);
#endif /* HASHT_H */

View File

@ -0,0 +1,56 @@
/*-------------------------------------------------------------------------
*
* lispsort.c--
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/lispsort.c,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "lib/lispsort.h"
#include "utils/palloc.h"
#include "lib/qsort.h"
/*
** lisp_qsort: Takes a lisp list as input, copies it into an array of lisp
** nodes which it sorts via qsort() with the comparison function
** as passed into lisp_qsort(), and returns a new list with
** the nodes sorted. The old list is *not* freed or modified (?)
*/
List *lisp_qsort(List *the_list, /* the list to be sorted */
int (*compare)()) /* function to compare two nodes */
{
int i;
size_t num;
List **nodearray;
List *tmp, *output;
/* find size of list */
num = length(the_list);
if (num < 2)
return(copyObject(the_list));
/* copy elements of the list into an array */
nodearray = (List **) palloc(num * sizeof(List *));
for (tmp = the_list, i = 0; tmp != NIL; tmp = lnext(tmp), i++)
nodearray[i] = copyObject(lfirst(tmp));
/* sort the array */
pg_qsort(nodearray, num, sizeof(List *), compare);
/* lcons together the array elements */
output = NIL;
for (i = num - 1; i >= 0; i--)
output = lcons(nodearray[i], output);
return(output);
}

View File

@ -0,0 +1,18 @@
/*-------------------------------------------------------------------------
*
* lispsort.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lispsort.h,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LISPSORT_H
#define LISPSORT_H
extern List *lisp_qsort(List *the_list, int (*compare)());
#endif /* LISPSORT_H */

281
src/backend/lib/qsort.c Normal file
View File

@ -0,0 +1,281 @@
/*-------------------------------------------------------------------------
*
* qsort.c--
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/qsort.c,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*-
* Copyright (c) 1980, 1983, 1990 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 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 5.9 (Berkeley) 2/23/91";
#endif /* LIBC_SCCS and not lint */
#include "postgres.h"
#include "lib/qsort.h"
/*
* MTHRESH is the smallest partition for which we compare for a median
* value instead of using the middle value.
*/
#define MTHRESH 6
/*
* THRESH is the minimum number of entries in a partition for continued
* partitioning.
*/
#define THRESH 4
static void insertion_sort(char* bot, int nmemb, int size, int (*compar)());
static void quick_sort(char* bot, int nmemb, int size, int (*compar)());
void pg_qsort(void *bot,
size_t nmemb,
size_t size,
int (*compar)(void *, void *))
{
if (nmemb <= 1)
return;
if (nmemb >= THRESH)
quick_sort(bot, nmemb, size, compar);
else
insertion_sort(bot, nmemb, size, compar);
}
/*
* Swap two areas of size number of bytes. Although qsort(3) permits random
* blocks of memory to be sorted, sorting pointers is almost certainly the
* common case (and, were it not, could easily be made so). Regardless, it
* isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
* arithmetic gets lost in the time required for comparison function calls.
*/
#define SWAP(a, b) { \
cnt = size; \
do { \
ch = *a; \
*a++ = *b; \
*b++ = ch; \
} while (--cnt); \
}
/*
* Knuth, Vol. 3, page 116, Algorithm Q, step b, argues that a single pass
* of straight insertion sort after partitioning is complete is better than
* sorting each small partition as it is created. This isn't correct in this
* implementation because comparisons require at least one (and often two)
* function calls and are likely to be the dominating expense of the sort.
* Doing a final insertion sort does more comparisons than are necessary
* because it compares the "edges" and medians of the partitions which are
* known to be already sorted.
*
* This is also the reasoning behind selecting a small THRESH value (see
* Knuth, page 122, equation 26), since the quicksort algorithm does less
* comparisons than the insertion sort.
*/
#define SORT(bot, n) { \
if (n > 1) \
if (n == 2) { \
t1 = bot + size; \
if (compar(t1, bot) < 0) \
SWAP(t1, bot); \
} else \
insertion_sort(bot, n, size, compar); \
}
static void
quick_sort(char* bot, int nmemb, int size, int (*compar)())
{
register int cnt;
register u_char ch;
register char *top, *mid, *t1, *t2;
register int n1, n2;
char *bsv;
/* bot and nmemb must already be set. */
partition:
/* find mid and top elements */
mid = bot + size * (nmemb >> 1);
top = bot + (nmemb - 1) * size;
/*
* Find the median of the first, last and middle element (see Knuth,
* Vol. 3, page 123, Eq. 28). This test order gets the equalities
* right.
*/
if (nmemb >= MTHRESH) {
n1 = compar(bot, mid);
n2 = compar(mid, top);
if (n1 < 0 && n2 > 0)
t1 = compar(bot, top) < 0 ? top : bot;
else if (n1 > 0 && n2 < 0)
t1 = compar(bot, top) > 0 ? top : bot;
else
t1 = mid;
/* if mid element not selected, swap selection there */
if (t1 != mid) {
SWAP(t1, mid);
mid -= size;
}
}
/* Standard quicksort, Knuth, Vol. 3, page 116, Algorithm Q. */
#define didswap n1
#define newbot t1
#define replace t2
didswap = 0;
for (bsv = bot;;) {
for (; bot < mid && compar(bot, mid) <= 0; bot += size);
while (top > mid) {
if (compar(mid, top) <= 0) {
top -= size;
continue;
}
newbot = bot + size; /* value of bot after swap */
if (bot == mid) /* top <-> mid, mid == top */
replace = mid = top;
else { /* bot <-> top */
replace = top;
top -= size;
}
goto swap;
}
if (bot == mid)
break;
/* bot <-> mid, mid == bot */
replace = mid;
newbot = mid = bot; /* value of bot after swap */
top -= size;
swap: SWAP(bot, replace);
bot = newbot;
didswap = 1;
}
/*
* Quicksort behaves badly in the presence of data which is already
* sorted (see Knuth, Vol. 3, page 119) going from O N lg N to O N^2.
* To avoid this worst case behavior, if a re-partitioning occurs
* without swapping any elements, it is not further partitioned and
* is insert sorted. This wins big with almost sorted data sets and
* only loses if the data set is very strangely partitioned. A fix
* for those data sets would be to return prematurely if the insertion
* sort routine is forced to make an excessive number of swaps, and
* continue the partitioning.
*/
if (!didswap) {
insertion_sort(bsv, nmemb, size, compar);
return;
}
/*
* Re-partition or sort as necessary. Note that the mid element
* itself is correctly positioned and can be ignored.
*/
#define nlower n1
#define nupper n2
bot = bsv;
nlower = (mid - bot) / size; /* size of lower partition */
mid += size;
nupper = nmemb - nlower - 1; /* size of upper partition */
/*
* If must call recursively, do it on the smaller partition; this
* bounds the stack to lg N entries.
*/
if (nlower > nupper) {
if (nupper >= THRESH)
quick_sort(mid, nupper, size, compar);
else {
SORT(mid, nupper);
if (nlower < THRESH) {
SORT(bot, nlower);
return;
}
}
nmemb = nlower;
} else {
if (nlower >= THRESH)
quick_sort(bot, nlower, size, compar);
else {
SORT(bot, nlower);
if (nupper < THRESH) {
SORT(mid, nupper);
return;
}
}
bot = mid;
nmemb = nupper;
}
goto partition;
}
static void
insertion_sort(char* bot, int nmemb, int size, int (*compar)())
{
register int cnt;
register u_char ch;
register char *s1, *s2, *t1, *t2, *top;
/*
* A simple insertion sort (see Knuth, Vol. 3, page 81, Algorithm
* S). Insertion sort has the same worst case as most simple sorts
* (O N^2). It gets used here because it is (O N) in the case of
* sorted data.
*/
top = bot + nmemb * size;
for (t1 = bot + size; t1 < top;) {
for (t2 = t1; (t2 -= size) >= bot && compar(t1, t2) < 0;);
if (t1 != (t2 += size)) {
/* Bubble bytes up through each element. */
for (cnt = size; cnt--; ++t1) {
ch = *t1;
for (s1 = s2 = t1; (s2 -= size) >= t2; s1 = s2)
*s1 = *s2;
*s1 = ch;
}
} else
t1 += size;
}
}

24
src/backend/lib/qsort.h Normal file
View File

@ -0,0 +1,24 @@
/*-------------------------------------------------------------------------
*
* qsort.h--
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: qsort.h,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef QSORT_H
#define QSORT_H
#include <sys/types.h>
extern void pg_qsort(void *bot,
size_t nmemb,
size_t size,
int (*compar)(void *, void *));
#endif /* QSORT_H */

View File

@ -0,0 +1,116 @@
/*-------------------------------------------------------------------------
*
* stringinfo.c--
* These are routines that can be used to write informations to a string,
* without having to worry about string lengths, space allocation etc.
* Ideally the interface should look like the file i/o interface,
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/stringinfo.c,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "nodes/pg_list.h"
#include "lib/stringinfo.h"
#include "utils/elog.h"
#include "utils/palloc.h"
/*---------------------------------------------------------------------
* makeStringInfo
*
* Create a StringInfoData & return a pointer to it.
*
*---------------------------------------------------------------------
*/
StringInfo
makeStringInfo()
{
StringInfo res;
long size;
res = (StringInfo) palloc(sizeof(StringInfoData));
if (res == NULL) {
elog(WARN, "makeStringInfo: Out of memory!");
}
size = 100;
res->data = palloc(size);
if (res->data == NULL) {
elog(WARN,
"makeStringInfo: Out of memory! (%ld bytes requested)", size);
}
res->maxlen = size;
res->len = 0;
/*
* NOTE: we must initialize `res->data' to the empty string because
* we use 'strcat' in 'appendStringInfo', which of course it always
* expects a null terminated string.
*/
res->data[0] = '\0';
return(res);
}
/*---------------------------------------------------------------------
* appendStringInfo
*
* append to the current 'StringInfo' a new string.
* If there is not enough space in the current 'data', then reallocate
* some more...
*
* NOTE: if we reallocate space, we pfree the old one!
*---------------------------------------------------------------------
*/
void
appendStringInfo(StringInfo str, char *buffer)
{
int buflen, newlen;
char *s;
Assert((str!=NULL));
/*
* do we have enough space to append the new string?
* (don't forget to count the null string terminating char!)
* If no, then reallocate some more.
*/
buflen = strlen(buffer);
if (buflen + str->len >= str->maxlen-1) {
/*
* how much more space to allocate ?
* Let's say double the current space...
* However we must check if this is enough!
*/
newlen = 2 * str->len;
while (buflen + str->len >= newlen-1) {
newlen = 2 * newlen;
}
/*
* allocate enough space.
*/
s = palloc(newlen);
if (s==NULL) {
elog(WARN,
"appendStringInfo: Out of memory (%d bytes requested)",
newlen);
}
memmove(s, str->data, str->len+1);
pfree(str->data);
str->maxlen = newlen;
str->data = s;
}
/*
* OK, we have enough space now, append 'buffer' at the
* end of the string & update the string length.
* NOTE: this is a text string (i.e. printable characters)
* so 'strcat' will do the job (no need to use 'bcopy' et all...)
*/
(void) strcat(str->data, buffer);
str->len += buflen;
}

View File

@ -0,0 +1,47 @@
/*-------------------------------------------------------------------------
*
* stringinfo.h--
* Declarations/definitons for "string" functions.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: stringinfo.h,v 1.1.1.1 1996/07/09 06:21:29 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef STRINGINFO_H
#define STRINGINFO_H
/*#include "c.h" */ /* for 'String' */
/*-------------------------
* StringInfoData holds information about a string.
* 'data' is the string.
* 'len' is the current string length (as returned by 'strlen')
* 'maxlen' is the size in bytes of 'data', i.e. the maximum string
* size (includeing the terminating '\0' char) that we can
* currently store in 'data' without having to reallocate
* more space.
*/
typedef struct StringInfoData {
char *data;
int maxlen;
int len;
} StringInfoData;
typedef StringInfoData *StringInfo;
/*------------------------
* makeStringInfo
* create a 'StringInfoData' & return a pointer to it.
*/
extern StringInfo makeStringInfo(void);
/*------------------------
* appendStringInfo
* similar to 'strcat' but reallocates more space if necessary...
*/
extern void appendStringInfo(StringInfo str, char *buffer);
#endif /* STRINGINFO_H */