Skip to content

Instantly share code, notes, and snippets.

@haileys
Last active December 24, 2015 13:39
Show Gist options
  • Save haileys/6806385 to your computer and use it in GitHub Desktop.
Save haileys/6806385 to your computer and use it in GitHub Desktop.
~/ruby char-immediate-value ruby-2.0.0-github λ cat x.rb
str = "hello"
p [str[0], str[0].object_id]
p [str[1], str[1].object_id]
p [str[2], str[2].object_id]
~/ruby char-immediate-value ruby-2.0.0-github λ ./miniruby x.rb
["h", 26652]
["e", 25884]
["l", 27676]
diff --git include/ruby/encoding.h include/ruby/encoding.h
index 1c5d8da..acddf7f 100644
--- include/ruby/encoding.h
+++ include/ruby/encoding.h
@@ -34,7 +34,10 @@ RUBY_SYMBOL_EXPORT_BEGIN
} while (0)
#define ENCODING_SET(obj,i) rb_enc_set_index((obj), (i))
-#define ENCODING_GET_INLINED(obj) (int)((RBASIC(obj)->flags & ENCODING_MASK)>>ENCODING_SHIFT)
+#define ENCODING_GET_INLINED(obj) ( \
+ IMMSTR_P(obj) ? 0 : \
+ (int)((RBASIC(obj)->flags & ENCODING_MASK)>>ENCODING_SHIFT))
+
#define ENCODING_GET(obj) \
(ENCODING_GET_INLINED(obj) != ENCODING_INLINE_MAX ? \
ENCODING_GET_INLINED(obj) : \
@@ -49,7 +52,9 @@ RUBY_SYMBOL_EXPORT_BEGIN
#define ENC_CODERANGE_7BIT ((int)FL_USER8)
#define ENC_CODERANGE_VALID ((int)FL_USER9)
#define ENC_CODERANGE_BROKEN ((int)(FL_USER8|FL_USER9))
-#define ENC_CODERANGE(obj) ((int)RBASIC(obj)->flags & ENC_CODERANGE_MASK)
+#define ENC_CODERANGE(obj) ( \
+ IMMSTR_P(obj) ? ENC_CODERANGE_7BIT : \
+ (int)RBASIC(obj)->flags & ENC_CODERANGE_MASK)
#define ENC_CODERANGE_ASCIIONLY(obj) (ENC_CODERANGE(obj) == ENC_CODERANGE_7BIT)
#define ENC_CODERANGE_SET(obj,cr) (RBASIC(obj)->flags = \
(RBASIC(obj)->flags & ~ENC_CODERANGE_MASK) | (cr))
diff --git include/ruby/ruby.h include/ruby/ruby.h
index d0ba1c2..ec9dfc3 100644
--- include/ruby/ruby.h
+++ include/ruby/ruby.h
@@ -355,6 +355,10 @@ rb_long2int_inline(long n)
#define ID2SYM(x) (((VALUE)(x)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG)
#define SYM2ID(x) RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT)
+#define IMMSTR_P(x) (((VALUE)(x)&~((~(VALUE)0)<<RUBY_SPECIAL_SHIFT))==STRING_FLAG)
+#define CHAR2IMM(x) (((VALUE)(x)<<RUBY_SPECIAL_SHIFT)|STRING_FLAG)
+#define IMM2CHAR(x) (char)RSHIFT((unsigned long)(x),RUBY_SPECIAL_SHIFT)
+
#ifndef USE_FLONUM
#if SIZEOF_VALUE >= SIZEOF_DOUBLE
#define USE_FLONUM 1
@@ -377,6 +381,7 @@ rb_long2int_inline(long n)
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
+...0001 1110 String (single character)
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
@@ -387,6 +392,7 @@ USE_FLONUM
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
+...0001 1100 String (single character)
...0000 0000 Qfalse 0x00 = 0
...0000 1000 Qnil 0x08 = 8
...0001 0100 Qtrue 0x14 = 20
@@ -406,6 +412,7 @@ enum ruby_special_consts {
RUBY_FLONUM_MASK = 0x03,
RUBY_FLONUM_FLAG = 0x02,
RUBY_SYMBOL_FLAG = 0x0c,
+ RUBY_STRING_FLAG = 0x1c,
RUBY_SPECIAL_SHIFT = 8
#else
RUBY_Qfalse = 0,
@@ -418,6 +425,7 @@ enum ruby_special_consts {
RUBY_FLONUM_MASK = 0x00, /* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
RUBY_FLONUM_FLAG = 0x02,
RUBY_SYMBOL_FLAG = 0x0e,
+ RUBY_SYMBOL_FLAG = 0x1e,
RUBY_SPECIAL_SHIFT = 8
#endif
};
@@ -433,6 +441,7 @@ enum ruby_special_consts {
#define FLONUM_FLAG RUBY_FLONUM_FLAG
#endif
#define SYMBOL_FLAG RUBY_SYMBOL_FLAG
+#define STRING_FLAG RUBY_STRING_FLAG
#define RTEST(v) !(((VALUE)(v) & ~Qnil) == 0)
#define NIL_P(v) !((VALUE)(v) != Qnil)
@@ -836,22 +845,26 @@ struct RString {
(long)((RBASIC(str)->flags >> RSTRING_EMBED_LEN_SHIFT) & \
(RSTRING_EMBED_LEN_MASK >> RSTRING_EMBED_LEN_SHIFT))
#define RSTRING_LEN(str) \
- (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
- RSTRING_EMBED_LEN(str) : \
- RSTRING(str)->as.heap.len)
+ (IMMSTR_P(str) ? \
+ 1 : \
+ (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
+ RSTRING_EMBED_LEN(str) : \
+ RSTRING(str)->as.heap.len))
#define RSTRING_PTR(str) \
- (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
- RSTRING(str)->as.ary : \
- RSTRING(str)->as.heap.ptr)
+ (IMMSTR_P(str) ? \
+ ((char*)&(str) + 1) : \
+ (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
+ RSTRING(str)->as.ary : \
+ RSTRING(str)->as.heap.ptr))
#define RSTRING_END(str) \
- (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
- (RSTRING(str)->as.ary + RSTRING_EMBED_LEN(str)) : \
- (RSTRING(str)->as.heap.ptr + RSTRING(str)->as.heap.len))
+ (IMMSTR_P(str) ? \
+ ((char*)&(str) + 2) : \
+ (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
+ (RSTRING(str)->as.ary + RSTRING_EMBED_LEN(str)) : \
+ (RSTRING(str)->as.heap.ptr + RSTRING(str)->as.heap.len)))
#define RSTRING_LENINT(str) rb_long2int(RSTRING_LEN(str))
#define RSTRING_GETMEM(str, ptrvar, lenvar) \
- (!(RBASIC(str)->flags & RSTRING_NOEMBED) ? \
- ((ptrvar) = RSTRING(str)->as.ary, (lenvar) = RSTRING_EMBED_LEN(str)) : \
- ((ptrvar) = RSTRING(str)->as.heap.ptr, (lenvar) = RSTRING(str)->as.heap.len))
+ ((ptrvar) = RSTRING_PTR(str), (lenvar) = RSTRING_LEN(str))
#define RARRAY_EMBED_LEN_MAX 3
struct RArray {
@@ -1170,7 +1183,7 @@ struct RBignum {
RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT; \
} while (0)
-#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):(FIXNUM_P(x)||FLONUM_P(x)||SYMBOL_P(x))))
+#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):(FIXNUM_P(x)||FLONUM_P(x)||SYMBOL_P(x)||IMMSTR_P(x))))
#define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE)
#if USE_RGENGC
@@ -1603,6 +1616,7 @@ rb_class_of(VALUE obj)
if (FLONUM_P(obj)) return rb_cFloat;
if (obj == Qtrue) return rb_cTrueClass;
if (SYMBOL_P(obj)) return rb_cSymbol;
+ if (IMMSTR_P(obj)) return rb_cString;
}
else if (!RTEST(obj)) {
if (obj == Qnil) return rb_cNilClass;
@@ -1619,6 +1633,7 @@ rb_type(VALUE obj)
if (FLONUM_P(obj)) return T_FLOAT;
if (obj == Qtrue) return T_TRUE;
if (SYMBOL_P(obj)) return T_SYMBOL;
+ if (IMMSTR_P(obj)) return T_STRING;
if (obj == Qundef) return T_UNDEF;
}
else if (!RTEST(obj)) {
@@ -1637,6 +1652,7 @@ rb_type(VALUE obj)
((type) == T_NIL) ? ((obj) == Qnil) : \
((type) == T_UNDEF) ? ((obj) == Qundef) : \
((type) == T_SYMBOL) ? SYMBOL_P(obj) : \
+ ((type) == T_STRING && IMMSTR_P(obj)) ? 1 : \
((type) == T_FLOAT) ? RB_FLOAT_TYPE_P(obj) : \
(!SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == (type)))
diff --git numeric.c numeric.c
index 6979b21..bb1ccee 100644
--- numeric.c
+++ numeric.c
@@ -3256,11 +3256,13 @@ bit_coerce(VALUE *x, VALUE *y, int err)
do_coerce(x, y, err);
if (!FIXNUM_P(*x) && !RB_TYPE_P(*x, T_BIGNUM)
&& !FIXNUM_P(*y) && !RB_TYPE_P(*y, T_BIGNUM)) {
+ VALUE y_str;
if (!err) return FALSE;
+ y_str = rb_inspect(*y);
rb_raise(rb_eTypeError,
"%s can't be coerced into %s for bitwise arithmetic",
rb_special_const_p(*y) ?
- RSTRING_PTR(rb_inspect(*y)) : rb_obj_classname(*y),
+ RSTRING_PTR(y_str) : rb_obj_classname(*y),
rb_obj_classname(*x));
}
}
diff --git string.c string.c
index 7bf4006..bcb48ce 100644
--- string.c
+++ string.c
@@ -1879,6 +1879,9 @@ rb_str_substr(VALUE str, long beg, long len)
char *p = rb_str_subpos(str, beg, &len);
if (!p) return Qnil;
+ if (len == 1 && ENCODING_GET(str) == ENCINDEX_UTF_8 || ENCODING_GET(str) == ENCINDEX_ASCII) {
+ return CHAR2IMM(*p);
+ }
if (len > RSTRING_EMBED_LEN_MAX && p + len == RSTRING_END(str)) {
str2 = rb_str_new4(str);
str2 = str_new3(rb_obj_class(str2), str2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment