summaryrefslogtreecommitdiffstats
path: root/src/util/t_enum.pm
blob: e62bfce5a8314e1d25152b45644cdbf76fc72fe6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package t_enum;

use strict;
use vars qw(@ISA);

#require ktemplate;
require t_template;
require t_array;

@ISA=qw(t_template);

my @parms = qw(NAME TYPE COMPARE);
my %defaults = ( );
my @templatelines = <DATA>;

sub new { # no args
    my $self = {};
    bless $self;
    $self->init(\@parms, \%defaults, \@templatelines);
    return $self;
}

sub output {
    my ($self, $fh) = @_;
    my $a = new t_array;
    $a->setparm("NAME", $self->{values}{"NAME"} . "__enumerator_array");
    $a->setparm("TYPE", $self->{values}{"TYPE"});
    $a->output($fh);
    $self->SUPER::output($fh);
}

1;

__DATA__

/*
 * an enumerated collection type, generated from template
 *
 * Methods:
 * int init() -> returns nonzero on alloc failure
 * long size()
 * long find(match) -> -1 or index of any match
 * long append(value) -> -1 or new index
 * <TYPE> get(index) -> aborts if out of range
 * void destroy() -> frees array data
 *
 * Errors adding elements don't distinguish between "out of memory"
 * and "too big for size_t".
 *
 * Initial implementation: A flat array, reallocated as needed.  Our
 * uses probably aren't going to get very large.
 */

struct <NAME>__enumerator {
    <NAME>__enumerator_array a;
    size_t used;       /* number of entries used, idx used-1 is last */
};
typedef struct <NAME>__enumerator <NAME>;

static inline int
<NAME>_init(<NAME> *en)
{
    en->used = 0;
    return <NAME>__enumerator_array_init(&en->a);
}

static inline long
<NAME>_size(<NAME> *en)
{
    return en->used;
}

static inline long
<NAME>__s2l(size_t idx)
{
    long l;
    if (idx > LONG_MAX)
	abort();
    l = idx;
    if (l != idx)
	abort();
    return l;
}

static inline long
<NAME>_find(<NAME> *en, <TYPE> value)
{
    size_t i;
    for (i = 0; i < en->used; i++) {
	if (<COMPARE> (value, <NAME>__enumerator_array_get(&en->a, <NAME>__s2l(i))) == 0)
	    return i;
    }
    return -1;
}

static inline long
<NAME>_append(<NAME> *en, <TYPE> value)
{
    if (en->used >= LONG_MAX - 1)
	return -1;
    if (en->used >= SIZE_MAX - 1)
	return -1;
    if (<NAME>__enumerator_array_size(&en->a) == en->used) {
	if (<NAME>__enumerator_array_grow(&en->a, en->used + 1) < 0)
	    return -1;
    }
    <NAME>__enumerator_array_set(&en->a, <NAME>__s2l(en->used), value);
    en->used++;
    return en->used-1;
}

static inline <TYPE>
<NAME>_get(<NAME> *en, size_t idx)
{
    return <NAME>__enumerator_array_get(&en->a, <NAME>__s2l(idx));
}

static inline void
<NAME>_destroy(<NAME> *en)
{
    <NAME>__enumerator_array_destroy(&en->a);
    en->used = 0;
}

static inline void
<NAME>_foreach(<NAME> *en, int (*fn)(size_t i, <TYPE> t, void *p), void *p)
{
    size_t i;
    for (i = 0; i < en->used; i++) {
	if (fn (i, <NAME>__enumerator_array_get(&en->a, <NAME>__s2l(i)), p) != 0)
	    break;
    }
}