OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2014 Google Inc. All rights reserved. | 2 // Copyright 2014 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 // strings rather than Ruby strings: traversing the Map requires conversion to | 56 // strings rather than Ruby strings: traversing the Map requires conversion to |
57 // Ruby string values on every traversal, potentially creating more garbage. We | 57 // Ruby string values on every traversal, potentially creating more garbage. We |
58 // should consider ways to cache a Ruby version of the key if this becomes an | 58 // should consider ways to cache a Ruby version of the key if this becomes an |
59 // issue later. | 59 // issue later. |
60 | 60 |
61 // Forms a key to use with the underlying strtable from a Ruby key value. |buf| | 61 // Forms a key to use with the underlying strtable from a Ruby key value. |buf| |
62 // must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to | 62 // must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to |
63 // construct a key byte sequence if needed. |out_key| and |out_length| provide | 63 // construct a key byte sequence if needed. |out_key| and |out_length| provide |
64 // the resulting key data/length. | 64 // the resulting key data/length. |
65 #define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) | 65 #define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) |
66 static void table_key(Map* self, VALUE key, | 66 static VALUE table_key(Map* self, VALUE key, |
67 char* buf, | 67 char* buf, |
68 const char** out_key, | 68 const char** out_key, |
69 size_t* out_length) { | 69 size_t* out_length) { |
70 switch (self->key_type) { | 70 switch (self->key_type) { |
71 case UPB_TYPE_BYTES: | 71 case UPB_TYPE_BYTES: |
72 case UPB_TYPE_STRING: | 72 case UPB_TYPE_STRING: |
73 // Strings: use string content directly. | 73 // Strings: use string content directly. |
74 Check_Type(key, T_STRING); | 74 Check_Type(key, T_STRING); |
75 native_slot_validate_string_encoding(self->key_type, key); | 75 key = native_slot_encode_and_freeze_string(self->key_type, key); |
76 *out_key = RSTRING_PTR(key); | 76 *out_key = RSTRING_PTR(key); |
77 *out_length = RSTRING_LEN(key); | 77 *out_length = RSTRING_LEN(key); |
78 break; | 78 break; |
79 | 79 |
80 case UPB_TYPE_BOOL: | 80 case UPB_TYPE_BOOL: |
81 case UPB_TYPE_INT32: | 81 case UPB_TYPE_INT32: |
82 case UPB_TYPE_INT64: | 82 case UPB_TYPE_INT64: |
83 case UPB_TYPE_UINT32: | 83 case UPB_TYPE_UINT32: |
84 case UPB_TYPE_UINT64: | 84 case UPB_TYPE_UINT64: |
85 native_slot_set(self->key_type, Qnil, buf, key); | 85 native_slot_set(self->key_type, Qnil, buf, key); |
86 *out_key = buf; | 86 *out_key = buf; |
87 *out_length = native_slot_size(self->key_type); | 87 *out_length = native_slot_size(self->key_type); |
88 break; | 88 break; |
89 | 89 |
90 default: | 90 default: |
91 // Map constructor should not allow a Map with another key type to be | 91 // Map constructor should not allow a Map with another key type to be |
92 // constructed. | 92 // constructed. |
93 assert(false); | 93 assert(false); |
94 break; | 94 break; |
95 } | 95 } |
| 96 |
| 97 return key; |
96 } | 98 } |
97 | 99 |
98 static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { | 100 static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { |
99 switch (self->key_type) { | 101 switch (self->key_type) { |
100 case UPB_TYPE_BYTES: | 102 case UPB_TYPE_BYTES: |
101 case UPB_TYPE_STRING: { | 103 case UPB_TYPE_STRING: { |
102 VALUE ret = rb_str_new(buf, length); | 104 VALUE ret = rb_str_new(buf, length); |
103 rb_enc_associate(ret, | 105 rb_enc_associate(ret, |
104 (self->key_type == UPB_TYPE_BYTES) ? | 106 (self->key_type == UPB_TYPE_BYTES) ? |
105 kRubyString8bitEncoding : kRubyStringUtf8Encoding); | 107 kRubyString8bitEncoding : kRubyStringUtf8Encoding); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 * Accesses the element at the given key. Throws an exception if the key type is | 352 * Accesses the element at the given key. Throws an exception if the key type is |
351 * incorrect. Returns nil when the key is not present in the map. | 353 * incorrect. Returns nil when the key is not present in the map. |
352 */ | 354 */ |
353 VALUE Map_index(VALUE _self, VALUE key) { | 355 VALUE Map_index(VALUE _self, VALUE key) { |
354 Map* self = ruby_to_Map(_self); | 356 Map* self = ruby_to_Map(_self); |
355 | 357 |
356 char keybuf[TABLE_KEY_BUF_LENGTH]; | 358 char keybuf[TABLE_KEY_BUF_LENGTH]; |
357 const char* keyval = NULL; | 359 const char* keyval = NULL; |
358 size_t length = 0; | 360 size_t length = 0; |
359 upb_value v; | 361 upb_value v; |
360 table_key(self, key, keybuf, &keyval, &length); | 362 key = table_key(self, key, keybuf, &keyval, &length); |
361 | 363 |
362 if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { | 364 if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { |
363 void* mem = value_memory(&v); | 365 void* mem = value_memory(&v); |
364 return native_slot_get(self->value_type, self->value_type_class, mem); | 366 return native_slot_get(self->value_type, self->value_type_class, mem); |
365 } else { | 367 } else { |
366 return Qnil; | 368 return Qnil; |
367 } | 369 } |
368 } | 370 } |
369 | 371 |
370 /* | 372 /* |
371 * call-seq: | 373 * call-seq: |
372 * Map.[]=(key, value) => value | 374 * Map.[]=(key, value) => value |
373 * | 375 * |
374 * Inserts or overwrites the value at the given key with the given new value. | 376 * Inserts or overwrites the value at the given key with the given new value. |
375 * Throws an exception if the key type is incorrect. Returns the new value that | 377 * Throws an exception if the key type is incorrect. Returns the new value that |
376 * was just inserted. | 378 * was just inserted. |
377 */ | 379 */ |
378 VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { | 380 VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { |
379 Map* self = ruby_to_Map(_self); | 381 Map* self = ruby_to_Map(_self); |
380 | 382 |
381 char keybuf[TABLE_KEY_BUF_LENGTH]; | 383 char keybuf[TABLE_KEY_BUF_LENGTH]; |
382 const char* keyval = NULL; | 384 const char* keyval = NULL; |
383 size_t length = 0; | 385 size_t length = 0; |
384 upb_value v; | 386 upb_value v; |
385 void* mem; | 387 void* mem; |
386 table_key(self, key, keybuf, &keyval, &length); | 388 key = table_key(self, key, keybuf, &keyval, &length); |
387 | 389 |
388 mem = value_memory(&v); | 390 mem = value_memory(&v); |
389 native_slot_set(self->value_type, self->value_type_class, mem, value); | 391 native_slot_set(self->value_type, self->value_type_class, mem, value); |
390 | 392 |
391 // Replace any existing value by issuing a 'remove' operation first. | 393 // Replace any existing value by issuing a 'remove' operation first. |
392 upb_strtable_remove2(&self->table, keyval, length, NULL); | 394 upb_strtable_remove2(&self->table, keyval, length, NULL); |
393 if (!upb_strtable_insert2(&self->table, keyval, length, v)) { | 395 if (!upb_strtable_insert2(&self->table, keyval, length, v)) { |
394 rb_raise(rb_eRuntimeError, "Could not insert into table"); | 396 rb_raise(rb_eRuntimeError, "Could not insert into table"); |
395 } | 397 } |
396 | 398 |
397 // Ruby hashmap's :[]= method also returns the inserted value. | 399 // Ruby hashmap's :[]= method also returns the inserted value. |
398 return value; | 400 return value; |
399 } | 401 } |
400 | 402 |
401 /* | 403 /* |
402 * call-seq: | 404 * call-seq: |
403 * Map.has_key?(key) => bool | 405 * Map.has_key?(key) => bool |
404 * | 406 * |
405 * Returns true if the given key is present in the map. Throws an exception if | 407 * Returns true if the given key is present in the map. Throws an exception if |
406 * the key has the wrong type. | 408 * the key has the wrong type. |
407 */ | 409 */ |
408 VALUE Map_has_key(VALUE _self, VALUE key) { | 410 VALUE Map_has_key(VALUE _self, VALUE key) { |
409 Map* self = ruby_to_Map(_self); | 411 Map* self = ruby_to_Map(_self); |
410 | 412 |
411 char keybuf[TABLE_KEY_BUF_LENGTH]; | 413 char keybuf[TABLE_KEY_BUF_LENGTH]; |
412 const char* keyval = NULL; | 414 const char* keyval = NULL; |
413 size_t length = 0; | 415 size_t length = 0; |
414 table_key(self, key, keybuf, &keyval, &length); | 416 key = table_key(self, key, keybuf, &keyval, &length); |
415 | 417 |
416 if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { | 418 if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { |
417 return Qtrue; | 419 return Qtrue; |
418 } else { | 420 } else { |
419 return Qfalse; | 421 return Qfalse; |
420 } | 422 } |
421 } | 423 } |
422 | 424 |
423 /* | 425 /* |
424 * call-seq: | 426 * call-seq: |
425 * Map.delete(key) => old_value | 427 * Map.delete(key) => old_value |
426 * | 428 * |
427 * Deletes the value at the given key, if any, returning either the old value or | 429 * Deletes the value at the given key, if any, returning either the old value or |
428 * nil if none was present. Throws an exception if the key is of the wrong type. | 430 * nil if none was present. Throws an exception if the key is of the wrong type. |
429 */ | 431 */ |
430 VALUE Map_delete(VALUE _self, VALUE key) { | 432 VALUE Map_delete(VALUE _self, VALUE key) { |
431 Map* self = ruby_to_Map(_self); | 433 Map* self = ruby_to_Map(_self); |
432 | 434 |
433 char keybuf[TABLE_KEY_BUF_LENGTH]; | 435 char keybuf[TABLE_KEY_BUF_LENGTH]; |
434 const char* keyval = NULL; | 436 const char* keyval = NULL; |
435 size_t length = 0; | 437 size_t length = 0; |
436 upb_value v; | 438 upb_value v; |
437 table_key(self, key, keybuf, &keyval, &length); | 439 key = table_key(self, key, keybuf, &keyval, &length); |
438 | 440 |
439 if (upb_strtable_remove2(&self->table, keyval, length, &v)) { | 441 if (upb_strtable_remove2(&self->table, keyval, length, &v)) { |
440 void* mem = value_memory(&v); | 442 void* mem = value_memory(&v); |
441 return native_slot_get(self->value_type, self->value_type_class, mem); | 443 return native_slot_get(self->value_type, self->value_type_class, mem); |
442 } else { | 444 } else { |
443 return Qnil; | 445 return Qnil; |
444 } | 446 } |
445 } | 447 } |
446 | 448 |
447 /* | 449 /* |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 rb_define_method(klass, "delete", Map_delete, 1); | 801 rb_define_method(klass, "delete", Map_delete, 1); |
800 rb_define_method(klass, "clear", Map_clear, 0); | 802 rb_define_method(klass, "clear", Map_clear, 0); |
801 rb_define_method(klass, "length", Map_length, 0); | 803 rb_define_method(klass, "length", Map_length, 0); |
802 rb_define_method(klass, "dup", Map_dup, 0); | 804 rb_define_method(klass, "dup", Map_dup, 0); |
803 rb_define_method(klass, "==", Map_eq, 1); | 805 rb_define_method(klass, "==", Map_eq, 1); |
804 rb_define_method(klass, "hash", Map_hash, 0); | 806 rb_define_method(klass, "hash", Map_hash, 0); |
805 rb_define_method(klass, "inspect", Map_inspect, 0); | 807 rb_define_method(klass, "inspect", Map_inspect, 0); |
806 rb_define_method(klass, "merge", Map_merge, 1); | 808 rb_define_method(klass, "merge", Map_merge, 1); |
807 rb_include_module(klass, rb_mEnumerable); | 809 rb_include_module(klass, rb_mEnumerable); |
808 } | 810 } |
OLD | NEW |