tinybits 0.2.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51ab487694dc35eabde1bebda52a2726074ab6c80ef84ce2c845141c9732283c
4
- data.tar.gz: 5c3b2c2eb52a15fb5e32d54c37d705fd41c9ec4759464519c599f83f517b9e2b
3
+ metadata.gz: 579aa574466ff4f72f4e9fa59940d3d14fc773404cb73296b2b1498551da6d2f
4
+ data.tar.gz: 5edf98872ab8d59a3868b0dc6e3b05271d8dbdba7664afc039ca219820a7b247
5
5
  SHA512:
6
- metadata.gz: 65fd3c3a22a67d8a1a6a218644d4ed82171386202de0b09ce86c285501852cf40c71690820defbf811be66db29da6346d9e933878027377e1ac0c680c08cdf60
7
- data.tar.gz: 6d389ea71dac6c417956d98dfe545f3baa015f2947ce968d9f8ec2f0dbe62ffdd5f841fb789658b00a69fe7975b8ed7788b1747a2867440fee10f0c19b05c243
6
+ metadata.gz: 887b0b5c435cd7da039af2b370f680c5266c06cad1db665e54436f81a22172837495739c051ccea3050a446e055ca24a9198269a51bdb7005fec79d398c37758
7
+ data.tar.gz: 44c1cd7a40ccf330d8ca96a5c7203b6ce60c07c00c3580fe28440ef0b62c6c083ad4417143a52afce3ae0553eefbc7a9d9035e7011d13557f682704be6f5ad5d
@@ -1,5 +1,6 @@
1
1
  require 'mkmf'
2
2
 
3
+ $CFLAGS << " -O3 -march=native"
3
4
 
4
5
  dir_config('tinybits_ext')
5
6
  create_makefile('tinybits_ext')
@@ -7,19 +7,30 @@ t = [Time.now, nil, true, false]
7
7
 
8
8
 
9
9
 
10
-
10
+ =begin
11
11
  puts packer.dump(t).bytesize
12
12
 
13
13
  puts t
14
14
  puts t2 = unpacker.unpack(packer.pack(t))
15
15
  puts t == t2
16
-
16
+ =end
17
+
18
+ class User
19
+ def initialize(name:, title:)
20
+ @name = name
21
+ @title = title
22
+ end
23
+
24
+ def to_tinybits
25
+ {"name" => @name, "title" => @title}
26
+ end
27
+ end
17
28
 
18
29
  objects = [{"abc": 123}, {"abc": [1, 2, "abc"]}, ["xyz", "abc", "xyz", 7.6] ]
19
30
 
20
31
  puts "----------------"
21
32
 
22
- packer.reset
33
+ #packer.reset
23
34
 
24
35
  objects.each do |obj|
25
36
  puts packer << obj
@@ -31,7 +42,21 @@ puts buffer.bytesize
31
42
 
32
43
  unpacker.buffer = buffer
33
44
 
45
+
34
46
  while(value = unpacker.pop)
35
47
  pp value
36
48
  puts "+++++++++++++++++++++++++"
37
49
  end
50
+
51
+ packer.reset
52
+
53
+ user = User.new(name: "Mohamed", title: "Father")
54
+
55
+ data = { "user" => user, "tags" => ["user", "Father"] }
56
+
57
+ pp user
58
+ pp user.to_tinybits
59
+ packed = packer.pack(data)
60
+ puts packed.bytesize
61
+ pp unpacker.unpack(packed)
62
+
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * TinyBits Amalgamated Header
3
- * Generated on: Sat May 3 09:20:46 PM CEST 2025
3
+ * Generated on: Sun May 4 05:43:30 PM CEST 2025
4
4
  */
5
5
 
6
6
  #ifndef TINY_BITS_H
@@ -89,8 +89,11 @@ typedef struct HashTable {
89
89
 
90
90
  static inline uint32_t fast_hash_32(const char* str, uint16_t len) {
91
91
  uint32_t hash = len;
92
- hash = (hash << 16) | (((unsigned char)str[0] << 8) | (unsigned char)str[1]);
93
- hash ^= (((unsigned char)str[len-2] << 8) | (unsigned char)str[len-1]);
92
+ hash = (hash << 24) |
93
+ ((unsigned char)str[0] << 16) |
94
+ ((unsigned char)str[1] << 8 ) |
95
+ ((unsigned char)str[len-1]);
96
+ //hash ^= (((unsigned char)str[len-2] << 24) | ((unsigned char)str[len-1] << 16));
94
97
  return hash;
95
98
  }
96
99
 
@@ -652,7 +655,7 @@ static inline int pack_str(tiny_bits_packer *encoder, char* str, uint32_t str_le
652
655
  HashEntry entry = encoder->encode_table.cache[index - 1];
653
656
  if (hash_code == entry.hash
654
657
  && str_len == entry.length
655
- && (str_len <= 4 || (fast_memcmp(str, encoder->buffer + entry.offset, str_len) == 0) )) {
658
+ && fast_memcmp(str, encoder->buffer + entry.offset, str_len) == 0 ) {
656
659
  id = index - 1;
657
660
  found = 1;
658
661
  break;
@@ -1052,7 +1055,7 @@ static inline enum tiny_bits_type _unpack_str(tiny_bits_unpacker *decoder, uint8
1052
1055
  }
1053
1056
  value->str_blob_val.id = 0;
1054
1057
  // Handle new string (not deduplicated)
1055
- if(decoder->strings_count < TB_HASH_CACHE_SIZE){
1058
+ if(decoder->strings_count < TB_HASH_CACHE_SIZE && len >= 2 && len <= 128){
1056
1059
  if (decoder->strings_count >= decoder->strings_size) {
1057
1060
  size_t new_size = decoder->strings_size * 2;
1058
1061
  void *new_strings = realloc(decoder->strings, new_size * sizeof(*decoder->strings));
@@ -4,8 +4,23 @@
4
4
  #include "tinybits.h"
5
5
 
6
6
  // Ruby module and classes
7
+ /*
8
+ * Document-module: TinyBits
9
+ *
10
+ * A Ruby extension for fast binary serialization and deserialization of Ruby objects.
11
+ */
7
12
  VALUE rb_mTinyBits;
13
+ /*
14
+ * Document-class: TinyBits::Packer
15
+ *
16
+ * The Packer class handles serialization of Ruby objects to the TinyBits binary format.
17
+ */
8
18
  VALUE rb_cPacker;
19
+ /*
20
+ * Document-class: TinyBits::Unpacker
21
+ *
22
+ * The Unpacker class handles deserialization of TinyBits binary format to Ruby objects.
23
+ */
9
24
  VALUE rb_cUnpacker;
10
25
 
11
26
  // Forward declarations
@@ -75,6 +90,13 @@ static VALUE rb_packer_alloc(VALUE klass) {
75
90
  return TypedData_Wrap_Struct(klass, &packer_data_type, packer_data);
76
91
  }
77
92
 
93
+ /*
94
+ * Document-method: initialize
95
+ *
96
+ * Initializes a new Packer object
97
+ *
98
+ * @return [Packer] The initialized packer object.
99
+ */
78
100
  static VALUE rb_packer_init(VALUE self) {
79
101
  PackerData* packer_data;
80
102
  TypedData_Get_Struct(self, PackerData, &packer_data_type, packer_data);
@@ -131,13 +153,27 @@ static inline int pack_ruby_object_recursive(tiny_bits_packer* packer, VALUE obj
131
153
  double unixtime = NUM2DBL(rb_funcall(obj, rb_intern("to_f"), 0));
132
154
  return pack_datetime(packer, unixtime, FIX2INT(rb_time_utc_offset(obj)));
133
155
  }
156
+ if(rb_respond_to(obj, rb_intern("to_tinybits"))){
157
+ VALUE custom_obj = rb_funcall(obj, rb_intern("to_tinybits"), 0);
158
+ return pack_ruby_object_recursive(packer, custom_obj, context);
159
+ }
134
160
  //printf("Unsupported type encountered during packing: %s", rb_obj_classname(obj));
135
161
  rb_warn("Unsupported type encountered during packing: %s", rb_obj_classname(obj));
136
162
  return 0;
137
163
  }
138
164
  }
139
165
 
140
- // keeps the public API the same.
166
+ /*
167
+ * Document-method: pack
168
+ *
169
+ * Packs a Ruby object into a binary string.
170
+ * Supports Ruby types: String, Array, Hash, Integer, Float, nil, true, false, Symbol, and Time.
171
+ * Objects can implement a `to_tinybits` method to provide custom serialization.
172
+ *
173
+ * @param obj [Object] The Ruby object to pack.
174
+ * @return [String] The packed binary string (frozen).
175
+ * @raise [RuntimeError] If packing fails due to unsupported types or other errors.
176
+ */
141
177
  static VALUE rb_pack(VALUE self, VALUE obj) {
142
178
  PackerData* packer_data;
143
179
  TypedData_Get_Struct(self, PackerData, &packer_data_type, packer_data);
@@ -165,6 +201,16 @@ static VALUE rb_pack(VALUE self, VALUE obj) {
165
201
  return result;
166
202
  }
167
203
 
204
+ /*
205
+ * Document-method: push
206
+ *
207
+ * Appends a packed object to the current buffer.
208
+ * Inserts a separator when appending to non-empty buffer.
209
+ *
210
+ * @param obj [Object] The Ruby object to append.
211
+ * @return [Integer] The number of bytes added to the buffer.
212
+ * @raise [RuntimeError] If packing fails.
213
+ */
168
214
  static VALUE rb_push(VALUE self, VALUE obj) {
169
215
  PackerData* packer_data;
170
216
  TypedData_Get_Struct(self, PackerData, &packer_data_type, packer_data);
@@ -195,6 +241,13 @@ static VALUE rb_push(VALUE self, VALUE obj) {
195
241
  return INT2FIX(packer_data->packer->current_pos - initial_pos);
196
242
  }
197
243
 
244
+ /*
245
+ * Document-method: to_s
246
+ *
247
+ * Returns the current packed buffer as a string.
248
+ *
249
+ * @return [String] The current packed buffer contents (frozen).
250
+ */
198
251
  static VALUE rb_to_s(VALUE self){
199
252
  PackerData* packer_data;
200
253
  TypedData_Get_Struct(self, PackerData, &packer_data_type, packer_data);
@@ -1,3 +1,3 @@
1
1
  module TinyBits
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/lib/tinybits.rb CHANGED
@@ -2,6 +2,19 @@ require_relative './tinybits/version'
2
2
  require 'tinybits_ext'
3
3
 
4
4
  module TinyBits
5
+ # packs an object to a binary string
6
+ # @param obj [Object] The Ruby object to pack.
7
+ # @return [String] The packed binary string (frozen).
8
+ # @raise [RuntimeError] If packing fails due to unsupported types or other errors.
9
+ # this is a convinience interface, a better way is to instantiate a TinyBits::Packer
10
+ # object and use its #pack method
5
11
  def self.pack(object) = Packer.new.pack(object)
12
+
13
+ # unpacks an object from a binary string
14
+ # @param buffer [String] The Ruby string holding the packed buffer.
15
+ # @return [Object] The unpacked Ruby Object (all strings within the object will be frozen).
16
+ # @raise [RuntimeError] If unpacking fails due to unsupported types or malformed data.
17
+ # this is a convinience interface, a better way is to instantiate a TinyBits::Unpacker
18
+ # object and use its #unpack method
6
19
  def self.unpack(buffer) = Unpacker.new.unpack(buffer)
7
20
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinybits
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mohamed Hassan
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-03 00:00:00.000000000 Z
10
+ date: 2025-05-04 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: TinyBits is a Ruby gem that wraps the TinyBits C serializartion library,
13
13
  offering Rubyists the power of serializion with intger/float compression and string