diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/lib | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/lib')
-rw-r--r-- | src/backend/lib/Makefile.inc | 20 | ||||
-rw-r--r-- | src/backend/lib/bit.c | 45 | ||||
-rw-r--r-- | src/backend/lib/dllist.c | 204 | ||||
-rw-r--r-- | src/backend/lib/dllist.h | 72 | ||||
-rw-r--r-- | src/backend/lib/fstack.c | 153 | ||||
-rw-r--r-- | src/backend/lib/fstack.h | 113 | ||||
-rw-r--r-- | src/backend/lib/hasht.c | 47 | ||||
-rw-r--r-- | src/backend/lib/hasht.h | 23 | ||||
-rw-r--r-- | src/backend/lib/lispsort.c | 56 | ||||
-rw-r--r-- | src/backend/lib/lispsort.h | 18 | ||||
-rw-r--r-- | src/backend/lib/qsort.c | 281 | ||||
-rw-r--r-- | src/backend/lib/qsort.h | 24 | ||||
-rw-r--r-- | src/backend/lib/stringinfo.c | 116 | ||||
-rw-r--r-- | src/backend/lib/stringinfo.h | 47 |
14 files changed, 1219 insertions, 0 deletions
diff --git a/src/backend/lib/Makefile.inc b/src/backend/lib/Makefile.inc new file mode 100644 index 00000000000..c3a46d546ce --- /dev/null +++ b/src/backend/lib/Makefile.inc @@ -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 + diff --git a/src/backend/lib/bit.c b/src/backend/lib/bit.c new file mode 100644 index 00000000000..9aa12b48502 --- /dev/null +++ b/src/backend/lib/bit.c @@ -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) ); +} + diff --git a/src/backend/lib/dllist.c b/src/backend/lib/dllist.c new file mode 100644 index 00000000000..92526632c9f --- /dev/null +++ b/src/backend/lib/dllist.c @@ -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; +} + diff --git a/src/backend/lib/dllist.h b/src/backend/lib/dllist.h new file mode 100644 index 00000000000..cd9ac42a12f --- /dev/null +++ b/src/backend/lib/dllist.h @@ -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 */ diff --git a/src/backend/lib/fstack.c b/src/backend/lib/fstack.c new file mode 100644 index 00000000000..541767183d8 --- /dev/null +++ b/src/backend/lib/fstack.c @@ -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)); +} diff --git a/src/backend/lib/fstack.h b/src/backend/lib/fstack.h new file mode 100644 index 00000000000..b0b1df00d83 --- /dev/null +++ b/src/backend/lib/fstack.h @@ -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 */ diff --git a/src/backend/lib/hasht.c b/src/backend/lib/hasht.c new file mode 100644 index 00000000000..5487bed44bc --- /dev/null +++ b/src/backend/lib/hasht.c @@ -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); + } +} diff --git a/src/backend/lib/hasht.h b/src/backend/lib/hasht.h new file mode 100644 index 00000000000..543c8c95d84 --- /dev/null +++ b/src/backend/lib/hasht.h @@ -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 */ diff --git a/src/backend/lib/lispsort.c b/src/backend/lib/lispsort.c new file mode 100644 index 00000000000..0cf49bf0c0b --- /dev/null +++ b/src/backend/lib/lispsort.c @@ -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); +} diff --git a/src/backend/lib/lispsort.h b/src/backend/lib/lispsort.h new file mode 100644 index 00000000000..e49ee543622 --- /dev/null +++ b/src/backend/lib/lispsort.h @@ -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 */ diff --git a/src/backend/lib/qsort.c b/src/backend/lib/qsort.c new file mode 100644 index 00000000000..5af64bf8006 --- /dev/null +++ b/src/backend/lib/qsort.c @@ -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; + } +} diff --git a/src/backend/lib/qsort.h b/src/backend/lib/qsort.h new file mode 100644 index 00000000000..d81d4e2e070 --- /dev/null +++ b/src/backend/lib/qsort.h @@ -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 */ + diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c new file mode 100644 index 00000000000..7167ffcf65c --- /dev/null +++ b/src/backend/lib/stringinfo.c @@ -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; +} diff --git a/src/backend/lib/stringinfo.h b/src/backend/lib/stringinfo.h new file mode 100644 index 00000000000..717f2ad5985 --- /dev/null +++ b/src/backend/lib/stringinfo.h @@ -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 */ |