-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrle-parse.h
158 lines (132 loc) · 3.32 KB
/
rle-parse.h
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
/*
RLE Parsing Utility Functions
Copyright (c) 2022, Eddy L O Jansson. Licensed under The MIT License.
TODO:
The parser is incomplete and not fully functional.
'goldbox' encoding is broken -- always uses REP due to min-rep==1
Add support for LIT.
See https://github.com/eloj/rle-zoo
*/
#ifdef __cplusplus
extern "C" {
#endif
// NOTE: The order and value of these matter.
enum RLE_OP {
RLE_OP_CPY,
RLE_OP_REP,
RLE_OP_LIT,
RLE_OP_NOP,
RLE_OP_INVALID,
};
struct rle8 {
enum RLE_OP op;
uint8_t cnt; // TODO: rename to 'arg'?
};
struct rle8_tbl {
const char *name;
enum RLE_OP op_used;
const int16_t *encode_tbl[3];
const struct rle8 *decode_tbl;
const size_t minmax_op[3][2];
};
struct rle8_params {
int min_cpy;
int max_cpy;
int min_rep;
int max_rep;
};
const char *rle_op_cstr(enum RLE_OP op);
struct rle8 parse_rle(const uint8_t *in, size_t len, const struct rle8_params *params);
size_t rle_count_rep(const uint8_t* src, size_t len, size_t max);
size_t rle_count_cpy(const uint8_t* src, size_t len, size_t max);
#ifdef RLE_PARSE_IMPLEMENTATION
const char *rle_op_cstr(enum RLE_OP op) {
const char *res = "UNKNOWN";
switch (op) {
case RLE_OP_CPY:
res = "CPY";
break;
case RLE_OP_REP:
res = "REP";
break;
case RLE_OP_LIT:
res = "LIT";
break;
case RLE_OP_NOP:
res = "NOP";
break;
case RLE_OP_INVALID:
res = "INVALID";
break;
}
return res;
}
struct rle8 parse_rle(const uint8_t *in, size_t len, const struct rle8_params *params) {
struct rle8 res = { RLE_OP_CPY, 0 };
const uint8_t *p = in;
uint8_t prev = *p;
int num_same = 0;
int num_scan = 0;
while (p < in + len) {
++num_scan;
if (*p == prev) {
++num_same;
} else {
// Check end of REP. -- XXX: this is b0rken..
if (num_same >= params->min_rep) {
return (struct rle8){ RLE_OP_REP, num_same };
}
num_same = 1;
}
// printf("<'%c'> scan:%d, same:%d\n", *p, num_scan, num_same);
// Check for min-rep violation while in CPY scan
if (num_same == params->min_rep && num_scan != num_same) {
return (struct rle8){ RLE_OP_CPY, num_scan - num_same };
}
// Check for max-cpy limit
if (num_scan == params->max_cpy && (num_scan != num_same)) {
return (struct rle8){ RLE_OP_CPY, num_scan };
}
// Check for max-rep limit
if (num_same == params->max_rep && num_scan == num_same) {
return (struct rle8){ RLE_OP_REP, num_same };
}
prev = *p;
++p;
}
if (num_same == num_scan && num_same >= params->min_rep) {
res.op = RLE_OP_REP;
}
res.cnt = num_scan;
return res;
}
/*
A -> 1
AA -> 2
AB -> 1
*/
// Count the number of repeated characters in the buffer `src` of length `len`, up to the maximum `max`.
// The count is inclusive; for any non-zero length input there's at least one repeated character.
size_t rle_count_rep(const uint8_t* src, size_t len, size_t max) {
size_t cnt = 0;
if (len && max) {
do { ++cnt; } while ((cnt + 1 <= len) && (cnt < max) && (src[cnt-1] == src[cnt]));
}
return cnt;
}
/*
A -> 1
AA -> 0 (<--!)
AB -> 2
ABB -> 1
*/
// Count the number of non-repeated characters in the buffer `src` of length `len`, up to the maximum `max`.
size_t rle_count_cpy(const uint8_t* src, size_t len, size_t max) {
size_t cnt = 0;
while ((cnt + 1 <= len) && (cnt < max) && ((cnt + 1 == len) || (src[cnt] != src[cnt+1]))) { ++cnt; };
return cnt;
}
#endif
#ifdef __cplusplus
}
#endif