ext/slim_attrib_ext.c in slim-attributes-0.6.6 vs ext/slim_attrib_ext.c in slim-attributes-0.7.1

- old
+ new

@@ -16,11 +16,12 @@ #define GetMysqlRes(obj) (Check_Type(obj, T_DATA), ((struct mysql_res*)DATA_PTR(obj))->res) #define GetCharPtr(obj) (Check_Type(obj, T_DATA), (char*)DATA_PTR(obj)) #define GetCharStarPtr(obj) (Check_Type(obj, T_DATA), (char**)DATA_PTR(obj)) VALUE cRowHash, cClass; -ID pointers_id, row_info_id, field_indexes_id, real_hash_id, to_hash_id; +ID pointers_id, row_info_id, field_indexes_id, real_hash_id, to_hash_id, sq_parens_id, + sq_parens_equal_id, has_key_id; #define MAX_CACHED_COLUMN_IDS 40 ID column_ids[MAX_CACHED_COLUMN_IDS]; // from mysql/ruby @@ -28,12 +29,12 @@ MYSQL_RES* res; char freed; }; // row info -#define SLIM_IS_NULL (char)0x01 -#define SLIM_IS_SET (char)0x02 +#define SLIM_IS_NULL 0x01 +#define SLIM_IS_SET 0x02 #define GET_COL_IV_ID(str, cnum) (cnum < MAX_CACHED_COLUMN_IDS ? column_ids[cnum] : (sprintf(str, "@col_%ld", cnum), rb_intern(str))) #define REAL_HASH_EXISTS NIL_P(field_indexes = rb_ivar_get(obj, field_indexes_id)) @@ -101,11 +102,11 @@ char *row_info, **pointers, *start, col_name[16]; ID col_id; long col_number = FIX2LONG(index); unsigned int length; row_info = GetCharPtr(rb_ivar_get(obj, row_info_id)) + col_number; // flags for this column - if (*row_info == SLIM_IS_NULL) return Qnil; // return nil if null from db + if (*row_info & SLIM_IS_NULL) return Qnil; // return nil if null from db col_id = GET_COL_IV_ID(col_name, col_number); if (*row_info == SLIM_IS_SET) return rb_ivar_get(obj, col_id); // was made to a string already pointers = GetCharStarPtr(rb_ivar_get(obj, pointers_id)); // find the data and make ruby string start = pointers[col_number]; length = pointers[col_number + 1] - start; @@ -116,16 +117,20 @@ } // This is the [] method of the row data object. // It checks for a real hash, but if none exists it will call fetch_by_index static VALUE slim_fetch(VALUE obj, VALUE name) { - VALUE field_indexes, hash_lookup; + VALUE field_indexes, hash_lookup, real_hash; - if (REAL_HASH_EXISTS) return rb_hash_aref(rb_ivar_get(obj, real_hash_id), name); + if (REAL_HASH_EXISTS) return rb_funcall(rb_ivar_get(obj, real_hash_id), sq_parens_id, 1, name); hash_lookup = rb_hash_aref(field_indexes, name); - if (NIL_P(hash_lookup)) return Qnil; + if (NIL_P(hash_lookup)) { + real_hash = rb_ivar_get(obj, real_hash_id); + if (NIL_P(real_hash)) return Qnil; + return rb_funcall(real_hash, sq_parens_id, 1, name); + } return fetch_by_index(obj, hash_lookup); } // This is the []= method of the row data object. // It either operates on the real hash if it exists, or sets the appropriate @@ -134,14 +139,14 @@ VALUE field_indexes, hash_lookup; long col_number; char col_name[16]; ID col_id; - if (REAL_HASH_EXISTS) return rb_hash_aset(rb_ivar_get(obj, real_hash_id), name, val); + if (REAL_HASH_EXISTS) return rb_funcall(rb_ivar_get(obj, real_hash_id), sq_parens_equal_id, 2, name, val); hash_lookup = rb_hash_aref(field_indexes, name); - if (NIL_P(hash_lookup)) return rb_hash_aset(rb_funcall(obj, to_hash_id, 0), name, val); + if (NIL_P(hash_lookup)) return rb_funcall(rb_funcall(obj, to_hash_id, 0), sq_parens_equal_id, 2, name, val); col_number = FIX2LONG(hash_lookup); col_id = GET_COL_IV_ID(col_name, col_number); rb_ivar_set(obj, col_id, val); GetCharPtr(rb_ivar_get(obj, row_info_id))[col_number] = SLIM_IS_SET; return val; @@ -182,19 +187,24 @@ // This is the has_key? method of the row data object. // Calls to model property methods in AR cause a call to has_key?, so it // is implemented here in C for speed. static VALUE has_key(VALUE obj, VALUE name) { - VALUE field_indexes; + VALUE field_indexes, real_hash; #ifdef RHASH_TBL if (REAL_HASH_EXISTS) return (st_lookup(RHASH_TBL(rb_ivar_get(obj, real_hash_id)), name, 0) ? Qtrue : Qfalse); - else return (st_lookup(RHASH_TBL(field_indexes), name, 0) ? Qtrue : Qfalse); + else if (st_lookup(RHASH_TBL(field_indexes), name, 0)) return Qtrue; #else if (REAL_HASH_EXISTS) return (st_lookup(RHASH(rb_ivar_get(obj, real_hash_id))->tbl, name, 0) ? Qtrue : Qfalse); - else return (st_lookup(RHASH(field_indexes)->tbl, name, 0) ? Qtrue : Qfalse); + else if (st_lookup(RHASH(field_indexes)->tbl, name, 0)) return Qtrue; #endif + else { + real_hash = rb_ivar_get(obj, real_hash_id); + if (NIL_P(real_hash)) return Qfalse; + return rb_funcall(real_hash, has_key_id, 1, name); + } } void Init_slim_attrib_ext() { int i; char col_name[16]; @@ -208,16 +218,21 @@ // set up methods rb_define_private_method(cRowHash, "fetch_by_index", (VALUE(*)(ANYARGS))fetch_by_index, 1); rb_define_method(cRowHash, "[]", (VALUE(*)(ANYARGS))slim_fetch, 1); rb_define_method(cRowHash, "[]=", (VALUE(*)(ANYARGS))set_element, 2); rb_define_method(cRowHash, "dup", (VALUE(*)(ANYARGS))slim_dup, 0); - rb_define_method(cRowHash, "has_key?", (VALUE(*)(ANYARGS))has_key, 1); + rb_define_method(cRowHash, "has_key?", (VALUE(*)(ANYARGS))has_key, 1); + rb_define_method(cRowHash, "accessed_keys", (VALUE(*)(ANYARGS))accessed_keys, 0); + // set up some symbols that we will need pointers_id = rb_intern("@pointers"); row_info_id = rb_intern("@row_info"); field_indexes_id = rb_intern("@field_indexes"); real_hash_id = rb_intern("@real_hash"); to_hash_id = rb_intern("to_hash"); + sq_parens_id = rb_intern("[]"); + sq_parens_equal_id = rb_intern("[]="); + has_key_id = rb_intern("has_key?"); for(i=0; i < MAX_CACHED_COLUMN_IDS; i++) { sprintf(col_name, "@col_%d", i); column_ids[i] = rb_intern(col_name); } }