void Err_throw_mess(VTable *vtable, CharBuf *message) { Err_Make_t make = METHOD_PTR(CERTIFY(vtable, VTABLE), Cfish_Err_Make); Err *err = (Err*)CERTIFY(make(NULL), ERR); Err_Cat_Mess(err, message); DECREF(message); Err_do_throw(err); }
static String* S_do_encode(Highlighter *self, String *text, CharBuf **encode_buf) { VTable *vtable = Highlighter_Get_VTable(self); Highlighter_Encode_t my_meth = (Highlighter_Encode_t)METHOD_PTR(vtable, LUCY_Highlighter_Encode); Highlighter_Encode_t orig_meth = (Highlighter_Encode_t)METHOD_PTR(HIGHLIGHTER, LUCY_Highlighter_Encode); if (my_meth != orig_meth) { return my_meth(self, text); } else { if (*encode_buf == NULL) { *encode_buf = CB_new(0); } return S_encode_entities(text, *encode_buf); } }
size_t Str_Hash_Sum_IMP(String *self) { size_t hashvalue = 5381; StringIterator *iter = STACK_ITER(self, 0); const StrIter_Next_t next = METHOD_PTR(STRINGITERATOR, CFISH_StrIter_Next); int32_t code_point; while (STR_OOB != (code_point = next(iter))) { hashvalue = ((hashvalue << 5) + hashvalue) ^ (size_t)code_point; } return hashvalue; }
int32_t CB_hash_sum(CharBuf *self) { uint32_t hashvalue = 5381; ZombieCharBuf *iterator = ZCB_WRAP(self); const CB_Nip_One_t nip_one = METHOD_PTR(iterator->vtable, Lucy_CB_Nip_One); while (iterator->size) { uint32_t code_point = (uint32_t)nip_one((CharBuf*)iterator); hashvalue = ((hashvalue << 5) + hashvalue) ^ code_point; } return (int32_t) hashvalue; }
void THROW(VTable *vtable, char *pattern, ...) { va_list args; Err_Make_t make = METHOD_PTR(CERTIFY(vtable, VTABLE), Lucy_Err_Make); Err *err = (Err*)CERTIFY(make(NULL), ERR); CharBuf *mess = Err_Get_Mess(err); va_start(args, pattern); CB_VCatF(mess, pattern, args); va_end(args); Err_do_throw(err); }
Obj* Hash_load(Hash *self, Obj *dump) { Hash *source = (Hash*)CERTIFY(dump, HASH); CharBuf *class_name = (CharBuf*)Hash_Fetch_Str(source, "_class", 6); UNUSED_VAR(self); // Assume that the presence of the "_class" key paired with a valid class // name indicates the output of a Dump rather than an ordinary Hash. */ if (class_name && CB_Is_A(class_name, CHARBUF)) { VTable *vtable = VTable_fetch_vtable(class_name); if (!vtable) { CharBuf *parent_class = VTable_find_parent_class(class_name); if (parent_class) { VTable *parent = VTable_singleton(parent_class, NULL); vtable = VTable_singleton(class_name, parent); DECREF(parent_class); } else { // TODO: Fix Hash_Load() so that it works with ordinary hash // keys named "_class". THROW(ERR, "Can't find class '%o'", class_name); } } // Dispatch to an alternate Load() method. if (vtable) { Obj_Load_t load = METHOD_PTR(vtable, Lucy_Obj_Load); if (load == Obj_load) { THROW(ERR, "Abstract method Load() not defined for %o", VTable_Get_Name(vtable)); } else if (load != (Obj_Load_t)Hash_load) { // stop inf loop return VTable_Load_Obj(vtable, dump); } } } // It's an ordinary Hash. Hash *loaded = Hash_new(source->size); Obj *key; Obj *value; Hash_Iterate(source); while (Hash_Next(source, &key, &value)) { Hash_Store(loaded, key, Obj_Load(value, value)); } return (Obj*)loaded; }
void Err_throw_at(VTable *vtable, const char *file, int line, const char *func, const char *pattern, ...) { va_list args; Err_Make_t make = METHOD_PTR(CERTIFY(vtable, VTABLE), Lucy_Err_Make); Err *err = (Err*)CERTIFY(make(NULL), ERR); CharBuf *mess = Err_Get_Mess(err); va_start(args, pattern); S_vcat_mess(mess, file, line, func, pattern, args); va_end(args); Err_do_throw(err); }
void SortEx_Sort_Buffer_IMP(SortExternal *self) { SortExternalIVARS *const ivars = SortEx_IVARS(self); if (ivars->buf_tick != 0) { THROW(ERR, "Cant Sort_Buffer() after fetching %u32 items", ivars->buf_tick); } if (ivars->buf_max != 0) { Class *klass = SortEx_get_class(self); CFISH_Sort_Compare_t compare = (CFISH_Sort_Compare_t)METHOD_PTR(klass, LUCY_SortEx_Compare); if (ivars->scratch_cap < ivars->buf_cap) { ivars->scratch_cap = ivars->buf_cap; ivars->scratch = (Obj**)REALLOCATE(ivars->scratch, ivars->scratch_cap * sizeof(Obj*)); } Sort_mergesort(ivars->buffer, ivars->scratch, ivars->buf_max, sizeof(Obj*), compare, self); } }
void SortEx_Sort_Cache_IMP(SortExternal *self) { SortExternalIVARS *const ivars = SortEx_IVARS(self); if (ivars->cache_tick != 0) { THROW(ERR, "Cant Sort_Cache() after fetching %u32 items", ivars->cache_tick); } if (ivars->cache_max != 0) { VTable *vtable = SortEx_Get_VTable(self); CFISH_Sort_Compare_t compare = (CFISH_Sort_Compare_t)METHOD_PTR(vtable, LUCY_SortEx_Compare); if (ivars->scratch_cap < ivars->cache_cap) { ivars->scratch_cap = ivars->cache_cap; ivars->scratch = (uint8_t*)REALLOCATE(ivars->scratch, ivars->scratch_cap * ivars->width); } Sort_mergesort(ivars->cache, ivars->scratch, ivars->cache_max, ivars->width, compare, self); } }
static uint32_t S_find_slice_size(SortExternal *self, SortExternalIVARS *ivars, Obj **endpost) { int32_t lo = ivars->buf_tick - 1; int32_t hi = ivars->buf_max; Obj **buffer = ivars->buffer; SortEx_Compare_t compare = METHOD_PTR(SortEx_get_class(self), LUCY_SortEx_Compare); // Binary search. while (hi - lo > 1) { const int32_t mid = lo + ((hi - lo) / 2); const int32_t delta = compare(self, buffer + mid, endpost); if (delta > 0) { hi = mid; } else { lo = mid; } } // If lo is still -1, we didn't find anything. return lo == -1 ? 0 : (lo - ivars->buf_tick) + 1; }
static uint32_t S_find_slice_size(SortExternal *self, SortExternalIVARS *ivars, uint8_t *endpost) { int32_t lo = ivars->cache_tick - 1; int32_t hi = ivars->cache_max; uint8_t *const cache = ivars->cache; const size_t width = ivars->width; SortEx_Compare_t compare = METHOD_PTR(SortEx_Get_VTable(self), LUCY_SortEx_Compare); // Binary search. while (hi - lo > 1) { const int32_t mid = lo + ((hi - lo) / 2); const int32_t delta = compare(self, cache + mid * width, endpost); if (delta > 0) { hi = mid; } else { lo = mid; } } // If lo is still -1, we didn't find anything. return lo == -1 ? 0 : (lo - ivars->cache_tick) + 1; }
static void S_absorb_slices(SortExternal *self, SortExternalIVARS *ivars, Obj **endpost) { uint32_t num_runs = Vec_Get_Size(ivars->runs); Obj ***slice_starts = ivars->slice_starts; uint32_t *slice_sizes = ivars->slice_sizes; Class *klass = SortEx_get_class(self); CFISH_Sort_Compare_t compare = (CFISH_Sort_Compare_t)METHOD_PTR(klass, LUCY_SortEx_Compare); if (ivars->buf_max != 0) { THROW(ERR, "Can't refill unless empty"); } // Move all the elements in range into the main buffer as slices. for (uint32_t i = 0; i < num_runs; i++) { SortExternal *const run = (SortExternal*)Vec_Fetch(ivars->runs, i); SortExternalIVARS *const run_ivars = SortEx_IVARS(run); uint32_t slice_size = S_find_slice_size(run, run_ivars, endpost); if (slice_size) { // Move slice content from run buffer to main buffer. if (ivars->buf_max + slice_size > ivars->buf_cap) { size_t cap = Memory_oversize(ivars->buf_max + slice_size, sizeof(Obj*)); SortEx_Grow_Buffer(self, cap); } memcpy(ivars->buffer + ivars->buf_max, run_ivars->buffer + run_ivars->buf_tick, slice_size * sizeof(Obj*)); run_ivars->buf_tick += slice_size; ivars->buf_max += slice_size; // Track number of slices and slice sizes. slice_sizes[ivars->num_slices++] = slice_size; } } // Transform slice starts from ticks to pointers. uint32_t total = 0; for (uint32_t i = 0; i < ivars->num_slices; i++) { slice_starts[i] = ivars->buffer + total; total += slice_sizes[i]; } // The main buffer now consists of several slices. Sort the main buffer, // but exploit the fact that each slice is already sorted. if (ivars->scratch_cap < ivars->buf_cap) { ivars->scratch_cap = ivars->buf_cap; ivars->scratch = (Obj**)REALLOCATE( ivars->scratch, ivars->scratch_cap * sizeof(Obj*)); } // Exploit previous sorting, rather than sort buffer naively. // Leave the first slice intact if the number of slices is odd. */ while (ivars->num_slices > 1) { uint32_t i = 0; uint32_t j = 0; while (i < ivars->num_slices) { if (ivars->num_slices - i >= 2) { // Merge two consecutive slices. const uint32_t merged_size = slice_sizes[i] + slice_sizes[i + 1]; Sort_merge(slice_starts[i], slice_sizes[i], slice_starts[i + 1], slice_sizes[i + 1], ivars->scratch, sizeof(Obj*), compare, self); slice_sizes[j] = merged_size; slice_starts[j] = slice_starts[i]; memcpy(slice_starts[j], ivars->scratch, merged_size * sizeof(Obj*)); i += 2; j += 1; } else if (ivars->num_slices - i >= 1) { // Move single slice pointer. slice_sizes[j] = slice_sizes[i]; slice_starts[j] = slice_starts[i]; i += 1; j += 1; } } ivars->num_slices = j; } ivars->num_slices = 0; }