/* tag: Tom Lord Tue Dec 4 14:41:51 2001 (pow2-array-print.c)
*/
/* pow2-array-print.c -
*
****************************************************************
* Copyright (C) 2000 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/bugs/panic.h"
#include "hackerlab/mem/alloc-limits.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/hash/hashtree.h"
#include "hackerlab/hash/hash-utils.h"
#include "hackerlab/arrays/ar.h"
#include "hackerlab/arrays/pow2-array-print.h"
/************************************************************************
*(h2 "Generating C Code for a Sparse Array")
*
*
*
*/
static void
pow2_array_print_node (int fd,
struct hashtree * table,
t_uchar * name,
void * node,
void ** default_tree_nodes,
t_uchar ** default_tree_names,
struct pow2_array_level_rule * level,
size_t elt_size,
t_uchar * elt_type,
void (*print_elt_initializer) (int fd, void * elt))
{
if (!node)
{
safe_printfmt (fd, "#define %s 0\n\n", name);
return;
}
else if (default_tree_nodes && (*default_tree_nodes == node))
{
safe_printfmt (fd, "#define %s %s\n\n", name, *default_tree_names);
return;
}
if (table)
{
struct hashtree_item * item;
item = hashtree_store (table, hash_ul ((unsigned long)node), node, 0);
if (item->binding)
{
safe_printfmt (fd, "#define %s %s\n\n", name, (t_uchar *)item->binding);
return;
}
else
{
item->binding = (void *)str_save (lim_use_must_malloc, name);
}
}
if (!level->addr_shift)
{
size_t n_elts;
size_t x;
safe_printfmt (fd, "static %s %s[] =\n", elt_type, name);
safe_printfmt (fd, "{");
n_elts = level->addr_mask + 1;
for (x = 0; x < n_elts; ++x)
{
print_elt_initializer (fd, (void *)((t_uchar *)node + elt_size * x));
safe_printfmt (fd, ",\n");
}
safe_printfmt (fd, "};\n\n");
}
else
{
size_t n_elts;
size_t x;
t_uchar * page_name;
t_uchar page_suffix[100];
n_elts = level->addr_mask + 1;
page_suffix[0] = '_';
for (x = 0; x < n_elts; ++x)
{
cvt_ulong_to_decimal (page_suffix + 1, (t_ulong)x);
page_name = str_alloc_cat (lim_use_must_malloc, name, page_suffix);
pow2_array_print_node (fd,
table,
page_name,
((void **)node)[x],
(default_tree_nodes ? (default_tree_nodes + 1) : 0),
(default_tree_names ? (default_tree_names + 1) : 0),
level + 1,
elt_size,
elt_type,
print_elt_initializer);
lim_free (lim_use_must_malloc, (void *)page_name);
}
safe_printfmt (fd, "static void * %s[] =\n", name);
safe_printfmt (fd, "{");
for (x = 0; x < n_elts; ++x)
{
cvt_ulong_to_decimal (page_suffix + 1, (t_ulong)x);
page_name = str_alloc_cat (lim_use_must_malloc, name, page_suffix);
safe_printfmt (fd, " (void *)%s,\n", page_name);
lim_free (lim_use_must_malloc, (void *)page_name);
}
safe_printfmt (fd, "};\n\n");
}
}
static void
pow2_array_print_default_node (int fd,
t_uchar * name,
t_uchar * subtree_name,
struct pow2_array_level_rule * level)
{
size_t elts;
size_t x;
elts = level->addr_mask + 1;
safe_printfmt (fd, "static void * %s[] =\n", name);
safe_printfmt (fd, "{\n");
for (x = 0; x < elts; ++x)
safe_printfmt (fd, " (void *)%s,\n", subtree_name);
safe_printfmt (fd, "};\n\n");
}
static void
pow2_array_rules_print (t_uchar *** default_tree_names_p,
int fd,
t_uchar * name,
struct pow2_array_rules * rules,
t_uchar * elt_type,
void (*print_elt_initializer) (int fd, void * elt))
{
t_uchar * levels_name;
t_uchar * defaults_name;
t_converter default_tree_names;
t_uchar * default_page_name;
levels_name = 0;
defaults_name = 0,
default_tree_names.uchar_ptr_ptr = 0;
default_page_name = 0;
if (!rules->defaults)
defaults_name = str_save (lim_use_must_malloc, "0");
else
{
int level;
for (level = 0; rules->levels[level].addr_shift; ++level)
;
default_page_name = str_alloc_cat (lim_use_must_malloc, name, "_dflt_page");
pow2_array_print_node (fd, 0, default_page_name, rules->defaults[level], 0, 0, rules->levels + level, rules->elt_size, elt_type, print_elt_initializer);
*(t_uchar **)ar_ref (&default_tree_names.void_ptr, level, sizeof (t_uchar *))
= str_save (lim_use_must_malloc, default_page_name);
while (level--)
{
static t_uchar suffix[100];
static t_uchar number[100];
cvt_long_to_decimal (number, (long)level);
str_cpy (suffix, "_dflt_");
str_cat (suffix, number);
default_tree_names.uchar_ptr_ptr[level] = str_alloc_cat (lim_use_must_malloc, name, suffix);
pow2_array_print_default_node (fd, default_tree_names.uchar_ptr_ptr[level], default_tree_names.uchar_ptr_ptr[level + 1], rules->levels + level);
}
defaults_name = str_alloc_cat (lim_use_must_malloc, name, "_defaults");
safe_printfmt (fd, "static void * %s[] =\n", defaults_name);
safe_printfmt (fd, "{\n");
{
int x;
x = 0;
while (1)
{
safe_printfmt (fd, " (void *)%s,\n", default_tree_names.uchar_ptr_ptr[x]);
if (!rules->levels[x].addr_shift)
break;
++x;
}
}
safe_printfmt (fd, "};\n\n");
}
{
int x;
levels_name = str_alloc_cat (lim_use_must_malloc, name, "_levels");
safe_printfmt (fd, "static struct pow2_array_level_rule %s[] =\n", levels_name);
safe_printfmt (fd, "{\n");
x = 0;
while (1)
{
safe_printfmt (fd, " { %d, 0x%lx },\n", rules->levels[x].addr_shift, (t_ulong)rules->levels[x].addr_mask);
if (!rules->levels[x].addr_shift)
break;
++x;
}
safe_printfmt (fd, "};\n\n");
}
safe_printfmt (fd, "static struct pow2_array_rules %s =\n", name);
safe_printfmt (fd, "{\n");
safe_printfmt (fd, " %s,\n", defaults_name);
safe_printfmt (fd, " %s,\n", levels_name);
safe_printfmt (fd, " %lu,\n", (t_ulong)rules->elt_size);
safe_printfmt (fd, "};\n\n");
lim_free (lim_use_must_malloc, levels_name);
lim_free (lim_use_must_malloc, defaults_name);
lim_free (lim_use_must_malloc, default_page_name);
*default_tree_names_p = default_tree_names.uchar_ptr_ptr;
}
static void
pow2_array_print_macro_exp (int fd, pow2_array array, int level)
{
if (!level)
{
safe_printfmt (fd, "((void **)(ARRAY)->root)");
}
else
{
safe_printfmt (fd, "((void **)(");
pow2_array_print_macro_exp (fd, array, level - 1);
safe_printfmt (fd, "[((INDEX) >> %d) & 0x%lx]))", array->rules->levels[level - 1].addr_shift, (t_ulong)array->rules->levels[level - 1].addr_mask);
}
}
static void
free_item (struct hashtree_item * it, struct hashtree_rules * ign)
{
lim_free (lim_use_must_malloc, it->binding);
}
/*(c pow2_array_print)
* void pow2_array_print (int fd,
* struct pow2_array * array,
* t_uchar * name,
* t_uchar * stub,
* int decls_only,
* t_uchar * ref_macro_name,
* int is_static,
* t_uchar * elt_type,
* void (*print_elt_initializer) (int fd, void * elt));
*
* On descriptor `fd', print C code which compiles to a staticly initialized
* sparse array equal to `array'.
*
* `name' is the variable name to use.
*
* `stub' is a variable name prefix to use when printing internal
* data structures of `array'.
*
* `decls_only', if not 0, means to print only a declaration for the
* array -- not the static initializer.
*
* `ref_macro_name', if not 0, is a name for a CPP macro. The macro
* will be of the form:
*
* #define REF_MACRO(ARRAY, ELT) ((ELT_TYPE *)(....))
*
* The macro is a version of `pow2_array_rref', optimized for access to
* the staticly initialized array.
*
* `elt_type' is a type name for elements of the array.
*
* `print_elt_initializer' prints a static initializer for particular
* elements.
*
* This function exits by calling `panic' if an error occurs.
*/
void
pow2_array_print (int fd,
struct pow2_array * array,
t_uchar * name,
t_uchar * stub,
int decls_only,
t_uchar * ref_macro_name,
int is_static,
t_uchar * elt_type,
void (*print_elt_initializer) (int fd, void * elt))
{
struct hashtree * table;
t_uchar * rules_name;
t_uchar * root_name;
t_converter default_tree_names;
t_uchar * struct_name;
if (decls_only)
{
safe_printfmt (fd, "%s struct pow2_array * %s;\n", (is_static ? "static " : "extern "), name);
}
if (ref_macro_name)
{
int n_levels;
n_levels = 0;
for (n_levels = 0; array->rules->levels[n_levels].addr_shift; ++n_levels)
;
++n_levels;
if (!array->rules->defaults)
panic ("asked to print pow2_array ref macro for array without defaults");
safe_printfmt (fd, "#define %s(ARRAY, INDEX) (((%s *)", ref_macro_name, elt_type);
pow2_array_print_macro_exp (fd, array, n_levels - 1);
safe_printfmt (fd, ")[(INDEX) & 0x%lx])\n\n", (t_ulong)array->rules->levels[n_levels - 1].addr_mask);
}
if (decls_only)
return;
table = hashtree_alloc (0);
rules_name = str_alloc_cat (lim_use_must_malloc, stub, "_rules");
pow2_array_rules_print (&default_tree_names.uchar_ptr_ptr, fd, rules_name, array->rules, elt_type, print_elt_initializer);
root_name = str_alloc_cat (lim_use_must_malloc, stub, "_0");
pow2_array_print_node (fd, table, root_name, array->root, array->rules->defaults, default_tree_names.uchar_ptr_ptr, array->rules->levels, array->rules->elt_size, elt_type, print_elt_initializer);
struct_name = str_alloc_cat (lim_use_must_malloc, name, "_struct");
safe_printfmt (fd, "static struct pow2_array %s =\n", struct_name);
safe_printfmt (fd, "{\n");
safe_printfmt (fd, " lim_no_allocations,\n");
safe_printfmt (fd, " &%s,\n", rules_name);
safe_printfmt (fd, " (void *)%s\n", root_name);
safe_printfmt (fd, "};\n\n");
safe_printfmt (fd, "%spow2_array %s = &%s;\n", (is_static ? "static " : ""), name, struct_name);
safe_printfmt (fd, "\n\n");
lim_free (lim_use_must_malloc, (void *)rules_name);
lim_free (lim_use_must_malloc, (void *)root_name);
lim_free (lim_use_must_malloc, (void *)struct_name);
hashtree_free (table, free_item, 0);
{
int x;
x = (int)ar_size (default_tree_names.void_ptr);
while (x--)
{
lim_free (lim_use_must_malloc, default_tree_names.uchar_ptr_ptr[x]);
}
ar_free (&default_tree_names.void_ptr);
}
}
syntax highlighted by Code2HTML, v. 0.9.1