/* * Copyright (c) 2002, The Tendra Project * 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 unmodified, 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * * Crown Copyright (c) 1997 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/producers/common/c_class.c,v 1.7 2004/08/15 11:13:35 bp Exp $ */ #include "config.h" #include "producer.h" #include "fmm.h" #include "msgcat.h" #include "c_types.h" #include "error.h" /* * CHECK FOR CORRECT HEADERS * * The functions defined in this file give the implementations of various * support functions used by the c_class implementation. They should * therefore be compiled with the c_class implementation rather than the * specification. */ #if c_class_SPECIFICATION FAIL_COMPILER (Implementation functions compiled with token specifications) #endif /* * FREE OBJECTS * * These variables indicate the free c_classes. There is an array * containing lists of small blocks, plus a single larger block. */ #define SMALL_BLOCK 24 #define ALLOC_BLOCK 2048 #if (c_class_GEN_MAX > SMALL_BLOCK) FAIL_COMPILER (Free block array is too small) #endif static c_class *free_c_classes = NULL; static unsigned free_c_classes_left = 0; unsigned total_c_classes = 0; static c_class *free_c_class_array [ SMALL_BLOCK ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* * GENERATE A NEW OBJECT BLOCK * * This routine generates a new block of c_classes of size sz. Small * blocks are allocated from the c_class array, others from the main * c_class list. */ c_class *gen_c_class(unsigned sz) { c_class *p; unsigned n = sz; if (n < SMALL_BLOCK) { /* Allocate from small block array */ if (n == 0) return (NULL); p = free_c_class_array [n]; if (p) { free_c_class_array [n] = TAIL_list (p); return (p); } } if (n > free_c_classes_left) { /* Allocate new blocks */ unsigned m = ALLOC_BLOCK; if (n > m) m = n; free_c_classes = xmalloc_nof (c_class, m); free_c_classes_left = m; } p = free_c_classes; free_c_classes += n; free_c_classes_left -= n; return (p); } /* * MARK AN OBJECT AS FREE * * This routine is used in the object destruction routines to mark an * object as having been freed. This only has any effect in conjunction * with the debugging routine below. */ #ifdef RUNTIME #define clean_c_class(P, Z)\ {\ ASSERT (TYPEID (P) != TYPEID_free) ;\ TYPEID (P) = TYPEID_free ;\ total_c_classes -= (Z) ;\ } #else #define clean_c_class(P, Z) /* empty */ #endif /* * GENERATE A NEW OBJECT BLOCK (DEBUG VERSION) * * This routine is identical to gen_c_class except that it includes the * run-time type information t in the allocated block. */ #ifdef RUNTIME c_class *debug_c_class(unsigned sz, unsigned t) { c_class *p; unsigned n = sz; total_c_classes += n; if (n < SMALL_BLOCK) { /* Allocate from small block array */ if (n == 0) return (NULL); p = free_c_class_array [n]; if (p) { free_c_class_array [n] = TAIL_list (p); ASSERT (TYPEID (p) == TYPEID_free); TYPEID (p) = t; return (p); } } n += 1; if (n > free_c_classes_left) { /* Allocate new blocks */ unsigned m = ALLOC_BLOCK; if (n > m) m = n; free_c_classes = xmalloc_nof (c_class, m); free_c_classes_left = m; } p = free_c_classes + 1; TYPEID (p) = t; free_c_classes += n; free_c_classes_left -= n; return (p); } #endif /* RUNTIME */ /* * DESTROY AN OBJECT BLOCK * * This routine destroys the block of c_classes p of size sz. */ void destroy_c_class(c_class *p, unsigned sz) { if (p) { unsigned n = sz; c_class **r = free_c_class_array; if (n < SMALL_BLOCK) r += n; clean_c_class (p, n); TAIL_list (p) = *r; *r = p; } return; } /* * DUMMY OBJECT BLOCK DESTRUCTOR * * This routine is a dummy destructor which does nothing. */ void dummy_destroy_c_class(c_class *p, unsigned sz) { UNUSED (p); UNUSED (sz); return; } /* * DESTROY A LIST OF OBJECT BLOCKS * * This routine destroys the list p of blocks of c_classes of size sz. * The list is added to the appropriate entry of the free c_class array. */ void destroy_c_class_list(c_class *p, unsigned sz) { if (p) { c_class *q = p; unsigned n = sz + 1; c_class **r = free_c_class_array; if (n < SMALL_BLOCK) r += n; while (TAIL_list (p)) { clean_c_class (p, n); p = TAIL_list (p); } clean_c_class (p, n); TAIL_list (p) = *r; *r = q; } return; } /* * FIND THE LENGTH OF A LIST * * This routine calculates the length of the list p. */ unsigned length_c_class_list(c_class *p) { unsigned n = 0; c_class *q = p; while (q) { n++; q = TAIL_list (q); } return (n); } /* * REVERSE A LIST * * This routine reverses the order of the list p. */ c_class *reverse_c_class_list(c_class *p) { c_class *r = NULL; c_class *q = p; while (q) { c_class *nq = TAIL_list (q); TAIL_list (q) = r; r = q; q = nq; } return (r); } /* * APPEND TWO LISTS * * This routine appends the lists of c_class blocks p and q. */ c_class *append_c_class_list(c_class *p, c_class *q) { c_class *r = p; if (r == NULL) return (q); while (TAIL_list (r)) r = TAIL_list (r); TAIL_list (r) = q; return (p); } /* * FIND THE LAST MEMBER OF A LIST * * This routine returns the last member of the list of c_class blocks p. */ c_class *end_c_class_list(c_class *p) { c_class *r = p; if (r == NULL) return (NULL); while (TAIL_list (r)) r = TAIL_list (r); return (r); } /* * GENERIC EMPTY VECTOR * * This c_class represents the generic empty vector. It is only defined * if vector operations have been enabled. Note that the element field * of a vector is not be NULL, even if the vector is empty. */ #ifdef VEC static c_class dummy_elem; c_class_VEC empty_c_class_vec = { 0, { &dummy_elem, &dummy_elem } }; #endif #ifdef c_class_IO_ROUTINES /* * ALIASING VARIABLES * * These variables give respectively the current alias number and the * list of all aliases. */ unsigned crt_c_class_alias = 0; static c_class *crt_alias_list = NULL; /* * SET AN ALIAS * * This routine sets up an alias of p to n. */ void set_c_class_alias(c_class *p, unsigned n) { c_class *q = GEN_c_class (2, TYPEID_list); TAIL_list (q) = crt_alias_list; HEAD_list (q)->ag_ptr = p; ASSERT (p != NULL); p->ag_tag = n; crt_alias_list = q; return; } /* * FIND AN ALIAS * * This routine searches for alias number n. */ c_class *find_c_class_alias(unsigned n) { c_class *p = crt_alias_list; while (p) { c_class *q = HEAD_list (p)->ag_ptr; if (q->ag_tag == n) return (q); p = TAIL_list (p); } error (ERROR_INTERNAL, "Can't find alias %u", n); return (NULL); } /* * CLEAR ALL ALIASES * * This routine clears all aliases. Each alias in the list is reset to * zero, and the list itself is freed. */ void clear_c_class_alias() { c_class *p = crt_alias_list; c_class *q = NULL; while (p) { HEAD_list (p)->ag_ptr->ag_tag = 0; q = p; p = TAIL_list (p); } if (q) { TAIL_list (q) = free_c_class_array [2]; free_c_class_array [2] = crt_alias_list; } crt_c_class_alias = 0; crt_alias_list = NULL; return; } #endif /* c_class_IO_ROUTINES */ /* * ASSERTION ROUTINES * * These routine implement the assertion checks. */ #ifdef ASSERTS #define assert_c_class assertion #include "assert_def.h" #endif