summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c366
1 files changed, 145 insertions, 221 deletions
diff --git a/hash.c b/hash.c
index 608738aab5..c1cc13383b 100644
--- a/hash.c
+++ b/hash.c
@@ -71,10 +71,6 @@
#define HASH_DEBUG 0
#endif
-#if HASH_DEBUG
-#include "internal/gc.h"
-#endif
-
#define SET_DEFAULT(hash, ifnone) ( \
FL_UNSET_RAW(hash, RHASH_PROC_DEFAULT), \
RHASH_SET_IFNONE(hash, ifnone))
@@ -184,7 +180,7 @@ any_hash(VALUE a, st_index_t (*other_func)(VALUE))
hnum = rb_hash_start(hnum);
}
else {
- hnum = RSYMBOL(a)->hashval;
+ hnum = RSHIFT(RSYMBOL(a)->hashval, 1);
}
break;
case T_FIXNUM:
@@ -325,40 +321,35 @@ objid_hash(VALUE obj)
#endif
}
-/**
+/*
* call-seq:
- * obj.hash -> integer
- *
- * Generates an Integer hash value for this object. This function must have the
- * property that <code>a.eql?(b)</code> implies <code>a.hash == b.hash</code>.
- *
- * The hash value is used along with #eql? by the Hash class to determine if
- * two objects reference the same hash key. Any hash value that exceeds the
- * capacity of an Integer will be truncated before being used.
+ * hash -> integer
*
- * The hash value for an object may not be identical across invocations or
- * implementations of Ruby. If you need a stable identifier across Ruby
- * invocations and implementations you will need to generate one with a custom
- * method.
+ * Returns the integer hash value for +self+;
+ * has the property that if <tt>foo.eql?(bar)</tt>
+ * then <tt>foo.hash == bar.hash</tt>.
*
- * Certain core classes such as Integer use built-in hash calculations and
- * do not call the #hash method when used as a hash key.
+ * \Class Hash uses both #hash and #eql? to determine whether two objects
+ * used as hash keys are to be treated as the same key.
+ * A hash value that exceeds the capacity of an Integer is truncated before being used.
*
- * When implementing your own #hash based on multiple values, the best
- * practice is to combine the class and any values using the hash code of an
- * array:
+ * Many core classes override method Object#hash;
+ * other core classes (e.g., Integer) calculate the hash internally,
+ * and do not call the #hash method when used as a hash key.
*
- * For example:
+ * When implementing #hash for a user-defined class,
+ * best practice is to use Array#hash with the class name and the values
+ * that are important in the instance;
+ * this takes advantage of that method's logic for safely and efficiently
+ * generating a hash value:
*
* def hash
* [self.class, a, b, c].hash
* end
*
- * The reason for this is that the Array#hash method already has logic for
- * safely and efficiently combining multiple hash values.
- *--
- * \private
- *++
+ * The hash value may differ among invocations or implementations of Ruby.
+ * If you need stable hash-like identifiers across Ruby invocations and implementations,
+ * use a custom method to generate them.
*/
VALUE
rb_obj_hash(VALUE obj)
@@ -501,37 +492,6 @@ RHASH_AR_TABLE_BOUND(VALUE h)
#if HASH_DEBUG
#define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__)
-void
-rb_hash_dump(VALUE hash)
-{
- rb_obj_info_dump(hash);
-
- if (RHASH_AR_TABLE_P(hash)) {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
-
- fprintf(stderr, " size:%u bound:%u\n",
- RHASH_AR_TABLE_SIZE(hash), bound);
-
- for (i=0; i<bound; i++) {
- st_data_t k, v;
-
- if (!ar_cleared_entry(hash, i)) {
- char b1[0x100], b2[0x100];
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- k = pair->key;
- v = pair->val;
- fprintf(stderr, " %d key:%s val:%s hint:%02x\n", i,
- rb_raw_obj_info(b1, 0x100, k),
- rb_raw_obj_info(b2, 0x100, v),
- ar_hint(hash, i));
- }
- else {
- fprintf(stderr, " %d empty\n", i);
- }
- }
- }
-}
-
static VALUE
hash_verify_(VALUE hash, const char *file, int line)
{
@@ -882,8 +842,9 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
if (replace) {
(*replace)(&key, &val, arg, TRUE);
- // TODO: pair should be same as pair before.
- pair = RHASH_AR_TABLE_REF(hash, i);
+ // Pair should not have moved
+ HASH_ASSERT(pair == RHASH_AR_TABLE_REF(hash, i));
+
pair->key = (VALUE)key;
pair->val = (VALUE)val;
}
@@ -1300,7 +1261,6 @@ hash_ar_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
if (error) return ST_STOP;
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
- /* TODO: rehash check? rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); */
return hash_iter_status_check(status);
}
@@ -1312,13 +1272,8 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
if (error) return ST_STOP;
- st_table *tbl = RHASH_ST_TABLE(arg->hash);
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
- if (RHASH_ST_TABLE(arg->hash) != tbl) {
- rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
- }
-
return hash_iter_status_check(status);
}
@@ -1542,6 +1497,10 @@ rb_hash_new_capa(long capa)
static VALUE
hash_copy(VALUE ret, VALUE hash)
{
+ if (rb_hash_compare_by_id_p(hash)) {
+ rb_gc_register_pinning_obj(ret);
+ }
+
if (RHASH_AR_TABLE_P(hash)) {
if (RHASH_AR_TABLE_P(ret)) {
ar_copy(ret, hash);
@@ -1597,10 +1556,10 @@ VALUE
rb_hash_dup(VALUE hash)
{
const VALUE flags = RBASIC(hash)->flags;
- VALUE ret = hash_dup(hash, rb_obj_class(hash),
- flags & (FL_EXIVAR|RHASH_PROC_DEFAULT));
- if (flags & FL_EXIVAR)
- rb_copy_generic_ivar(ret, hash);
+ VALUE ret = hash_dup(hash, rb_obj_class(hash), flags & RHASH_PROC_DEFAULT);
+
+ rb_copy_generic_ivar(ret, hash);
+
return ret;
}
@@ -2920,7 +2879,7 @@ hash_aset(st_data_t *key, st_data_t *val, struct update_arg *arg, int existing)
VALUE
rb_hash_key_str(VALUE key)
{
- if (!RB_FL_ANY_RAW(key, FL_EXIVAR) && RBASIC_CLASS(key) == rb_cString) {
+ if (!rb_obj_gen_fields_p(key) && RBASIC_CLASS(key) == rb_cString) {
return rb_fstring(key);
}
else {
@@ -2995,6 +2954,14 @@ rb_hash_aset(VALUE hash, VALUE key, VALUE val)
* h = {foo: 0, bar: 1, baz: 2}
* h.replace({bat: 3, bam: 4}) # => {bat: 3, bam: 4}
*
+ * Also replaces the default value or proc of +self+ with the default value
+ * or proc of +other_hash+.
+ *
+ * h = {}
+ * other = Hash.new(:ok)
+ * h.replace(other)
+ * h.default # => :ok
+ *
* Related: see {Methods for Assigning}[rdoc-ref:Hash@Methods+for+Assigning].
*/
@@ -3612,24 +3579,24 @@ symbol_key_needs_quote(VALUE str)
if (first == '@' || first == '$' || first == '!') return true;
if (!at_char_boundary(s, s + len - 1, RSTRING_END(str), rb_enc_get(str))) return false;
switch (s[len - 1]) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '`':
- case '%':
- case '^':
- case '&':
- case '|':
- case ']':
- case '<':
- case '=':
- case '>':
- case '~':
- case '@':
- return true;
- default:
- return false;
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '`':
+ case '%':
+ case '^':
+ case '&':
+ case '|':
+ case ']':
+ case '<':
+ case '=':
+ case '>':
+ case '~':
+ case '@':
+ return true;
+ default:
+ return false;
}
}
@@ -3871,7 +3838,6 @@ rb_hash_values(VALUE hash)
}
rb_ary_set_len(values, size);
}
-
else {
rb_hash_foreach(hash, values_i, values);
}
@@ -4013,17 +3979,13 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
/*
* call-seq:
- * self == object -> true or false
- *
- * Returns whether +self+ and +object+ are equal.
+ * self == other -> true or false
*
- * Returns +true+ if all of the following are true:
- *
- * - +object+ is a +Hash+ object (or can be converted to one).
- * - +self+ and +object+ have the same keys (regardless of order).
- * - For each key +key+, <tt>self[key] == object[key]</tt>.
+ * Returns whether all of the following are true:
*
- * Otherwise, returns +false+.
+ * - +other+ is a +Hash+ object (or can be converted to one).
+ * - +self+ and +other+ have the same keys (regardless of order).
+ * - For each key +key+, <tt>self[key] == other[key]</tt>.
*
* Examples:
*
@@ -4655,7 +4617,7 @@ rb_hash_compact_bang(VALUE hash)
* returns +self+:
*
* By default, two keys are considered to be the same key
- * if and only if they are _equal_ objects (per method #==):
+ * if and only if they are _equal_ objects (per method #eql?):
*
* h = {}
* h['x'] = 0
@@ -4710,6 +4672,8 @@ rb_hash_compare_by_id(VALUE hash)
RHASH_ST_CLEAR(tmp);
}
+ rb_gc_register_pinning_obj(hash);
+
return hash;
}
@@ -4739,6 +4703,7 @@ rb_ident_hash_new(void)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, 0);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4747,6 +4712,7 @@ rb_ident_hash_new_with_size(st_index_t size)
{
VALUE hash = rb_hash_new();
hash_st_table_init(hash, &identhash, size);
+ rb_gc_register_pinning_obj(hash);
return hash;
}
@@ -4925,10 +4891,9 @@ hash_le(VALUE hash1, VALUE hash2)
/*
* call-seq:
- * self <= other_hash -> true or false
+ * self <= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a subset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1}
* h1 = {foo: 0, bar: 1, baz: 2}
@@ -4936,7 +4901,7 @@ hash_le(VALUE hash1, VALUE hash2)
* h0 <= h1 # => true
* h1 <= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4952,10 +4917,9 @@ rb_hash_le(VALUE hash, VALUE other)
/*
* call-seq:
- * self < other_hash -> true or false
+ * self < other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper subset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper subset of the entries of +other+:
*
* h = {foo: 0, bar: 1}
* h < {foo: 0, bar: 1, baz: 2} # => true # Proper subset.
@@ -4965,7 +4929,7 @@ rb_hash_le(VALUE hash, VALUE other)
* h < {foo: 0, bar: 1, baz: 2} # => false # Different key.
* h < {foo: 0, bar: 1, baz: 2} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -4981,10 +4945,9 @@ rb_hash_lt(VALUE hash, VALUE other)
/*
* call-seq:
- * self >= other_hash -> true or false
+ * self >= other -> true or false
*
- * Returns +true+ if the entries of +self+ are a superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a superset of the entries of +other+:
*
* h0 = {foo: 0, bar: 1, baz: 2}
* h1 = {foo: 0, bar: 1}
@@ -4992,7 +4955,7 @@ rb_hash_lt(VALUE hash, VALUE other)
* h0 >= h0 # => true
* h1 >= h0 # => false
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -5008,10 +4971,9 @@ rb_hash_ge(VALUE hash, VALUE other)
/*
* call-seq:
- * self > other_hash -> true or false
+ * self > other -> true or false
*
- * Returns +true+ if the entries of +self+ are a proper superset of the entries of +other_hash+,
- * +false+ otherwise:
+ * Returns whether the entries of +self+ are a proper superset of the entries of +other+:
*
* h = {foo: 0, bar: 1, baz: 2}
* h > {foo: 0, bar: 1} # => true # Proper superset.
@@ -5021,7 +4983,7 @@ rb_hash_ge(VALUE hash, VALUE other)
* h > {foo: 0, bar: 1} # => false # Different key.
* h > {foo: 0, bar: 1} # => false # Different value.
*
- * See {Hash Inclusion}[rdoc-ref:hash_inclusion.rdoc].
+ * See {Hash Inclusion}[rdoc-ref:language/hash_inclusion.rdoc].
*
* Raises TypeError if +other_hash+ is not a hash and cannot be converted to a hash.
*
@@ -5073,10 +5035,8 @@ rb_hash_deconstruct_keys(VALUE hash, VALUE keys)
static int
add_new_i(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
{
- VALUE *args = (VALUE *)arg;
if (existing) return ST_STOP;
- RB_OBJ_WRITTEN(args[0], Qundef, (VALUE)*key);
- RB_OBJ_WRITE(args[0], (VALUE *)val, args[1]);
+ *val = arg;
return ST_CONTINUE;
}
@@ -5088,22 +5048,25 @@ int
rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val)
{
st_table *tbl;
- int ret = 0;
- VALUE args[2];
- args[0] = hash;
- args[1] = val;
+ int ret = -1;
if (RHASH_AR_TABLE_P(hash)) {
- ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)args);
- if (ret != -1) {
- return ret;
+ ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)val);
+ if (ret == -1) {
+ ar_force_convert_table(hash, __FILE__, __LINE__);
}
- ar_force_convert_table(hash, __FILE__, __LINE__);
}
- tbl = RHASH_TBL_RAW(hash);
- return st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)args);
-
+ if (ret == -1) {
+ tbl = RHASH_TBL_RAW(hash);
+ ret = st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)val);
+ }
+ if (!ret) {
+ // Newly inserted
+ RB_OBJ_WRITTEN(hash, Qundef, key);
+ RB_OBJ_WRITTEN(hash, Qundef, val);
+ }
+ return ret;
}
static st_data_t
@@ -5170,8 +5133,7 @@ extern char **environ;
#define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
#endif
-#define ENV_LOCK() RB_VM_LOCK_ENTER()
-#define ENV_UNLOCK() RB_VM_LOCK_LEAVE()
+#define ENV_LOCKING() RB_VM_LOCKING()
static inline rb_encoding *
env_encoding(void)
@@ -5193,28 +5155,27 @@ env_enc_str_new(const char *ptr, long len, rb_encoding *enc)
}
static VALUE
-env_str_new(const char *ptr, long len)
+env_str_new(const char *ptr, long len, rb_encoding *enc)
{
- return env_enc_str_new(ptr, len, env_encoding());
+ return env_enc_str_new(ptr, len, enc);
}
static VALUE
-env_str_new2(const char *ptr)
+env_str_new2(const char *ptr, rb_encoding *enc)
{
if (!ptr) return Qnil;
- return env_str_new(ptr, strlen(ptr));
+ return env_str_new(ptr, strlen(ptr), enc);
}
static VALUE
getenv_with_lock(const char *name)
{
VALUE ret;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
const char *val = getenv(name);
- ret = env_str_new2(val);
+ ret = env_str_new2(val, enc);
}
- ENV_UNLOCK();
return ret;
}
@@ -5223,11 +5184,9 @@ has_env_with_lock(const char *name)
{
const char *val;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
val = getenv(name);
}
- ENV_UNLOCK();
return val ? true : false;
}
@@ -5477,13 +5436,11 @@ ruby_setenv(const char *name, const char *value)
*wvalue = L'\0';
}
- ENV_LOCK();
- {
+ ENV_LOCKING() {
/* Use _wputenv_s() instead of SetEnvironmentVariableW() to make sure
* special variables like "TZ" are interpret by libc. */
failed = _wputenv_s(wname, wvalue);
}
- ENV_UNLOCK();
ALLOCV_END(buf);
/* even if putenv() failed, clean up and try to delete the
@@ -5500,28 +5457,22 @@ ruby_setenv(const char *name, const char *value)
#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
if (value) {
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = setenv(name, value, 1);
}
- ENV_UNLOCK();
if (ret) rb_sys_fail_sprintf("setenv(%s)", name);
}
else {
#ifdef VOID_UNSETENV
- ENV_LOCK();
- {
+ ENV_LOCKING() {
unsetenv(name);
}
- ENV_UNLOCK();
#else
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = unsetenv(name);
}
- ENV_UNLOCK();
if (ret) rb_sys_fail_sprintf("unsetenv(%s)", name);
#endif
@@ -5544,8 +5495,7 @@ ruby_setenv(const char *name, const char *value)
snprintf(mem_ptr, mem_size, "%s=%s", name, value);
}
- ENV_LOCK();
- {
+ ENV_LOCKING() {
for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
if (!strncmp(str, name, len) && str[len] == '=') {
if (!in_origenv(str)) free(str);
@@ -5554,15 +5504,12 @@ ruby_setenv(const char *name, const char *value)
}
}
}
- ENV_UNLOCK();
if (value) {
int ret;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
ret = putenv(mem_ptr);
}
- ENV_UNLOCK();
if (ret) {
free(mem_ptr);
@@ -5573,8 +5520,7 @@ ruby_setenv(const char *name, const char *value)
size_t len;
int i;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
i = envix(name); /* where does it go? */
if (environ == origenviron) { /* need we copy environment? */
@@ -5615,7 +5561,6 @@ ruby_setenv(const char *name, const char *value)
finish:;
}
- ENV_UNLOCK();
#endif /* WIN32 */
}
@@ -5700,8 +5645,7 @@ env_keys(int raw)
rb_encoding *enc = raw ? 0 : rb_locale_encoding();
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -5715,7 +5659,6 @@ env_keys(int raw)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -5745,8 +5688,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
char **env;
long cnt = 0;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
env = GET_ENVIRON(environ);
for (; *env ; ++env) {
if (strchr(*env, '=')) {
@@ -5755,7 +5697,6 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return LONG2FIX(cnt);
}
@@ -5796,20 +5737,19 @@ env_values(void)
{
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, env_str_new2(s+1));
+ rb_ary_push(ary, env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -5890,21 +5830,20 @@ env_each_pair(VALUE ehash)
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, env_str_new(*env, s-*env));
- rb_ary_push(ary, env_str_new2(s+1));
+ rb_ary_push(ary, env_str_new(*env, s-*env, enc));
+ rb_ary_push(ary, env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
if (rb_block_pair_yield_optimizable()) {
for (i=0; i<RARRAY_LEN(ary); i+=2) {
@@ -6244,8 +6183,7 @@ env_inspect(VALUE _)
VALUE str = rb_str_buf_new2("{");
rb_encoding *enc = env_encoding();
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
const char *s = strchr(*env, '=');
@@ -6263,7 +6201,6 @@ env_inspect(VALUE _)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
rb_str_buf_cat2(str, "}");
@@ -6284,20 +6221,19 @@ env_to_a(VALUE _)
{
VALUE ary = rb_ary_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
- env_str_new2(s+1)));
+ rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env, enc),
+ env_str_new2(s+1, enc)));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ary;
}
@@ -6321,13 +6257,11 @@ env_size_with_lock(void)
{
int i = 0;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (env[i]) i++;
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return i;
}
@@ -6363,15 +6297,13 @@ env_empty_p(VALUE _)
{
bool empty = true;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
if (env[0] != 0) {
empty = false;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return RBOOL(empty);
}
@@ -6460,8 +6392,7 @@ env_has_value(VALUE dmy, VALUE obj)
VALUE ret = Qfalse;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -6476,7 +6407,6 @@ env_has_value(VALUE dmy, VALUE obj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return ret;
}
@@ -6503,8 +6433,7 @@ env_rassoc(VALUE dmy, VALUE obj)
VALUE result = Qnil;
- ENV_LOCK();
- {
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
@@ -6521,7 +6450,6 @@ env_rassoc(VALUE dmy, VALUE obj)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return result;
}
@@ -6548,15 +6476,15 @@ env_key(VALUE dmy, VALUE value)
StringValue(value);
VALUE str = Qnil;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s++) {
long len = strlen(s);
if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
- str = env_str_new(*env, s-*env-1);
+ str = env_str_new(*env, s-*env-1, enc);
break;
}
}
@@ -6564,7 +6492,6 @@ env_key(VALUE dmy, VALUE value)
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return str;
}
@@ -6574,20 +6501,19 @@ env_to_hash(void)
{
VALUE hash = rb_hash_new();
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) {
- rb_hash_aset(hash, env_str_new(*env, s-*env),
- env_str_new2(s+1));
+ rb_hash_aset(hash, env_str_new(*env, s-*env, enc),
+ env_str_new2(s+1, enc));
}
env++;
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
return hash;
}
@@ -6727,21 +6653,20 @@ env_shift(VALUE _)
VALUE result = Qnil;
VALUE key = Qnil;
- ENV_LOCK();
- {
+ rb_encoding *enc = env_encoding();
+ ENV_LOCKING() {
char **env = GET_ENVIRON(environ);
if (*env) {
const char *p = *env;
char *s = strchr(p, '=');
if (s) {
- key = env_str_new(p, s-p);
- VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
+ key = env_str_new(p, s-p, enc);
+ VALUE val = env_str_new2(getenv(RSTRING_PTR(key)), enc);
result = rb_assoc_new(key, val);
}
}
FREE_ENVIRON(environ);
}
- ENV_UNLOCK();
if (!NIL_P(key)) {
env_delete(key);
@@ -6955,7 +6880,7 @@ static const rb_data_type_t env_data_type = {
* A \Hash object maps each of its unique keys to a specific value.
*
* A hash has certain similarities to an Array, but:
-
+ *
* - An array index is always an integer.
* - A hash key can be (almost) any object.
*
@@ -7356,7 +7281,7 @@ static const rb_data_type_t env_data_type = {
* - #keys: Returns an array containing all keys in +self+.
* - #rassoc: Returns a 2-element array consisting of the key and value
* of the first-found entry having a given value.
- * - #values: Returns an array containing all values in +self+/
+ * - #values: Returns an array containing all values in +self+.
* - #values_at: Returns an array containing values for given keys.
*
* ==== Methods for Assigning
@@ -7405,7 +7330,6 @@ static const rb_data_type_t env_data_type = {
*
* ==== Methods for Transforming Keys and Values
*
- * - #flatten!: Returns +self+, flattened.
* - #invert: Returns a hash with the each key-value pair inverted.
* - #transform_keys: Returns a copy of +self+ with modified keys.
* - #transform_keys!: Modifies keys in +self+
@@ -7518,6 +7442,7 @@ Init_Hash(void)
rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1);
rb_cHash_empty_frozen = rb_hash_freeze(rb_hash_new());
+ RB_OBJ_SET_SHAREABLE(rb_cHash_empty_frozen);
rb_vm_register_global_object(rb_cHash_empty_frozen);
/* Document-class: ENV
@@ -7653,7 +7578,7 @@ Init_Hash(void)
*
* - ::assoc: Returns a 2-element array containing the name and value
* of the named environment variable if it exists:
- * - ::clone: Returns +ENV+ (and issues a warning).
+ * - ::clone: Raises an exception.
* - ::except: Returns a hash of all name/value pairs except those given.
* - ::fetch: Returns the value for the given name.
* - ::inspect: Returns the contents of +ENV+ as a string.
@@ -7687,8 +7612,7 @@ Init_Hash(void)
origenviron = environ;
envtbl = TypedData_Wrap_Struct(rb_cObject, &env_data_type, NULL);
rb_extend_object(envtbl, rb_mEnumerable);
- FL_SET_RAW(envtbl, RUBY_FL_SHAREABLE);
-
+ RB_OBJ_SET_SHAREABLE(envtbl);
rb_define_singleton_method(envtbl, "[]", rb_f_getenv, 1);
rb_define_singleton_method(envtbl, "fetch", env_fetch, -1);