Last active
December 24, 2015 13:39
-
-
Save haileys/6806385 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~/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] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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