From 052cb25f007c14ad1e751f53b3e31098d4b1407c Mon Sep 17 00:00:00 2001
From: Sokolov Yura <funny.falcon@gmail.com>
Date: Wed, 14 Dec 2011 12:35:36 +0400
Subject: [PATCH 1/3] Keep LOADED_FEATURES sorted by filename without
 extention for faster lookup on require.

---
 load.c |  183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 179 insertions(+), 4 deletions(-)

diff --git a/load.c b/load.c
index d36285f..ad72ba2 100644
--- a/load.c
+++ b/load.c
@@ -18,6 +18,7 @@
 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
 #endif
 
+static int sorted_loaded_features = 1;
 
 static const char *const loadable_ext[] = {
     ".rb", DLEXT,
@@ -129,6 +130,10 @@ struct loaded_feature_searching {
     return ST_STOP;
 }
 
+static int rb_feature_first_equal_or_greater(VALUE, const char *, long);
+static int rb_stop_search_feature(VALUE, const char *, long);
+static int feature_basename_length(const char *, long);
+
 static int
 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
 {
@@ -151,8 +156,10 @@ struct loaded_feature_searching {
 	type = 0;
     }
     features = get_loaded_features();
-    for (i = 0; i < RARRAY_LEN(features); ++i) {
+    i = rb_feature_first_equal_or_greater(features, feature, len);
+    for (; i < RARRAY_LEN(features); ++i) {
 	v = RARRAY_PTR(features)[i];
+	if (rb_stop_search_feature(v, feature, len)) break;
 	f = StringValuePtr(v);
 	if ((n = RSTRING_LEN(v)) < len) continue;
 	if (strncmp(f, feature, len) != 0) {
@@ -176,7 +183,7 @@ struct loaded_feature_searching {
 	}
     }
     loading_tbl = get_loading_table();
-    if (loading_tbl) {
+    if (loading_tbl && loading_tbl->num_entries > 0) {
 	f = 0;
 	if (!expanded) {
 	    struct loaded_feature_searching fs;
@@ -251,6 +258,174 @@ struct loaded_feature_searching {
     return FALSE;
 }
 
+static int
+feature_basename_length(const char *feature, long flen)
+{
+    if (sorted_loaded_features) {
+	const char *ext;
+	for (ext = feature + (flen - 1); ext >= feature; ext--) {
+	    if (*ext == '.') return ext - feature;
+	    if (*ext == '/') return flen;
+	}
+	return flen;
+    } else {
+	return 0;
+    }
+}
+
+static int
+compare_feature_name(const char *left, long llen, const char *right, long rlen)
+{
+    int diff = 0;
+    while (llen-- && rlen--) {
+	diff = left[llen] - right[rlen];
+	if (diff) break;
+	if (left[llen] == '/') break;
+    }
+    return diff;
+}
+
+static int
+rb_compare_feature_name(VALUE loaded, const char *feature, long flen)
+{
+    const char *loaded_name = StringValuePtr(loaded);
+    long loaded_len = feature_basename_length(loaded_name, RSTRING_LEN(loaded));
+    return compare_feature_name(loaded_name, loaded_len, feature, flen);
+}
+
+/* used to find when equal features run out */
+static int
+rb_stop_search_feature(VALUE loaded, const char *feature, long flen)
+{
+    if (sorted_loaded_features)
+	return rb_compare_feature_name(loaded, feature, flen) > 0;
+    else
+	return FALSE;
+}
+
+/* returns first position to search feature from */
+static int
+rb_feature_first_equal_or_greater(VALUE features, const char *feature, long flen)
+{
+    if (sorted_loaded_features) {
+	int before = 0, first = RARRAY_LEN(features);
+	VALUE *values = RARRAY_PTR(features);
+	if (first == 0)
+	    return 0;
+	if (rb_compare_feature_name(values[0], feature, flen) >= 0)
+	    return 0;
+
+	while (first - before > 1) {
+	    int mid = (first + before) / 2;
+	    int cmp = rb_compare_feature_name(values[mid], feature, flen);
+	    if (cmp >= 0)
+		first = mid;
+	    else
+		before = mid;
+	}
+	return first;
+    } else {
+	return 0;
+    }
+}
+
+/* returns position to insert new feature in */
+static int
+rb_feature_first_greater(VALUE features, const char *feature, long flen)
+{
+    if (sorted_loaded_features) {
+	int before = 0, first = RARRAY_LEN(features);
+	VALUE *values = RARRAY_PTR(features);
+	if (first == 0)
+	    return 0;
+	if (rb_compare_feature_name(values[0], feature, flen) > 0)
+	    return 0;
+	if (rb_compare_feature_name(values[first-1], feature, flen) <= 0)
+	    return first;
+
+	while (first - before > 1) {
+	    int mid = (first + before) / 2;
+	    int cmp = rb_compare_feature_name(values[mid], feature, flen);
+	    if (cmp > 0)
+		first = mid;
+	    else
+		before = mid;
+	}
+	return first;
+    } else {
+	return RARRAY_LEN(features);
+    }
+}
+
+
+static VALUE
+rb_push_feature_1(VALUE features, VALUE feature)
+{
+    const char *fname = StringValuePtr(feature);
+    long flen = feature_basename_length(fname, RSTRING_LEN(feature));
+    int i = rb_feature_first_greater(features, fname, flen);
+    rb_ary_push(features, feature);
+    if ( i < RARRAY_LEN(features) - 1 ) {
+	MEMMOVE(RARRAY_PTR(features) + i + 1, RARRAY_PTR(features) + i,
+		VALUE, RARRAY_LEN(features) - i - 1);
+	RARRAY_PTR(features)[i] = feature;
+    }
+    return features;
+}
+
+static VALUE
+rb_push_feature_m(int argc, VALUE *argv, VALUE features)
+{
+    while (argc--) {
+	rb_push_feature_1(features, *argv++);
+    }
+    return features;
+}
+
+static VALUE
+rb_concat_features(VALUE features, VALUE add)
+{
+    add = rb_convert_type(add, T_ARRAY, "Array", "to_ary");
+    if (RARRAY_LEN(add)) {
+	rb_push_feature_m(RARRAY_LEN(add), RARRAY_PTR(add), features);
+    }
+    return features;
+}
+static const char *load_features_undefined_methods[] = {
+    "[]=", "reverse!", "rotate!", "sort!", "sort_by!",
+    "collect!", "map!", "shuffle!", "fill", "insert",
+    NULL
+};
+
+static VALUE
+rb_loaded_features_init(void)
+{
+    char *sorted_flag;
+    const char **name;
+    VALUE loaded_features = rb_ary_new();
+    VALUE loaded_features_c = rb_singleton_class(loaded_features);
+
+    sorted_flag = getenv("RUBY_LOADED_FEATURES_SORTED");
+    if (sorted_flag != NULL) {
+	int sorted_set = atoi(sorted_flag);
+	if (RTEST(ruby_verbose))
+	    fprintf(stderr, "sorted_loaded_features=%d (%d)\n", sorted_set, sorted_loaded_features);
+	sorted_loaded_features = sorted_set;
+    }
+
+    for(name = load_features_undefined_methods; *name; name++) {
+	rb_undef_method(loaded_features_c, *name);
+    }
+
+    if (sorted_loaded_features) {
+	rb_define_method(loaded_features_c, "<<", rb_push_feature_1, 1);
+	rb_define_method(loaded_features_c, "push", rb_push_feature_m, -1);
+	rb_define_method(loaded_features_c, "concat", rb_concat_features, 1);
+	rb_define_method(loaded_features_c, "unshift", rb_push_feature_m, -1);
+    }
+    return loaded_features;
+}
+
 static void
 rb_provide_feature(VALUE feature)
 {
@@ -258,7 +433,7 @@ struct loaded_feature_searching {
 	rb_raise(rb_eRuntimeError,
 		 "$LOADED_FEATURES is frozen; cannot append feature");
     }
-    rb_ary_push(get_loaded_features(), feature);
+    rb_push_feature_1(get_loaded_features(), feature);
 }
 
 void
@@ -792,7 +967,7 @@ struct loaded_feature_searching {
 
     rb_define_virtual_variable("$\"", get_loaded_features, 0);
     rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
-    vm->loaded_features = rb_ary_new();
+    vm->loaded_features = rb_loaded_features_init();
 
     rb_define_global_function("load", rb_f_load, -1);
     rb_define_global_function("require", rb_f_require, 1);
-- 
1.7.10


From 17d21b8ba0fcfe9baa7f2b27bed277b17740f5c0 Mon Sep 17 00:00:00 2001
From: Sokolov Yura <funny.falcon@gmail.com>
Date: Fri, 16 Dec 2011 12:33:58 +0400
Subject: [PATCH 2/3] little optimization

---
 load.c |    9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/load.c b/load.c
index ad72ba2..5ae302a 100644
--- a/load.c
+++ b/load.c
@@ -132,7 +132,6 @@ struct loaded_feature_searching {
 
 static int rb_feature_first_equal_or_greater(VALUE, const char *, long);
 static int rb_stop_search_feature(VALUE, const char *, long);
-static int feature_basename_length(const char *, long);
 
 static int
 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
@@ -262,12 +261,8 @@ struct loaded_feature_searching {
 feature_basename_length(const char *feature, long flen)
 {
     if (sorted_loaded_features) {
-	const char *ext;
-	for (ext = feature + (flen - 1); ext >= feature; ext--) {
-	    if (*ext == '.') return ext - feature;
-	    if (*ext == '/') return flen;
-	}
-	return flen;
+	const char *ext = strrchr(feature, '.');
+	return ext && !strchr(ext, '/') ? ext - feature : flen;
     } else {
 	return 0;
     }
-- 
1.7.10


From 444c615068a13cfc44e3651b29360d4dfd3e3bd8 Mon Sep 17 00:00:00 2001
From: Sokolov Yura <funny.falcon@gmail.com>
Date: Wed, 25 Jan 2012 16:16:45 +0400
Subject: [PATCH 3/3] fix 64bit issue

---
 load.c |   26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/load.c b/load.c
index 5ae302a..98b8222 100644
--- a/load.c
+++ b/load.c
@@ -130,8 +130,8 @@ struct loaded_feature_searching {
     return ST_STOP;
 }
 
-static int rb_feature_first_equal_or_greater(VALUE, const char *, long);
-static int rb_stop_search_feature(VALUE, const char *, long);
+static long rb_feature_first_equal_or_greater(VALUE, const char *, long);
+static int  rb_stop_search_feature(VALUE, const char *, long);
 
 static int
 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
@@ -257,7 +257,7 @@ struct loaded_feature_searching {
     return FALSE;
 }
 
-static int
+static long
 feature_basename_length(const char *feature, long flen)
 {
     if (sorted_loaded_features) {
@@ -299,11 +299,11 @@ struct loaded_feature_searching {
 }
 
 /* returns first position to search feature from */
-static int
+static long
 rb_feature_first_equal_or_greater(VALUE features, const char *feature, long flen)
 {
     if (sorted_loaded_features) {
-	int before = 0, first = RARRAY_LEN(features);
+	long before = 0, first = RARRAY_LEN(features);
 	VALUE *values = RARRAY_PTR(features);
 	if (first == 0)
 	    return 0;
@@ -311,8 +311,8 @@ struct loaded_feature_searching {
 	    return 0;
 
 	while (first - before > 1) {
-	    int mid = (first + before) / 2;
-	    int cmp = rb_compare_feature_name(values[mid], feature, flen);
+	    long mid = (first + before) / 2;
+	    long cmp = rb_compare_feature_name(values[mid], feature, flen);
 	    if (cmp >= 0)
 		first = mid;
 	    else
@@ -325,11 +325,11 @@ struct loaded_feature_searching {
 }
 
 /* returns position to insert new feature in */
-static int
+static long
 rb_feature_first_greater(VALUE features, const char *feature, long flen)
 {
     if (sorted_loaded_features) {
-	int before = 0, first = RARRAY_LEN(features);
+	long before = 0, first = RARRAY_LEN(features);
 	VALUE *values = RARRAY_PTR(features);
 	if (first == 0)
 	    return 0;
@@ -339,8 +339,8 @@ struct loaded_feature_searching {
 	    return first;
 
 	while (first - before > 1) {
-	    int mid = (first + before) / 2;
-	    int cmp = rb_compare_feature_name(values[mid], feature, flen);
+	    long mid = (first + before) / 2;
+	    long cmp = rb_compare_feature_name(values[mid], feature, flen);
 	    if (cmp > 0)
 		first = mid;
 	    else
@@ -358,7 +358,7 @@ struct loaded_feature_searching {
 {
     const char *fname = StringValuePtr(feature);
     long flen = feature_basename_length(fname, RSTRING_LEN(feature));
-    int i = rb_feature_first_greater(features, fname, flen);
+    long i = rb_feature_first_greater(features, fname, flen);
     rb_ary_push(features, feature);
     if ( i < RARRAY_LEN(features) - 1 ) {
 	MEMMOVE(RARRAY_PTR(features) + i + 1, RARRAY_PTR(features) + i,
@@ -369,7 +369,7 @@ struct loaded_feature_searching {
 }
 
 static VALUE
-rb_push_feature_m(int argc, VALUE *argv, VALUE features)
+rb_push_feature_m(long argc, VALUE *argv, VALUE features)
 {
     while (argc--) {
 	rb_push_feature_1(features, *argv++);
-- 
1.7.10

