/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* 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
syntax highlighted by Code2HTML, v. 0.9.1