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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
/// @file
#include "jets/k.h"
#include "jets/q.h"
#include "jets/w.h"
#include "noun.h"
/*
Get the lowest `n` bits of a word `w` using a bitmask.
*/
#define TAKEBITS(n,w) \
((n)==32) ? (w) : \
((n)==0) ? 0 : \
((w) & ((1 << (n)) - 1))
/*
Divide, rounding up.
*/
#define DIVCEIL(x,y) \
(x==0) ? 0 : \
1 + ((x - 1) / y);
/*
`ripn` breaks `atom` into a list of blocks, of bit-width `bits`. The
resulting list will be least-significant block first.
XX TODO This only handles cases where the bit-width is <= 32.
For each block we produce, we need to grab the relevant words inside
`atom`, so we first compute their indicies.
`ins_idx` is the word-index of the least-significant word we
care about, and `sig_idx` is the word after that.
Next we grab those words (`ins_word` and `sig_word`) from the atom
using `u3r_word`. Note that `sig_idx` might be out-of-bounds for the
underlying array of `atom`, but `u3r_word` returns 0 in that case,
which is exatly what we want.
Now, we need to grab the relevant bits out of both words, and combine
them. `bits_rem_in_ins_word` is the number of remaining (insignificant)
bits in `ins_word`, `nbits_ins` is the number of bits we want from the
less-significant word, and `nbits_sig` from the more-significant one.
Take the least significant `nbits_sig` bits from `sig_word`, and take
the slice we care about from `ins_word`. In order to take that slice,
we drop `bits_rem_in_ins_word` insignificant bits, and then take the
`nbits_sig` most-significant bits.
Last, we slice out those bits from the two words, combine them into
one word, and cons them onto the front of the result.
*/
static u3_noun
_bit_rip(u3_atom bits, u3_atom atom)
{
if ( !_(u3a_is_cat(bits) || bits==0 || bits>31) ) {
return u3m_bail(c3__fail);
}
c3_w bit_width = u3r_met(0, atom);
c3_w num_blocks = DIVCEIL(bit_width, bits);
u3_noun res = u3_nul;
for ( c3_w blk = 0; blk < num_blocks; blk++ ) {
c3_w next_blk = blk + 1;
c3_w blks_rem = num_blocks - next_blk;
c3_w bits_rem = blks_rem * bits;
c3_w ins_idx = bits_rem / 32;
c3_w sig_idx = ins_idx + 1;
c3_w bits_rem_in_ins_word = bits_rem % 32;
c3_w ins_word = u3r_word(ins_idx, atom);
c3_w sig_word = u3r_word(sig_idx, atom);
c3_w nbits_ins = c3_min(bits, 32 - bits_rem_in_ins_word);
c3_w nbits_sig = bits - nbits_ins;
c3_w ins_word_bits = TAKEBITS(nbits_ins, ins_word >> bits_rem_in_ins_word);
c3_w sig_word_bits = TAKEBITS(nbits_sig, sig_word);
c3_w item = ins_word_bits | (sig_word_bits << nbits_ins);
res = u3nc(item, res);
}
return res;
}
static u3_noun
_block_rip(u3_atom bloq, u3_atom b)
{
if ( !_(u3a_is_cat(bloq)) || (bloq >= 32) ) {
return u3m_bail(c3__fail);
}
c3_g bloq_g = bloq;
/*
This is a fast-path for the case where all the resulting blocks will
fit in 31-bit direct atoms.
*/
if ( bloq_g < 5 ) { // produce direct atoms
u3_noun acc = u3_nul;
c3_w met_w = u3r_met(bloq_g, b); // num blocks in atom
c3_w nbits_w = 1 << bloq_g; // block size in bits
c3_w bmask_w = (1 << nbits_w) - 1; // result mask
for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { // `i_w` is block index
c3_w nex_w = i_w + 1; // next block
c3_w pat_w = met_w - nex_w; // blks left after this
c3_w bit_w = pat_w << bloq_g; // bits left after this
c3_w wor_w = bit_w >> 5; // wrds left after this
c3_w sif_w = bit_w & 31; // bits left in word
c3_w src_w = u3r_word(wor_w, b); // find word by index
c3_w rip_w = (src_w >> sif_w) & bmask_w; // get item from word
acc = u3nc(rip_w, acc);
}
return acc;
}
u3_noun acc = u3_nul;
c3_w met_w = u3r_met(bloq_g, b);
c3_w len_w = u3r_met(5, b);
c3_g san_g = (bloq_g - 5);
c3_w san_w = 1 << san_g;
c3_w dif_w = (met_w << san_g) - len_w;
c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w));
for ( c3_w i_w = 0; i_w < met_w; i_w++ ) {
c3_w pat_w = (met_w - (i_w + 1));
c3_w wut_w = (pat_w << san_g);
c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
c3_w j_w;
u3_atom rip;
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 5, sap_w);
for ( j_w = 0; j_w < sap_w; j_w++ ) {
sab_u.buf_w[j_w] = u3r_word(wut_w + j_w, b);
}
rip = u3i_slab_mint(&sab_u);
acc = u3nc(rip, acc);
len_w -= san_w;
}
return acc;
}
u3_noun
u3qc_rip(u3_atom a,
u3_atom b,
u3_atom c)
{
if ( 1 == b ) {
return _block_rip(a, c);
}
if ( 0 == a ) {
return _bit_rip(b, c);
}
u3l_log("rip: stub");
return u3_none;
}
u3_noun
u3wc_rip(u3_noun cor)
{
u3_atom bloq, step;
u3_noun a, b;
u3x_mean(cor, u3x_sam_2, &a,
u3x_sam_3, &b, 0);
u3x_bite(a, &bloq, &step);
return u3qc_rip(bloq, step, u3x_atom(b));
}
u3_noun
u3kc_rip(u3_atom a,
u3_atom b,
u3_atom c)
{
u3_noun pro = u3qc_rip(a, b, c);
u3z(a); u3z(b); u3z(c);
return pro;
}
|