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 VALUE table_key(Map* self, VALUE key, | 66 static void 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 key = native_slot_encode_and_freeze_string(self->key_type, key); | 75 native_slot_validate_string_encoding(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; | |
98 } | 96 } |
99 | 97 |
100 static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { | 98 static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { |
101 switch (self->key_type) { | 99 switch (self->key_type) { |
102 case UPB_TYPE_BYTES: | 100 case UPB_TYPE_BYTES: |
103 case UPB_TYPE_STRING: { | 101 case UPB_TYPE_STRING: { |
104 VALUE ret = rb_str_new(buf, length); | 102 VALUE ret = rb_str_new(buf, length); |
105 rb_enc_associate(ret, | 103 rb_enc_associate(ret, |
106 (self->key_type == UPB_TYPE_BYTES) ? | 104 (self->key_type == UPB_TYPE_BYTES) ? |
107 kRubyString8bitEncoding : kRubyStringUtf8Encoding); | 105 kRubyString8bitEncoding : kRubyStringUtf8Encoding); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 * Accesses the element at the given key. Throws an exception if the key type is | 350 * Accesses the element at the given key. Throws an exception if the key type is |
353 * incorrect. Returns nil when the key is not present in the map. | 351 * incorrect. Returns nil when the key is not present in the map. |
354 */ | 352 */ |
355 VALUE Map_index(VALUE _self, VALUE key) { | 353 VALUE Map_index(VALUE _self, VALUE key) { |
356 Map* self = ruby_to_Map(_self); | 354 Map* self = ruby_to_Map(_self); |
357 | 355 |
358 char keybuf[TABLE_KEY_BUF_LENGTH]; | 356 char keybuf[TABLE_KEY_BUF_LENGTH]; |
359 const char* keyval = NULL; | 357 const char* keyval = NULL; |
360 size_t length = 0; | 358 size_t length = 0; |
361 upb_value v; | 359 upb_value v; |
362 key = table_key(self, key, keybuf, &keyval, &length); | 360 table_key(self, key, keybuf, &keyval, &length); |
363 | 361 |
364 if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { | 362 if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { |
365 void* mem = value_memory(&v); | 363 void* mem = value_memory(&v); |
366 return native_slot_get(self->value_type, self->value_type_class, mem); | 364 return native_slot_get(self->value_type, self->value_type_class, mem); |
367 } else { | 365 } else { |
368 return Qnil; | 366 return Qnil; |
369 } | 367 } |
370 } | 368 } |
371 | 369 |
372 /* | 370 /* |
373 * call-seq: | 371 * call-seq: |
374 * Map.[]=(key, value) => value | 372 * Map.[]=(key, value) => value |
375 * | 373 * |
376 * Inserts or overwrites the value at the given key with the given new value. | 374 * Inserts or overwrites the value at the given key with the given new value. |
377 * Throws an exception if the key type is incorrect. Returns the new value that | 375 * Throws an exception if the key type is incorrect. Returns the new value that |
378 * was just inserted. | 376 * was just inserted. |
379 */ | 377 */ |
380 VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { | 378 VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { |
381 Map* self = ruby_to_Map(_self); | 379 Map* self = ruby_to_Map(_self); |
382 | 380 |
383 char keybuf[TABLE_KEY_BUF_LENGTH]; | 381 char keybuf[TABLE_KEY_BUF_LENGTH]; |
384 const char* keyval = NULL; | 382 const char* keyval = NULL; |
385 size_t length = 0; | 383 size_t length = 0; |
386 upb_value v; | 384 upb_value v; |
387 void* mem; | 385 void* mem; |
388 key = table_key(self, key, keybuf, &keyval, &length); | 386 table_key(self, key, keybuf, &keyval, &length); |
389 | 387 |
390 mem = value_memory(&v); | 388 mem = value_memory(&v); |
391 native_slot_set(self->value_type, self->value_type_class, mem, value); | 389 native_slot_set(self->value_type, self->value_type_class, mem, value); |
392 | 390 |
393 // Replace any existing value by issuing a 'remove' operation first. | 391 // Replace any existing value by issuing a 'remove' operation first. |
394 upb_strtable_remove2(&self->table, keyval, length, NULL); | 392 upb_strtable_remove2(&self->table, keyval, length, NULL); |
395 if (!upb_strtable_insert2(&self->table, keyval, length, v)) { | 393 if (!upb_strtable_insert2(&self->table, keyval, length, v)) { |
396 rb_raise(rb_eRuntimeError, "Could not insert into table"); | 394 rb_raise(rb_eRuntimeError, "Could not insert into table"); |
397 } | 395 } |
398 | 396 |
399 // Ruby hashmap's :[]= method also returns the inserted value. | 397 // Ruby hashmap's :[]= method also returns the inserted value. |
400 return value; | 398 return value; |
401 } | 399 } |
402 | 400 |
403 /* | 401 /* |
404 * call-seq: | 402 * call-seq: |
405 * Map.has_key?(key) => bool | 403 * Map.has_key?(key) => bool |
406 * | 404 * |
407 * Returns true if the given key is present in the map. Throws an exception if | 405 * Returns true if the given key is present in the map. Throws an exception if |
408 * the key has the wrong type. | 406 * the key has the wrong type. |
409 */ | 407 */ |
410 VALUE Map_has_key(VALUE _self, VALUE key) { | 408 VALUE Map_has_key(VALUE _self, VALUE key) { |
411 Map* self = ruby_to_Map(_self); | 409 Map* self = ruby_to_Map(_self); |
412 | 410 |
413 char keybuf[TABLE_KEY_BUF_LENGTH]; | 411 char keybuf[TABLE_KEY_BUF_LENGTH]; |
414 const char* keyval = NULL; | 412 const char* keyval = NULL; |
415 size_t length = 0; | 413 size_t length = 0; |
416 key = table_key(self, key, keybuf, &keyval, &length); | 414 table_key(self, key, keybuf, &keyval, &length); |
417 | 415 |
418 if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { | 416 if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { |
419 return Qtrue; | 417 return Qtrue; |
420 } else { | 418 } else { |
421 return Qfalse; | 419 return Qfalse; |
422 } | 420 } |
423 } | 421 } |
424 | 422 |
425 /* | 423 /* |
426 * call-seq: | 424 * call-seq: |
427 * Map.delete(key) => old_value | 425 * Map.delete(key) => old_value |
428 * | 426 * |
429 * Deletes the value at the given key, if any, returning either the old value or | 427 * Deletes the value at the given key, if any, returning either the old value or |
430 * nil if none was present. Throws an exception if the key is of the wrong type. | 428 * nil if none was present. Throws an exception if the key is of the wrong type. |
431 */ | 429 */ |
432 VALUE Map_delete(VALUE _self, VALUE key) { | 430 VALUE Map_delete(VALUE _self, VALUE key) { |
433 Map* self = ruby_to_Map(_self); | 431 Map* self = ruby_to_Map(_self); |
434 | 432 |
435 char keybuf[TABLE_KEY_BUF_LENGTH]; | 433 char keybuf[TABLE_KEY_BUF_LENGTH]; |
436 const char* keyval = NULL; | 434 const char* keyval = NULL; |
437 size_t length = 0; | 435 size_t length = 0; |
438 upb_value v; | 436 upb_value v; |
439 key = table_key(self, key, keybuf, &keyval, &length); | 437 table_key(self, key, keybuf, &keyval, &length); |
440 | 438 |
441 if (upb_strtable_remove2(&self->table, keyval, length, &v)) { | 439 if (upb_strtable_remove2(&self->table, keyval, length, &v)) { |
442 void* mem = value_memory(&v); | 440 void* mem = value_memory(&v); |
443 return native_slot_get(self->value_type, self->value_type_class, mem); | 441 return native_slot_get(self->value_type, self->value_type_class, mem); |
444 } else { | 442 } else { |
445 return Qnil; | 443 return Qnil; |
446 } | 444 } |
447 } | 445 } |
448 | 446 |
449 /* | 447 /* |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
801 rb_define_method(klass, "delete", Map_delete, 1); | 799 rb_define_method(klass, "delete", Map_delete, 1); |
802 rb_define_method(klass, "clear", Map_clear, 0); | 800 rb_define_method(klass, "clear", Map_clear, 0); |
803 rb_define_method(klass, "length", Map_length, 0); | 801 rb_define_method(klass, "length", Map_length, 0); |
804 rb_define_method(klass, "dup", Map_dup, 0); | 802 rb_define_method(klass, "dup", Map_dup, 0); |
805 rb_define_method(klass, "==", Map_eq, 1); | 803 rb_define_method(klass, "==", Map_eq, 1); |
806 rb_define_method(klass, "hash", Map_hash, 0); | 804 rb_define_method(klass, "hash", Map_hash, 0); |
807 rb_define_method(klass, "inspect", Map_inspect, 0); | 805 rb_define_method(klass, "inspect", Map_inspect, 0); |
808 rb_define_method(klass, "merge", Map_merge, 1); | 806 rb_define_method(klass, "merge", Map_merge, 1); |
809 rb_include_module(klass, rb_mEnumerable); | 807 rb_include_module(klass, rb_mEnumerable); |
810 } | 808 } |
OLD | NEW |