Skip to content

Instantly share code, notes, and snippets.

@soba1104
Created February 12, 2012 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soba1104/1805919 to your computer and use it in GitHub Desktop.
Save soba1104/1805919 to your computer and use it in GitHub Desktop.
Index: load.c
===================================================================
--- load.c (revision 34564)
+++ load.c (working copy)
@@ -8,6 +8,96 @@
#include "dln.h"
#include "eval_intern.h"
+struct expander {
+ VALUE hash;
+};
+
+struct expander_alive_values {
+ VALUE *ptr;
+ long len;
+};
+
+static struct expander *expander;
+
+static int
+expander_collect_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ struct expander_alive_values *alive_values = (void*)arg;
+ long i;
+
+ /* delete dead values using information in the alive_values */
+ for (i = 0; i < alive_values->len; i++) {
+ if (alive_values->ptr[i] == (VALUE)value) {
+ /* value is alive */
+ return ST_CONTINUE;
+ }
+ }
+ /* value is dead */
+ return ST_DELETE;
+}
+
+static void
+expander_collect(struct expander *e)
+{
+ st_table *st = RHASH(e->hash)->ntbl;
+ VALUE load_path = rb_get_load_path();
+ struct expander_alive_values alive_values;
+ VALUE *ptr = ALLOCA_N(VALUE, RARRAY_LEN(load_path));
+ long i, len = 0;
+
+ /* remember alive values */
+ for (i = 0; i < RARRAY_LEN(load_path); i++) {
+ /* alive values can be found by rb_hash_lookup2 */
+ VALUE key = RARRAY_PTR(load_path)[i];
+ VALUE value = rb_hash_lookup2(e->hash, key, Qfalse);
+ if (RTEST(value)) {
+ ptr[len] = value;
+ len++;
+ }
+ }
+ alive_values.ptr = ptr;
+ alive_values.len = len;
+ st_foreach(st, expander_collect_i, (st_data_t)&alive_values);
+}
+
+#define EXPANDER_COLLECTION_SPAN 10
+static void
+expander_mark(void *ptr)
+{
+ struct expander *e = ptr;
+ static int count = 0;
+
+ if (!e) return;
+ rb_gc_mark(e->hash);
+ if (++count < EXPANDER_COLLECTION_SPAN) return;
+ count = 0;
+ /* do collection in EXPANDER_COLLECTION_SPAN times once */
+ expander_collect(e);
+}
+
+static void
+expander_free(void *p)
+{
+ if (p) xfree(p);
+}
+
+static const rb_data_type_t expander_data_type = {
+ "expander",
+ {expander_mark, expander_free, NULL,},
+};
+
+static VALUE
+expander_alloc(VALUE klass)
+{
+ VALUE obj;
+ struct expander *e;
+
+ obj = TypedData_Make_Struct(klass, struct expander, &expander_data_type, e);
+ e->hash = rb_hash_new();
+
+ return obj;
+}
+
VALUE ruby_dln_librefs;
#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
@@ -43,8 +133,18 @@
ary = rb_ary_new2(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
+#if 0
VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
rb_str_freeze(path);
+#else
+ VALUE orig = RARRAY_PTR(load_path)[i];
+ VALUE path = rb_hash_lookup2(expander->hash, orig, Qfalse);
+ if (!RTEST(path)) {
+ path = rb_file_expand_path(orig, Qnil);
+ rb_str_freeze(path);
+ rb_hash_aset(expander->hash, orig, path);
+ }
+#endif
rb_ary_push(ary, path);
}
rb_obj_freeze(ary);
@@ -784,6 +884,9 @@
rb_vm_t *vm = GET_VM();
static const char var_load_path[] = "$:";
ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
+ VALUE expander_parent = rb_class_new(rb_cObject);
+ VALUE rb_cLoadPathExpander = rb_define_class_under(expander_parent, "Expander", rb_cObject);
+ VALUE expander_value;
rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
rb_alias_variable(rb_intern("$-I"), id_load_path);
@@ -804,4 +907,10 @@
ruby_dln_librefs = rb_ary_new();
rb_gc_register_mark_object(ruby_dln_librefs);
+
+ rb_define_alloc_func(rb_cLoadPathExpander, expander_alloc);
+ expander_value = rb_obj_alloc(rb_cLoadPathExpander);
+ rb_gc_register_mark_object(expander_parent);
+ rb_gc_register_mark_object(expander_value);
+ expander = DATA_PTR(expander_value);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment