home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////
- // Copyright 1991, 1992 MetaWare Incorporated. All rights reserved. //
- ///////////////////////////////////////////////////////////////////////
- // new/delete and array new/delete for C++.
-
- #define DEBUG 0
- #include <stdlib.h>
-
- // Array init initializes an array and, if required, allocates it
- // as well. The allocation occurs only as a request from "new".
- // Correspondingly a "delete" request may come for that same array.
- // For an array allocation we allocate the array and possibly some extra
- // space. The extra space stores the array count and is needed in certain
- // circumstances.
-
- // Here is how the size is stored:
- // If the array alignment is 4 bytes or less and the number of elements
- // is <= 65536:
- // struct {
- // ushort nelts;
- // ushort magic; // 0xabcd
- // char user_array[];
- // };
- // If the array alignment is > 4 bytes or the # elements is > 65536:
- // struct {
- // ulong nelts; // # elements
- // short how_much_pad; // # how much padding above user array?
- // short magic; // 0xabce
- // char user_array[];
- // }
- // Thus, for the typical case we use only 4 bytes. For non-typical case
- // we use 8 (for <= 8 align) and 16 (for <= 16 align). Such severe
- // alignments are relevant only for machines for which alignemnt is
- // enforced, such as 860 or sun4.
- // A simpler scheme would have been to put elemcount*2 in the preceding
- // word, and if there was more space than 4 bytes, or in bit 1 in that
- // word. This doesn't work as well on the 286 and also we don't get
- // the checking with the magic number.
-
- #define AL 1 // Define 0 if you don't want it.
- #if _I386 || _I286
- #define MAXALIGN 4
- #elif _I860
- #define MAXALIGN 16
- #else
- #define MAXALIGN 8
- #endif
- static const int magic_meaning_4_bytes = 0xabcd,
- magic_meaning_more = 0xabce;
-
- // We used to pass "as_base", but arrays are always constructed at
- // the top, so that's not necessary.
- // Format of mode:
- // mode << 8 = alignment (1,2,4,8,16,32)
- // mode & 1 = please store the count; the class type has destructors
- // and so we'll be calling array_dest later.
- // mode & 2 = please call passed function. We need this because 0
- // may in fact be a valid function address!
- // mode & 4 = please deallocate this storage when done. Should
- // be set only when the count was stored.
- enum {ARRAY_STORE_SIZE=1, ARRAY_CALL_FUNC=2, ARRAY_DEALLOCATE=4,};
- #define ALIGN_OF(x) ((x)>>8)
-
- typedef unsigned short ushort;
-
- extern "C" void *__array_init(char *base,
- unsigned elemcount, int elemsize, void (*f)(char *,int),
- unsigned mode) {
- unsigned extra_space = 0;
- if (mode & ARRAY_STORE_SIZE) {
- unsigned alignment = ALIGN_OF(mode);
- extra_space = _max(4,_min(MAXALIGN,alignment));
- if (elemcount > 65535) extra_space = _max(extra_space,8);
- }
- // If the pointer is 0, allocate it as well.
- // ARRAY_STORE_SIZE should not be requested for a non-newed array,
- // so that extra space will be 0 for such.
- if (base == 0) base = new char[elemcount*elemsize+extra_space];
- if (extra_space) {
- base += extra_space;
- ushort *q = (ushort*)base;
- if (extra_space == 4) {
- q[-1] = magic_meaning_4_bytes;
- q[-2] = elemcount;
- }
- else {
- q[-1] = magic_meaning_more;
- q[-2] = extra_space;
- long *p = (long*)base;
- p[-2] = elemcount;
- }
- }
- char *p = base;
- if (DEBUG) printf("array_init(%x,%d,%d,%x,%d,%d)\n",
- base,elemcount,elemsize,f,mode,extra_space);
- // Sorry, we may be given an address of 0 because the constructor
- // is the first thing in the program executable! Anyway, the compiler
- // always guarantees a valid procedure.
- if ((mode & ARRAY_CALL_FUNC) && base) {
- for (int i = 0; i < elemcount; i++) {
- if (DEBUG) printf("init %p elemsize=%d\n",p,elemsize);
- f(p,0), p+=elemsize;
- }
- }
- return base;
- }
-
- extern "C" void *__array_dest(char *base,
- unsigned elemcount, int elemsize, void (*f)(char *, int),
- unsigned mode) {
- if (DEBUG) printf("array_dest(%x,%d,%d,%x,%d)\n",
- base,elemcount,elemsize,f,mode);
- unsigned extra_space = 0;
- if (mode & ARRAY_STORE_SIZE) {
- ushort *q = (ushort*)base;
- if (q[-1] == magic_meaning_4_bytes) {
- extra_space = 4;
- elemcount = q[-2];
- }
- else if (q[-2] == magic_meaning_more) {
- extra_space = q[-2];
- long *p = (long*)base;
- elemcount = p[-2];
- }
- else {
- printf("Array deletion: non-array or corrupted array passed.\n");
- exit(1);
- }
- }
- char *p = ((char *)base)+elemsize*elemcount;
- if (mode & ARRAY_CALL_FUNC)
- for (int i = 0; i < elemcount; i++) {
- if (DEBUG) printf("dest %p elemsize=%d\n",p,elemsize);
- p-=elemsize, f(p,0);
- }
- if (mode & ARRAY_DEALLOCATE) free(base-extra_space), base = 0;
- return base;
- }
-