mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #3340 from k0kubun/object-freeze
Implement Object#freeze
This commit is contained in:
@@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
|
||||
}
|
||||
|
||||
// TODO: figure out where to put user flags
|
||||
#define MRB_FLAG_IS_FROZEN (1 << 18)
|
||||
#define MRB_FLAG_IS_PREPENDED (1 << 19)
|
||||
#define MRB_FLAG_IS_ORIGIN (1 << 20)
|
||||
#define MRB_CLASS_ORIGIN(c) do {\
|
||||
|
||||
@@ -22,6 +22,10 @@ struct RBasic {
|
||||
};
|
||||
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v)))
|
||||
|
||||
#define RBASIC_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN)
|
||||
#define RBASIC_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN)
|
||||
#define RBASIC_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN)
|
||||
|
||||
struct RObject {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct iv_tbl *iv;
|
||||
|
||||
@@ -62,10 +62,6 @@ struct RString {
|
||||
#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE)
|
||||
#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE)
|
||||
|
||||
#define RSTR_FROZEN_P(s) ((s)->flags & MRB_STR_FROZEN)
|
||||
#define RSTR_SET_FROZEN_FLAG(s) ((s)->flags |= MRB_STR_FROZEN)
|
||||
#define RSTR_UNSET_FROZEN_FLAG(s) ((s)->flags &= ~MRB_STR_FROZEN)
|
||||
|
||||
/*
|
||||
* Returns a pointer from a Ruby string
|
||||
*/
|
||||
@@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
|
||||
|
||||
#define MRB_STR_SHARED 1
|
||||
#define MRB_STR_NOFREE 2
|
||||
#define MRB_STR_FROZEN 4
|
||||
#define MRB_STR_NO_UTF 8
|
||||
#define MRB_STR_EMBED 16
|
||||
#define MRB_STR_EMBED_LEN_MASK 0x3e0
|
||||
|
||||
@@ -108,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
|
||||
static void
|
||||
ary_modify(mrb_state *mrb, struct RArray *a)
|
||||
{
|
||||
if (RBASIC_FROZEN_P(a)) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array");
|
||||
}
|
||||
|
||||
if (ARY_SHARED_P(a)) {
|
||||
mrb_shared_array *shared = a->aux.shared;
|
||||
|
||||
|
||||
+5
-2
@@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
|
||||
static inline mrb_value
|
||||
mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
|
||||
{
|
||||
if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) {
|
||||
if (mrb_string_p(key) && !RBASIC_FROZEN_P(mrb_str_ptr(key))) {
|
||||
key = mrb_str_dup(mrb, key);
|
||||
RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key));
|
||||
RBASIC_SET_FROZEN_FLAG(mrb_str_ptr(key));
|
||||
}
|
||||
return key;
|
||||
}
|
||||
@@ -278,6 +278,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
|
||||
static void
|
||||
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
if (RBASIC_FROZEN_P(mrb_hash_ptr(hash))) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash");
|
||||
}
|
||||
mrb_hash_tbl(mrb, hash);
|
||||
}
|
||||
|
||||
|
||||
@@ -450,6 +450,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
|
||||
return mrb_obj_extend(mrb, argc, argv, self);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_obj_freeze(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RBasic *b = mrb_basic_ptr(self);
|
||||
|
||||
RBASIC_SET_FROZEN_FLAG(b);
|
||||
return self;
|
||||
}
|
||||
|
||||
/* 15.3.1.3.15 */
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -1124,6 +1133,7 @@ mrb_init_kernel(mrb_state *mrb)
|
||||
mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */
|
||||
mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */
|
||||
mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */
|
||||
mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */
|
||||
mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */
|
||||
mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */
|
||||
|
||||
+2
-13
@@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
|
||||
static void
|
||||
check_frozen(mrb_state *mrb, struct RString *s)
|
||||
{
|
||||
if (RSTR_FROZEN_P(s)) {
|
||||
if (RBASIC_FROZEN_P(s)) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
|
||||
}
|
||||
}
|
||||
@@ -700,15 +700,6 @@ mrb_str_modify(mrb_state *mrb, struct RString *s)
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_str_freeze(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
struct RString *s = mrb_str_ptr(str);
|
||||
|
||||
RSTR_SET_FROZEN_FLAG(s);
|
||||
return str;
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len)
|
||||
{
|
||||
@@ -2217,7 +2208,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
|
||||
char *p = RSTR_PTR(ps);
|
||||
|
||||
if (!p || p[len] != '\0') {
|
||||
if (RSTR_FROZEN_P(ps)) {
|
||||
if (RBASIC_FROZEN_P(ps)) {
|
||||
*ptr = str = mrb_str_dup(mrb, str);
|
||||
ps = mrb_str_ptr(str);
|
||||
}
|
||||
@@ -2746,8 +2737,6 @@ mrb_init_string(mrb_state *mrb)
|
||||
mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */
|
||||
mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */
|
||||
mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -373,3 +373,10 @@ assert("Array#rindex") do
|
||||
$a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new]
|
||||
assert_equal 0, $a.rindex(1)
|
||||
end
|
||||
|
||||
assert('Array#freeze') do
|
||||
a = [].freeze
|
||||
assert_raise(RuntimeError) do
|
||||
a[0] = 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -366,3 +366,10 @@ assert('Hash#rehash') do
|
||||
h.rehash
|
||||
assert_equal("b", h[[:b]])
|
||||
end
|
||||
|
||||
assert('Hash#freeze') do
|
||||
h = {}.freeze
|
||||
assert_raise(RuntimeError) do
|
||||
h[:a] = 'b'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -257,6 +257,11 @@ assert('Kernel#extend works on toplevel', '15.3.1.3.13') do
|
||||
assert_true respond_to?(:test_method)
|
||||
end
|
||||
|
||||
assert('Kernel#freeze') do
|
||||
obj = Object.new
|
||||
assert_equal obj, obj.freeze
|
||||
end
|
||||
|
||||
assert('Kernel#global_variables', '15.3.1.3.14') do
|
||||
assert_equal Array, global_variables.class
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user