hikari_buffer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,517 @@
1
+ #include "buffer.h"
2
+ #include "convert.h"
3
+ #include "io.h"
4
+ #include <ruby/encoding.h>
5
+ static VALUE
6
+ buffer_alloc(VALUE klass);
7
+
8
+ #define BUFFER_INITIAL_CAPACITY 1024
9
+
10
+ #define DEFINE_WRITE_METHOD(NAME, TYPE, CONVERTER) \
11
+ static VALUE \
12
+ buffer_write_##NAME(VALUE self, VALUE val) \
13
+ { \
14
+ Buffer *buffer = get_buffer_struct(self); \
15
+ TYPE value = CONVERTER(val); \
16
+ \
17
+ buffer_write( \
18
+ buffer, \
19
+ &value, \
20
+ sizeof(value)); \
21
+ \
22
+ return self; \
23
+ }
24
+
25
+ #define DEFINE_READ_METHOD(NAME, TYPE, CONVERTER) \
26
+ static VALUE \
27
+ buffer_read_##NAME(VALUE self) \
28
+ { \
29
+ Buffer *buffer = get_buffer_struct(self); \
30
+ TYPE value; \
31
+ \
32
+ buffer_read( \
33
+ buffer, \
34
+ &value, \
35
+ sizeof(value)); \
36
+ \
37
+ return CONVERTER(value); \
38
+ }
39
+ #define DEFINE_PEEK_METHOD(NAME, TYPE, CONVERTER) \
40
+ static VALUE \
41
+ buffer_peek_##NAME(VALUE self) \
42
+ { \
43
+ Buffer *buffer = get_buffer_struct(self); \
44
+ TYPE value; \
45
+ \
46
+ buffer_peek( \
47
+ buffer, \
48
+ &value, \
49
+ sizeof(value)); \
50
+ \
51
+ return CONVERTER(value); \
52
+ }
53
+
54
+ #define DEFINE_WRITE(NAME) \
55
+ rb_define_method(rb_cBuffer, "write_" #NAME, buffer_write_##NAME, 1)
56
+
57
+ #define DEFINE_READ(NAME) \
58
+ rb_define_method(rb_cBuffer, "read_" #NAME, buffer_read_##NAME, 0)
59
+
60
+ #define DEFINE_PEEK(NAME) \
61
+ rb_define_method(rb_cBuffer, "peek_" #NAME, buffer_peek_##NAME, 0)
62
+
63
+ static void
64
+ buffer_mark(void *ptr)
65
+ {
66
+ (void)ptr; // No Ruby objects to mark
67
+ }
68
+
69
+ static void
70
+ buffer_free(void *ptr)
71
+ {
72
+ Buffer *buffer = ptr;
73
+ if (buffer == NULL)
74
+ return;
75
+ xfree(buffer->data);
76
+ }
77
+
78
+ static const rb_data_type_t buffer_type = {
79
+ .wrap_struct_name = "Hikari::Buffer",
80
+ .function = {
81
+ .dmark = buffer_mark,
82
+ .dfree = buffer_free,
83
+ .dsize = NULL},
84
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY};
85
+
86
+ static inline Buffer *
87
+ get_buffer_struct(VALUE self)
88
+ {
89
+ Buffer *buffer;
90
+ TypedData_Get_Struct(
91
+ self,
92
+ Buffer,
93
+ &buffer_type,
94
+ buffer);
95
+ return buffer;
96
+ }
97
+
98
+ static VALUE
99
+ buffer_initialize(int argc, VALUE *argv, VALUE self)
100
+ {
101
+
102
+ Buffer *buffer = get_buffer_struct(self);
103
+ size_t capacity = BUFFER_INITIAL_CAPACITY;
104
+ if (argc > 1)
105
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0 or 1)", argc);
106
+ if (argc == 1)
107
+ capacity = NUM2SIZET(argv[0]);
108
+ if (capacity == 0)
109
+ rb_raise(rb_eArgError, "capacity must be greater than 0");
110
+ buffer->capacity = capacity;
111
+ buffer->size = 0;
112
+ buffer->cursor = 0;
113
+ buffer->data = ALLOC_N(uint8_t, capacity);
114
+ return Qnil;
115
+ }
116
+
117
+ static VALUE
118
+ buffer_alloc(VALUE klass)
119
+ {
120
+ Buffer *buffer;
121
+
122
+ VALUE obj = TypedData_Make_Struct(
123
+ klass,
124
+ Buffer,
125
+ &buffer_type,
126
+ buffer);
127
+ buffer->data = NULL;
128
+ buffer->size = 0;
129
+ buffer->cursor = 0;
130
+ buffer->capacity = 0;
131
+ return obj;
132
+ }
133
+
134
+ static VALUE
135
+ buffer_capacity(VALUE self)
136
+ {
137
+ Buffer *buffer = get_buffer_struct(self);
138
+
139
+ return SIZET2NUM(buffer->capacity);
140
+ }
141
+
142
+ static VALUE
143
+ buffer_size(VALUE self)
144
+ {
145
+ Buffer *buffer = get_buffer_struct(self);
146
+
147
+ return SIZET2NUM(buffer->size);
148
+ }
149
+
150
+ static VALUE
151
+ buffer_cursor(VALUE self)
152
+ {
153
+ Buffer *buffer = get_buffer_struct(self);
154
+
155
+ return SIZET2NUM(buffer->cursor);
156
+ }
157
+
158
+ static VALUE
159
+ buffer_clear(VALUE self)
160
+ {
161
+ Buffer *buffer = get_buffer_struct(self);
162
+
163
+ buffer->size = 0;
164
+ buffer->cursor = 0;
165
+
166
+ return self;
167
+ }
168
+ static VALUE
169
+ buffer_rewind(VALUE self)
170
+ {
171
+ Buffer *buffer = get_buffer_struct(self);
172
+
173
+ buffer->cursor = 0;
174
+
175
+ return self;
176
+ }
177
+ static VALUE
178
+ buffer_tell(VALUE self)
179
+ {
180
+ Buffer *buffer = get_buffer_struct(self);
181
+
182
+ return SIZET2NUM(buffer->cursor);
183
+ }
184
+ static VALUE
185
+ buffer_remaining(VALUE self)
186
+ {
187
+ Buffer *buffer = get_buffer_struct(self);
188
+
189
+ return SIZET2NUM(buffer->size - buffer->cursor);
190
+ }
191
+ static VALUE
192
+ buffer_seek(VALUE self, VALUE pos)
193
+ {
194
+ Buffer *buffer = get_buffer_struct(self);
195
+ size_t position = NUM2SIZET(pos);
196
+ if (position > buffer->size)
197
+ {
198
+ rb_raise(
199
+ rb_eRangeError,
200
+ "seek position %zu exceeds buffer size %zu",
201
+ position,
202
+ buffer->size);
203
+ }
204
+ buffer->cursor = position;
205
+ return self;
206
+ }
207
+ static VALUE
208
+ buffer_skip(VALUE self, VALUE len)
209
+ {
210
+ Buffer *buffer = get_buffer_struct(self);
211
+
212
+ size_t length = NUM2SIZET(len);
213
+
214
+ buffer_check_read_bounds(buffer, length);
215
+
216
+ buffer->cursor += length;
217
+
218
+ return self;
219
+ }
220
+
221
+ DEFINE_WRITE_METHOD(u8, uint8_t, rb_value_to_u8)
222
+ DEFINE_WRITE_METHOD(u16, uint16_t, rb_value_to_u16)
223
+ DEFINE_WRITE_METHOD(u32, uint32_t, rb_value_to_u32)
224
+ DEFINE_WRITE_METHOD(u64, uint64_t, rb_value_to_u64)
225
+
226
+ DEFINE_READ_METHOD(u8, uint8_t, rb_u8_to_value)
227
+ DEFINE_READ_METHOD(u16, uint16_t, rb_u16_to_value)
228
+ DEFINE_READ_METHOD(u32, uint32_t, rb_u32_to_value)
229
+ DEFINE_READ_METHOD(u64, uint64_t, rb_u64_to_value)
230
+
231
+ DEFINE_PEEK_METHOD(u8, uint8_t, rb_u8_to_value)
232
+ DEFINE_PEEK_METHOD(u16, uint16_t, rb_u16_to_value)
233
+ DEFINE_PEEK_METHOD(u32, uint32_t, rb_u32_to_value)
234
+ DEFINE_PEEK_METHOD(u64, uint64_t, rb_u64_to_value)
235
+
236
+ DEFINE_WRITE_METHOD(i8, int8_t, rb_value_to_i8)
237
+ DEFINE_WRITE_METHOD(i16, int16_t, rb_value_to_i16)
238
+ DEFINE_WRITE_METHOD(i32, int32_t, rb_value_to_i32)
239
+ DEFINE_WRITE_METHOD(i64, int64_t, rb_value_to_i64)
240
+
241
+ DEFINE_READ_METHOD(i8, int8_t, rb_i8_to_value)
242
+ DEFINE_READ_METHOD(i16, int16_t, rb_i16_to_value)
243
+ DEFINE_READ_METHOD(i32, int32_t, rb_i32_to_value)
244
+ DEFINE_READ_METHOD(i64, int64_t, rb_i64_to_value)
245
+
246
+ DEFINE_PEEK_METHOD(i8, int8_t, rb_i8_to_value)
247
+ DEFINE_PEEK_METHOD(i16, int16_t, rb_i16_to_value)
248
+ DEFINE_PEEK_METHOD(i32, int32_t, rb_i32_to_value)
249
+ DEFINE_PEEK_METHOD(i64, int64_t, rb_i64_to_value)
250
+
251
+ DEFINE_WRITE_METHOD(f32, float, rb_value_to_f32)
252
+ DEFINE_WRITE_METHOD(f64, double, rb_value_to_f64)
253
+ DEFINE_READ_METHOD(f32, float, rb_f32_to_value)
254
+ DEFINE_READ_METHOD(f64, double, rb_f64_to_value)
255
+
256
+ DEFINE_PEEK_METHOD(f32, float, rb_f32_to_value)
257
+ DEFINE_PEEK_METHOD(f64, double, rb_f64_to_value)
258
+
259
+ static VALUE
260
+ buffer_write_bytes(VALUE self, VALUE str)
261
+ {
262
+ Buffer *buffer = get_buffer_struct(self);
263
+ Check_Type(str, T_STRING);
264
+ buffer_write(
265
+ buffer,
266
+ RSTRING_PTR(str),
267
+ RSTRING_LEN(str));
268
+ return self;
269
+ }
270
+ static VALUE
271
+ buffer_read_bytes(VALUE self, VALUE len)
272
+ {
273
+ Buffer *buffer = get_buffer_struct(self);
274
+ size_t length = NUM2SIZET(len);
275
+
276
+ VALUE str = rb_str_new(NULL, length);
277
+ buffer_read(
278
+ buffer,
279
+ RSTRING_PTR(str),
280
+ length);
281
+ return str;
282
+ }
283
+
284
+ static VALUE
285
+ buffer_write_string(VALUE self, VALUE str)
286
+ {
287
+ Buffer *buffer = get_buffer_struct(self);
288
+
289
+ Check_Type(str, T_STRING);
290
+
291
+ size_t len = RSTRING_LEN(str);
292
+
293
+ if (len > UINT32_MAX)
294
+ {
295
+ rb_raise(
296
+ rb_eRangeError,
297
+ "string is too large");
298
+ }
299
+
300
+ uint32_t length = (uint32_t)len;
301
+
302
+ buffer_write(
303
+ buffer,
304
+ &length,
305
+ sizeof(length));
306
+
307
+ buffer_write(
308
+ buffer,
309
+ RSTRING_PTR(str),
310
+ len);
311
+
312
+ return self;
313
+ }
314
+ static VALUE
315
+ buffer_read_string(VALUE self)
316
+ {
317
+ Buffer *buffer = get_buffer_struct(self);
318
+
319
+ uint32_t length = 0;
320
+
321
+ buffer_read(
322
+ buffer,
323
+ &length,
324
+ sizeof(length));
325
+
326
+ VALUE str = rb_str_new(NULL, length);
327
+ rb_enc_associate(
328
+ str,
329
+ rb_utf8_encoding());
330
+
331
+ buffer_read(
332
+ buffer,
333
+ RSTRING_PTR(str),
334
+ length);
335
+
336
+ return str;
337
+ }
338
+
339
+ static VALUE
340
+ buffer_write_bool(VALUE self, VALUE val)
341
+ {
342
+ if (val != Qtrue && val != Qfalse)
343
+ rb_raise(rb_eTypeError, "expected a boolean value");
344
+ Buffer *buffer = get_buffer_struct(self);
345
+ uint8_t value = (val == Qtrue);
346
+ buffer_write(
347
+ buffer,
348
+ &value,
349
+ sizeof(value));
350
+ return self;
351
+ }
352
+ static VALUE
353
+ buffer_read_bool(VALUE self)
354
+ {
355
+ Buffer *buffer = get_buffer_struct(self);
356
+ uint8_t value;
357
+ buffer_read(
358
+ buffer,
359
+ &value,
360
+ sizeof(value));
361
+ return value ? Qtrue : Qfalse;
362
+ }
363
+ static VALUE
364
+ buffer_peek_bool(VALUE self)
365
+ {
366
+ Buffer *buffer = get_buffer_struct(self);
367
+ uint8_t value;
368
+ buffer_peek(
369
+ buffer,
370
+ &value,
371
+ sizeof(value));
372
+ return value ? Qtrue : Qfalse;
373
+ }
374
+
375
+ void Init_hikari_buffer_class(void)
376
+ {
377
+ rb_cBuffer = rb_define_class_under(
378
+ rb_mHikari,
379
+ "Buffer",
380
+ rb_cObject);
381
+
382
+ rb_define_alloc_func(
383
+ rb_cBuffer,
384
+ buffer_alloc);
385
+ rb_define_method(
386
+ rb_cBuffer,
387
+ "initialize",
388
+ buffer_initialize,
389
+ -1);
390
+ rb_define_method(
391
+ rb_cBuffer,
392
+ "capacity",
393
+ buffer_capacity,
394
+ 0);
395
+ rb_define_method(
396
+ rb_cBuffer,
397
+ "size",
398
+ buffer_size,
399
+ 0);
400
+ rb_define_method(
401
+ rb_cBuffer,
402
+ "cursor",
403
+ buffer_cursor,
404
+ 0);
405
+ rb_define_method(
406
+ rb_cBuffer,
407
+ "clear",
408
+ buffer_clear,
409
+ 0);
410
+ rb_define_method(
411
+ rb_cBuffer,
412
+ "rewind",
413
+ buffer_rewind,
414
+ 0);
415
+ rb_define_method(
416
+ rb_cBuffer,
417
+ "tell",
418
+ buffer_tell,
419
+ 0);
420
+ rb_define_method(
421
+ rb_cBuffer,
422
+ "seek",
423
+ buffer_seek,
424
+ 1);
425
+ rb_define_method(
426
+ rb_cBuffer,
427
+ "remaining",
428
+ buffer_remaining,
429
+ 0);
430
+ rb_define_method(
431
+ rb_cBuffer,
432
+ "skip",
433
+ buffer_skip,
434
+ 1);
435
+ DEFINE_WRITE(u8);
436
+ DEFINE_WRITE(u16);
437
+ DEFINE_WRITE(u32);
438
+ DEFINE_WRITE(u64);
439
+
440
+ DEFINE_READ(u8);
441
+ DEFINE_READ(u16);
442
+ DEFINE_READ(u32);
443
+ DEFINE_READ(u64);
444
+
445
+ DEFINE_PEEK(u8);
446
+ DEFINE_PEEK(u16);
447
+ DEFINE_PEEK(u32);
448
+ DEFINE_PEEK(u64);
449
+
450
+ DEFINE_WRITE(i8);
451
+ DEFINE_WRITE(i16);
452
+ DEFINE_WRITE(i32);
453
+ DEFINE_WRITE(i64);
454
+
455
+ DEFINE_READ(i8);
456
+ DEFINE_READ(i16);
457
+ DEFINE_READ(i32);
458
+ DEFINE_READ(i64);
459
+
460
+ DEFINE_PEEK(i8);
461
+ DEFINE_PEEK(i16);
462
+ DEFINE_PEEK(i32);
463
+ DEFINE_PEEK(i64);
464
+
465
+ DEFINE_WRITE(f32);
466
+ DEFINE_WRITE(f64);
467
+ DEFINE_READ(f32);
468
+ DEFINE_READ(f64);
469
+ DEFINE_PEEK(f32);
470
+ DEFINE_PEEK(f64);
471
+
472
+ rb_define_method(
473
+ rb_cBuffer,
474
+ "write_bytes",
475
+ buffer_write_bytes,
476
+ 1);
477
+ rb_define_method(
478
+ rb_cBuffer,
479
+ "read_bytes",
480
+ buffer_read_bytes,
481
+ 1);
482
+ rb_define_method(
483
+ rb_cBuffer,
484
+ "write_string",
485
+ buffer_write_string,
486
+ 1);
487
+ rb_define_method(
488
+ rb_cBuffer,
489
+ "read_string",
490
+ buffer_read_string,
491
+ 0);
492
+
493
+ rb_define_method(
494
+ rb_cBuffer,
495
+ "write_bool",
496
+ buffer_write_bool,
497
+ 1);
498
+ rb_define_method(
499
+ rb_cBuffer,
500
+ "read_bool",
501
+ buffer_read_bool,
502
+ 0);
503
+ rb_define_method(
504
+ rb_cBuffer,
505
+ "peek_bool",
506
+ buffer_peek_bool,
507
+ 0);
508
+ }
509
+
510
+ #undef DEFINE_WRITE_METHOD
511
+ #undef DEFINE_READ_METHOD
512
+
513
+ #undef DEFINE_WRITE
514
+ #undef DEFINE_READ
515
+
516
+ #undef DEFINE_PEEK_METHOD
517
+ #undef DEFINE_PEEK
@@ -0,0 +1,15 @@
1
+ #ifndef HIKARI_BUFFER_BUFFER_H
2
+ #define HIKARI_BUFFER_BUFFER_H
3
+
4
+ #include "hikari_buffer.h"
5
+
6
+ typedef struct {
7
+ uint8_t * data;
8
+ size_t size;
9
+ size_t capacity;
10
+ size_t cursor;
11
+ } Buffer;
12
+
13
+ void Init_hikari_buffer_class(void);
14
+
15
+ #endif //HIKARI_BUFFER_BUFFER_H
@@ -0,0 +1,141 @@
1
+ #include "convert.h"
2
+
3
+ uint8_t
4
+ rb_value_to_u8(VALUE value)
5
+ {
6
+ unsigned int n = NUM2UINT(value);
7
+
8
+ if (n > UINT8_MAX) {
9
+ rb_raise(
10
+ rb_eRangeError,
11
+ "value %u is out of range for u8",
12
+ n
13
+ );
14
+ }
15
+
16
+ return (uint8_t)n;
17
+ }
18
+
19
+ uint16_t
20
+ rb_value_to_u16(VALUE value)
21
+ {
22
+ unsigned int n = NUM2UINT(value);
23
+
24
+ if (n > UINT16_MAX) {
25
+ rb_raise(
26
+ rb_eRangeError,
27
+ "value %u is out of range for u16",
28
+ n
29
+ );
30
+ }
31
+
32
+ return (uint16_t)n;
33
+ }
34
+
35
+ uint32_t
36
+ rb_value_to_u32(VALUE value)
37
+ {
38
+ return (uint32_t)NUM2UINT(value);
39
+ }
40
+
41
+ uint64_t
42
+ rb_value_to_u64(VALUE value)
43
+ {
44
+ return (uint64_t)NUM2ULL(value);
45
+ }
46
+
47
+ VALUE rb_u8_to_value(uint8_t value)
48
+ {
49
+ return UINT2NUM(value);
50
+ }
51
+
52
+ VALUE rb_u16_to_value(uint16_t value)
53
+ {
54
+ return UINT2NUM(value);
55
+ }
56
+
57
+ VALUE rb_u32_to_value(uint32_t value)
58
+ {
59
+ return UINT2NUM(value);
60
+ }
61
+
62
+ VALUE rb_u64_to_value(uint64_t value)
63
+ {
64
+ return ULL2NUM(value);
65
+ }
66
+
67
+
68
+
69
+
70
+ int8_t
71
+ rb_value_to_i8(VALUE value)
72
+ {
73
+ long n = NUM2LONG(value);
74
+ if (n < INT8_MIN || n > INT8_MAX) {
75
+ rb_raise(
76
+ rb_eRangeError,
77
+ "value %ld is out of range for i8",
78
+ n
79
+ );
80
+ }
81
+ return (int8_t)n;
82
+ }
83
+ int16_t
84
+ rb_value_to_i16(VALUE value)
85
+ {
86
+ long n = NUM2LONG(value);
87
+ if (n < INT16_MIN || n > INT16_MAX) {
88
+ rb_raise(
89
+ rb_eRangeError,
90
+ "value %ld is out of range for i16",
91
+ n
92
+ );
93
+ }
94
+ return (int16_t)n;
95
+ }
96
+ int32_t
97
+ rb_value_to_i32(VALUE value)
98
+ {
99
+ return (int32_t)NUM2INT(value);
100
+ }
101
+
102
+ int64_t
103
+ rb_value_to_i64(VALUE value)
104
+ {
105
+ return (int64_t)NUM2LL(value);
106
+ }
107
+ VALUE rb_i8_to_value(int8_t value)
108
+ {
109
+ return INT2NUM(value);
110
+ }
111
+
112
+ VALUE rb_i16_to_value(int16_t value)
113
+ {
114
+ return INT2NUM(value);
115
+ }
116
+ VALUE rb_i32_to_value(int32_t value)
117
+ {
118
+ return INT2NUM(value);
119
+ }
120
+ VALUE rb_i64_to_value(int64_t value)
121
+ {
122
+ return LL2NUM(value);
123
+ }
124
+
125
+ float rb_value_to_f32(VALUE value)
126
+ {
127
+ return (float)NUM2DBL(value);
128
+ }
129
+ double rb_value_to_f64(VALUE value)
130
+ {
131
+ return NUM2DBL(value);
132
+ }
133
+
134
+ VALUE rb_f32_to_value(float value)
135
+ {
136
+ return DBL2NUM((double)value);
137
+ }
138
+ VALUE rb_f64_to_value(double value)
139
+ {
140
+ return DBL2NUM(value);
141
+ }
@@ -0,0 +1,38 @@
1
+ #ifndef HIKARI_CONVERT_H
2
+ #define HIKARI_CONVERT_H
3
+
4
+ #include <stdint.h>
5
+ #include <limits.h>
6
+
7
+ #include "ruby.h"
8
+
9
+ uint8_t rb_value_to_u8(VALUE value);
10
+ uint16_t rb_value_to_u16(VALUE value);
11
+ uint32_t rb_value_to_u32(VALUE value);
12
+ uint64_t rb_value_to_u64(VALUE value);
13
+
14
+ VALUE rb_u8_to_value(uint8_t value);
15
+ VALUE rb_u16_to_value(uint16_t value);
16
+ VALUE rb_u32_to_value(uint32_t value);
17
+ VALUE rb_u64_to_value(uint64_t value);
18
+
19
+
20
+ int8_t rb_value_to_i8(VALUE value);
21
+ int16_t rb_value_to_i16(VALUE value);
22
+ int32_t rb_value_to_i32(VALUE value);
23
+ int64_t rb_value_to_i64(VALUE value);
24
+
25
+ VALUE rb_i8_to_value(int8_t value);
26
+ VALUE rb_i16_to_value(int16_t value);
27
+ VALUE rb_i32_to_value(int32_t value);
28
+ VALUE rb_i64_to_value(int64_t value);
29
+
30
+ float rb_value_to_f32(VALUE value);
31
+ double rb_value_to_f64(VALUE value);
32
+
33
+ VALUE rb_f32_to_value(float value);
34
+ VALUE rb_f64_to_value(double value);
35
+
36
+
37
+
38
+ #endif
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ # Makes all symbols private by default to avoid unintended conflict
6
+ # with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED
7
+ # selectively, or entirely remove this flag.
8
+ append_cflags("-fvisibility=hidden")
9
+
10
+ create_makefile("hikari_buffer/hikari_buffer")