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
134
135
136
137
138
139
140
141
142
143
|
using VQDR.Expression;
using Vee;
public class VQDR.Expression.RollAndKeepFunctionToken : FunctionToken {
private const int32 INDEX_ROLL = 1;
private const int32 INDEX_POOL = 1;
private const int32 INDEX_KEEP = 2;
private const int32 MAX_POOL_SIZE = 50;
private int64[] roll_values = null; // = new long[MAX_POOL_SIZE];
private bool[] valid_values = null; // = new bool[MAX_POOL_SIZE];
construct {
mandatory_num_child = 2;
optional_num_child = 1;
}
protected override void evaluate_self (VQDR.Expression.Context instance) throws GLib.Error {
Token? roll;
int64 pool_size;
int64 keep_size;
roll = get_child (INDEX_ROLL);
try {
get_child (INDEX_POOL).evaluate (instance);
} catch (Error e) {
stderr.printf ("Error: %s, Error Domain: %s\n",
e.message, e.domain.to_string ());
GLib.assert_not_reached ();
}
pool_size = get_child (INDEX_POOL).result_value.to_int ();
if (pool_size > MAX_POOL_SIZE) {
throw new ParamError.OUT_OF_BOUNDS
(@"($(get_function_name (this.get_type ()))) Max value $MAX_POOL_SIZE, got $pool_size");
}
if (pool_size < 0) {
pool_size = 0;
}
{
Token? keep_child = get_child (INDEX_KEEP);
if (keep_child != null) {
keep_child.evaluate (instance);
keep_size = keep_child.result_value.to_int ();
} else {
keep_size = pool_size;
}
}
if (keep_size > pool_size) {
keep_size = pool_size;
}
/* */
int64 roll_result;
int64 min_keep = int64.MAX;
int32 min_keep_index = 0;
if (roll_values == null || roll_values.length < pool_size) {
roll_values = new int64[pool_size];
valid_values = new bool[pool_size];
}
for (int32 i = 0; i < pool_size; i++) {
roll.evaluate (instance);
roll_result = roll.result_value.raw_number;
roll_values[i] = roll_result;
valid_values[i] = true;
if (i < keep_size) {
// simply keep and detect the minium kept value
if (min_keep > roll_result) {
min_keep = roll_result;
min_keep_index = i;
}
} else {
// Chose what to do.
if (roll_result >= min_keep) {
// Discard the Minimum value
valid_values[min_keep_index] = false;
// Search for new Minimum value
min_keep = int64.MAX;
min_keep_index = 0;
for (int32 j = 0; j <= i; j++) {
if (valid_values[j]) {
if (min_keep > roll_values[j]) {
min_keep = roll_values[j];
min_keep_index = j;
}
}
}
} else {
valid_values[i] = false;
}
}
} // end for loop
StringBuilder strbldr = new StringBuilder ();
strbldr.append (SYM_BEGIN);
FastNumber tmp_fstnmbr;
for (int32 i = 0; i < pool_size; i++) {
if (strbldr.len < MAX_TOKEN_STRING_LENGTH) {
//we don't start with a seperator mark.
if (i > 0) {
strbldr.append (SYM_SEP);
}
// We don't want to deal with the conertion directly.
// FIXME: Convert everything to FastNumbers instead of using "raw" values?
tmp_fstnmbr = FastNumber.raw (roll_values[i]);
strbldr.append (tmp_fstnmbr.to_string ());
if (valid_values[i] && keep_size != pool_size) {
strbldr.append (SYM_SELECTED);
}
}
if (valid_values[i]) {
tmp_fstnmbr = FastNumber.raw (roll_values[i]);
result_value.add (tmp_fstnmbr);
}
}
result_max_value = roll.result_max_value.multiply (FastNumber(keep_size));
result_min_value = roll.result_min_value.multiply (FastNumber(keep_size));
if (strbldr.len < MAX_TOKEN_STRING_LENGTH) {
strbldr.append (SYM_END);
result_string = strbldr.str;
} else {
result_string = SYM_TRUNK_BEGIN + result_value.to_string () + SYM_TRUNK_END;
}
}
}
/* vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab */
|