static void S_grow(Inversion *self, size_t size) { InversionIVARS *const ivars = Inversion_IVARS(self); if (size > ivars->cap) { uint64_t amount = size * sizeof(Token*); // Clip rather than wrap. if (amount > SIZE_MAX || amount < size) { amount = SIZE_MAX; } ivars->tokens = (Token**)REALLOCATE(ivars->tokens, (size_t)amount); ivars->cap = size; memset(ivars->tokens + ivars->size, 0, (size - ivars->size) * sizeof(Token*)); } }
static char* S_pod_escape(const char *content) { size_t len = strlen(content); size_t result_len = 0; size_t result_cap = len + 256; char *result = (char*)MALLOCATE(result_cap + 1); for (size_t i = 0; i < len; i++) { const char *subst = content + i; size_t subst_size = 1; switch (content[i]) { case '<': // Escape "less than". subst = "E<lt>"; subst_size = 5; break; case '>': // Escape "greater than". subst = "E<gt>"; subst_size = 5; break; case '|': // Escape vertical bar. subst = "E<verbar>"; subst_size = 9; break; case '=': // Escape equal sign at start of line. if (i == 0 || content[i-1] == '\n') { subst = "E<61>"; subst_size = 5; } break; default: break; } if (result_len + subst_size > result_cap) { result_cap += 256; result = (char*)REALLOCATE(result, result_cap + 1); } memcpy(result + result_len, subst, subst_size); result_len += subst_size; } result[result_len] = '\0'; return result; }
char* CFCBindMeth_abstract_method_def(CFCMethod *method, CFCClass *klass) { CFCType *ret_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(ret_type); CFCType *type = CFCMethod_self_type(method); const char *class_var = CFCType_get_class_var(type); const char *meth_name = CFCMethod_get_name(method); CFCParamList *param_list = CFCMethod_get_param_list(method); const char *params = CFCParamList_to_c(param_list); CFCVariable **vars = CFCParamList_get_variables(param_list); const char *invocant = CFCVariable_get_name(vars[0]); // All variables other than the invocant are unused, and the return is // unreachable. char *unused = CFCUtil_strdup(""); for (int i = 1; vars[i] != NULL; i++) { const char *var_name = CFCVariable_get_name(vars[i]); size_t size = strlen(unused) + strlen(var_name) + 80; unused = (char*)REALLOCATE(unused, size); strcat(unused, "\n CFISH_UNUSED_VAR("); strcat(unused, var_name); strcat(unused, ");"); } char *unreachable; if (!CFCType_is_void(ret_type)) { unreachable = CFCUtil_sprintf(" CFISH_UNREACHABLE_RETURN(%s);\n", ret_type_str); } else { unreachable = CFCUtil_strdup(""); } char *full_func_sym = CFCMethod_imp_func(method, klass); char pattern[] = "%s\n" "%s(%s) {\n" "%s" " cfish_Err_abstract_method_call((cfish_Obj*)%s, %s, \"%s\");\n" "%s" "}\n"; char *abstract_def = CFCUtil_sprintf(pattern, ret_type_str, full_func_sym, params, unused, invocant, class_var, meth_name, unreachable); FREEMEM(unused); FREEMEM(unreachable); FREEMEM(full_func_sym); return abstract_def; }
void CFCHierarchy_add_include_dir(CFCHierarchy *self, const char *include_dir) { // Don't add directory twice. for (size_t i = 0; self->includes[i] != NULL; ++i) { if (strcmp(self->includes[i], include_dir) == 0) { return; } } size_t n = self->num_includes; size_t size = (n + 2) * sizeof(char*); self->includes = (char**)REALLOCATE(self->includes, size); self->includes[n] = CFCUtil_strdup(include_dir); self->includes[n+1] = NULL; self->num_includes = n + 1; }
void CFCPerlClass_add_class_alias(CFCPerlClass *self, const char *alias) { for (size_t i = 0; i < self->num_class_aliases; i++) { if (strcmp(alias, self->class_aliases[i]) == 0) { CFCUtil_die("Alias '%s' already added for class '%s'", alias, self->class_name); } } size_t size = (self->num_class_aliases + 2) * sizeof(char*); self->class_aliases = (char**)REALLOCATE(self->class_aliases, size); self->class_aliases[self->num_class_aliases] = CFCUtil_strdup(alias); self->num_class_aliases++; self->class_aliases[self->num_class_aliases] = NULL; }
static void S_grow(Inversion *self, size_t size) { InversionIVARS *const ivars = Inversion_IVARS(self); if (size > ivars->cap) { if (size > SIZE_MAX / sizeof(Token*) || size > UINT32_MAX) { THROW(ERR, "Can't grow Inversion to hold %u64 elements", (uint64_t)size); } size_t amount = size * sizeof(Token*); ivars->tokens = (Token**)REALLOCATE(ivars->tokens, amount); ivars->cap = (uint32_t)size; memset(ivars->tokens + ivars->size, 0, (size - ivars->size) * sizeof(Token*)); } }
static char* S_build_unused_vars(CFCVariable **vars) { char *unused = CFCUtil_strdup(""); for (int i = 0; vars[i] != NULL; i++) { const char *var_name = CFCVariable_get_name(vars[i]); size_t size = strlen(unused) + strlen(var_name) + 80; unused = (char*)REALLOCATE(unused, size); strcat(unused, "\n CFISH_UNUSED_VAR("); strcat(unused, var_name); strcat(unused, ");"); } return unused; }
static char* S_obj_callback_def(CFCMethod *method, const char *callback_params, const char *refcount_mods) { const char *override_sym = CFCMethod_full_override_sym(method); const char *params = CFCParamList_to_c(CFCMethod_get_param_list(method)); CFCType *return_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(return_type); const char *cb_func_name = CFCType_is_string_type(return_type) ? "cfish_Host_callback_str" : "cfish_Host_callback_obj"; char *nullable_check = CFCUtil_strdup(""); if (!CFCType_nullable(return_type)) { const char *macro_sym = CFCMethod_get_macro_sym(method); char pattern[] = "\n if (!retval) { CFISH_THROW(CFISH_ERR, " "\"%s() for class '%%o' cannot return NULL\", " "Cfish_Obj_Get_Class_Name((cfish_Obj*)self)); }"; size_t size = sizeof(pattern) + strlen(macro_sym) + 30; nullable_check = (char*)REALLOCATE(nullable_check, size); sprintf(nullable_check, pattern, macro_sym); } char pattern[] = "%s\n" "%s(%s) {\n" " %s retval = (%s)%s(%s);%s%s\n" " return retval;\n" "}\n"; size_t size = sizeof(pattern) + strlen(ret_type_str) + strlen(override_sym) + strlen(params) + strlen(ret_type_str) + strlen(ret_type_str) + strlen(cb_func_name) + strlen(callback_params) + strlen(nullable_check) + strlen(refcount_mods) + 30; char *callback_def = (char*)MALLOCATE(size); sprintf(callback_def, pattern, ret_type_str, override_sym, params, ret_type_str, ret_type_str, cb_func_name, callback_params, nullable_check, refcount_mods); FREEMEM(nullable_check); return callback_def; }
void CFCClass_add_method(CFCClass *self, CFCMethod *method) { CFCUTIL_NULL_CHECK(method); if (self->tree_grown) { CFCUtil_die("Can't call add_method after grow_tree"); } if (self->is_inert) { CFCUtil_die("Can't add_method to an inert class"); } self->num_methods++; size_t size = (self->num_methods + 1) * sizeof(CFCMethod*); self->methods = (CFCMethod**)REALLOCATE(self->methods, size); self->methods[self->num_methods - 1] = (CFCMethod*)CFCBase_incref((CFCBase*)method); self->methods[self->num_methods] = NULL; }
static void S_lazy_init_method_bindings(CFCGoClass *self) { if (self->method_bindings) { return; } CFCUTIL_NULL_CHECK(self->client); size_t num_bound = 0; CFCMethod **fresh_methods = CFCClass_fresh_methods(self->client); CFCGoMethod **bound = (CFCGoMethod**)CALLOCATE(1, sizeof(CFCGoMethod*)); // Iterate over the class's fresh methods. for (size_t i = 0; fresh_methods[i] != NULL; i++) { CFCMethod *method = fresh_methods[i]; // Skip methods which have been explicitly excluded. if (CFCMethod_excluded_from_host(method)) { continue; } // Skip methods that shouldn't be bound. if (!CFCMethod_can_be_bound(method)) { continue; } // Only include novel methods. if (!CFCMethod_novel(method)) { continue; } const char *sym = CFCMethod_get_name(method); if (!CFCClass_fresh_method(self->client, sym)) { continue; } /* Create the binding, add it to the array. */ CFCGoMethod *meth_binding = CFCGoMethod_new(method); size_t size = (num_bound + 2) * sizeof(CFCGoMethod*); bound = (CFCGoMethod**)REALLOCATE(bound, size); bound[num_bound] = meth_binding; num_bound++; bound[num_bound] = NULL; } self->method_bindings = bound; self->num_bound = num_bound; }
static void S_register(CFCClass *self) { if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; registry = (CFCClassRegEntry*)REALLOCATE( registry, (new_cap + 1) * sizeof(CFCClassRegEntry)); for (size_t i = registry_cap; i <= new_cap; i++) { registry[i].key = NULL; registry[i].klass = NULL; } registry_cap = new_cap; } CFCParcel *parcel = CFCClass_get_parcel(self); const char *prefix = CFCParcel_get_prefix(parcel); const char *class_name = CFCClass_get_class_name(self); const char *cnick = CFCClass_get_cnick(self); const char *key = self->full_struct_sym; for (size_t i = 0; i < registry_size; i++) { CFCClass *other = registry[i].klass; CFCParcel *other_parcel = CFCClass_get_parcel(other); const char *other_prefix = CFCParcel_get_prefix(other_parcel); const char *other_class_name = CFCClass_get_class_name(other); const char *other_cnick = CFCClass_get_cnick(other); if (strcmp(class_name, other_class_name) == 0) { CFCUtil_die("Two classes with name %s", class_name); } if (strcmp(registry[i].key, key) == 0) { CFCUtil_die("Class name conflict between %s and %s", class_name, other_class_name); } if (strcmp(prefix, other_prefix) == 0 && strcmp(cnick, other_cnick) == 0 ) { CFCUtil_die("Class nickname conflict between %s and %s", class_name, other_class_name); } } registry[registry_size].key = CFCUtil_strdup(key); registry[registry_size].klass = (CFCClass*)CFCBase_incref((CFCBase*)self); registry_size++; }
static void S_register(CFCDocument *self) { if (CFCDocument_fetch(self->name) != NULL) { CFCUtil_die("Two documents with name %s", self->name); } if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; size_t bytes = (new_cap + 1) * sizeof(CFCDocument*); registry = (CFCDocument**)REALLOCATE(registry, bytes); registry_cap = new_cap; } registry[registry_size] = (CFCDocument*)CFCBase_incref((CFCBase*)self); registry[registry_size+1] = NULL; registry_size++; }
static void S_add_tree(CFCHierarchy *self, CFCClass *klass) { CFCUTIL_NULL_CHECK(klass); const char *full_struct_sym = CFCClass_full_struct_sym(klass); for (size_t i = 0; self->trees[i] != NULL; i++) { const char *existing = CFCClass_full_struct_sym(self->trees[i]); if (strcmp(full_struct_sym, existing) == 0) { CFCUtil_die("Tree '%s' alread added", full_struct_sym); } } self->num_trees++; size_t size = (self->num_trees + 1) * sizeof(CFCClass*); self->trees = (CFCClass**)REALLOCATE(self->trees, size); self->trees[self->num_trees - 1] = (CFCClass*)CFCBase_incref((CFCBase*)klass); self->trees[self->num_trees] = NULL; }
void CFCParcel_register(CFCParcel *self) { CFCParcel *existing = CFCParcel_fetch(self->name); if (existing) { CFCUtil_die("Parcel '%s' already registered", self->name); } if (!num_registered) { // Init default parcel as first. registry = (CFCParcel**)CALLOCATE(3, sizeof(CFCParcel*)); CFCParcel *def = CFCParcel_default_parcel(); registry[0] = (CFCParcel*)CFCBase_incref((CFCBase*)def); num_registered++; } size_t size = (num_registered + 2) * sizeof(CFCParcel*); registry = (CFCParcel**)REALLOCATE(registry, size); registry[num_registered++] = (CFCParcel*)CFCBase_incref((CFCBase*)self); registry[num_registered] = NULL; }
static void S_find_files(const char *path, void *arg) { CFCFindFilesContext *context = (CFCFindFilesContext*)arg; const char *ext = context->ext; size_t path_len = strlen(path); size_t ext_len = strlen(ext); if (path_len > ext_len && (strcmp(path + path_len - ext_len, ext) == 0)) { size_t num_paths = context->num_paths; size_t size = (num_paths + 2) * sizeof(char*); char **paths = (char**)REALLOCATE(context->paths, size); paths[num_paths] = CFCUtil_strdup(path); paths[num_paths + 1] = NULL; context->num_paths++; context->paths = paths; } }
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 void S_add_file(CFCHierarchy *self, CFCFile *file) { CFCUTIL_NULL_CHECK(file); CFCClass **classes = CFCFile_classes(file); self->num_files++; size_t size = (self->num_files + 1) * sizeof(CFCFile*); self->files = (CFCFile**)REALLOCATE(self->files, size); self->files[self->num_files - 1] = (CFCFile*)CFCBase_incref((CFCBase*)file); self->files[self->num_files] = NULL; for (size_t i = 0; classes[i] != NULL; i++) { CFCClass *klass = classes[i]; const char *parent_name = CFCClass_get_parent_class_name(klass); if (!parent_name) { S_add_tree(self, klass); } } }
void CFCGoClass_register(CFCGoClass *self) { if (registry_size == registry_cap) { size_t new_cap = registry_cap + 10; size_t amount = (new_cap + 1) * sizeof(CFCGoClass*); registry = (CFCGoClass**)REALLOCATE(registry, amount); for (size_t i = registry_cap; i <= new_cap; i++) { registry[i] = NULL; } registry_cap = new_cap; } CFCGoClass *existing = CFCGoClass_singleton(self->class_name); if (existing) { CFCUtil_die("Class '%s' already registered", self->class_name); } registry[registry_size] = (CFCGoClass*)CFCBase_incref((CFCBase*)self); registry_size++; qsort(registry, registry_size, sizeof(CFCGoClass*), S_compare_cfcgoclass); }
/** format **/ String* String::FormatV(const char* fmt, va_list vl){ va_list vc; va_copy(vc, vl); int64_t len =0; len =vsnprintf(0, 0, fmt, vl); if(len < 0){ OutputDebug("String::FormatV:vsnprintf fail"); return 0; } else if(len == 0){ return NewString(); } else{ String* o =NewString(); o->m_length =len; o->m_data =reinterpret_cast< char* >(REALLOCATE(o->m_data, o->m_length + 1)); vsnprintf(o->m_data, (size_t)(o->m_length+1), fmt, vc); return o; } }
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); } }
// Pass down member vars to from parent to children. static void S_bequeath_member_vars(CFCClass *self) { for (size_t i = 0; self->children[i] != NULL; i++) { CFCClass *child = self->children[i]; size_t num_vars = self->num_member_vars + child->num_member_vars; size_t size = (num_vars + 1) * sizeof(CFCVariable*); child->member_vars = (CFCVariable**)REALLOCATE(child->member_vars, size); memmove(child->member_vars + self->num_member_vars, child->member_vars, child->num_member_vars * sizeof(CFCVariable*)); memcpy(child->member_vars, self->member_vars, self->num_member_vars * sizeof(CFCVariable*)); for (size_t j = 0; self->member_vars[j] != NULL; j++) { CFCBase_incref((CFCBase*)child->member_vars[j]); } child->num_member_vars = num_vars; child->member_vars[num_vars] = NULL; S_bequeath_member_vars(child); } }
void ScorePost_Read_Record_IMP(ScorePosting *self, InStream *instream) { ScorePostingIVARS *const ivars = ScorePost_IVARS(self); uint32_t position = 0; const size_t max_start_bytes = (C32_MAX_BYTES * 2) + 1; const char *buf = InStream_Buf(instream, max_start_bytes); const uint32_t doc_code = NumUtil_decode_c32(&buf); const uint32_t doc_delta = doc_code >> 1; // Apply delta doc and retrieve freq. ivars->doc_id += doc_delta; if (doc_code & 1) { ivars->freq = 1; } else { ivars->freq = NumUtil_decode_c32(&buf); } // Decode boost/norm byte. ivars->weight = ivars->norm_decoder[*(uint8_t*)buf]; buf++; // Read positions. uint32_t num_prox = ivars->freq; if (num_prox > ivars->prox_cap) { ivars->prox = (uint32_t*)REALLOCATE( ivars->prox, num_prox * sizeof(uint32_t)); ivars->prox_cap = num_prox; } uint32_t *positions = ivars->prox; InStream_Advance_Buf(instream, buf); buf = InStream_Buf(instream, num_prox * C32_MAX_BYTES); while (num_prox--) { position += NumUtil_decode_c32(&buf); *positions++ = position; } InStream_Advance_Buf(instream, buf); }
void CFCParcel_register(CFCParcel *self) { const char *name = self->name; const char *nickname = self->nickname; for (size_t i = 0; i < num_registered ; i++) { CFCParcel *other = registry[i]; if (strcmp(other->name, name) == 0) { CFCUtil_die("Parcel '%s' already registered", name); } if (strcmp(other->nickname, nickname) == 0) { CFCUtil_die("Parcel with nickname '%s' already registered", nickname); } } size_t size = (num_registered + 2) * sizeof(CFCParcel*); registry = (CFCParcel**)REALLOCATE(registry, size); registry[num_registered++] = (CFCParcel*)CFCBase_incref((CFCBase*)self); registry[num_registered] = NULL; }
HitDoc* DefDocReader_Fetch_Doc_IMP(DefaultDocReader *self, int32_t doc_id) { DefaultDocReaderIVARS *const ivars = DefDocReader_IVARS(self); Schema *const schema = ivars->schema; InStream *const dat_in = ivars->dat_in; InStream *const ix_in = ivars->ix_in; Hash *const fields = Hash_new(1); int64_t start; uint32_t num_fields; uint32_t field_name_cap = 31; char *field_name = (char*)MALLOCATE(field_name_cap + 1); // Get data file pointer from index, read number of fields. InStream_Seek(ix_in, (int64_t)doc_id * 8); start = InStream_Read_U64(ix_in); InStream_Seek(dat_in, start); num_fields = InStream_Read_C32(dat_in); // Decode stored data and build up the doc field by field. while (num_fields--) { uint32_t field_name_len; Obj *value; FieldType *type; // Read field name. field_name_len = InStream_Read_C32(dat_in); if (field_name_len > field_name_cap) { field_name_cap = field_name_len; field_name = (char*)REALLOCATE(field_name, field_name_cap + 1); } InStream_Read_Bytes(dat_in, field_name, field_name_len); // Find the Field's FieldType. StackString *field_name_str = SSTR_WRAP_UTF8(field_name, field_name_len); type = Schema_Fetch_Type(schema, (String*)field_name_str); // Read the field value. switch (FType_Primitive_ID(type) & FType_PRIMITIVE_ID_MASK) { case FType_TEXT: { uint32_t value_len = InStream_Read_C32(dat_in); char *buf = (char*)MALLOCATE(value_len + 1); InStream_Read_Bytes(dat_in, buf, value_len); buf[value_len] = '\0'; value = (Obj*)Str_new_steal_utf8(buf, value_len); break; } case FType_BLOB: { uint32_t value_len = InStream_Read_C32(dat_in); char *buf = (char*)MALLOCATE(value_len); InStream_Read_Bytes(dat_in, buf, value_len); value = (Obj*)BB_new_steal_bytes( buf, value_len, value_len); break; } case FType_FLOAT32: value = (Obj*)Float32_new( InStream_Read_F32(dat_in)); break; case FType_FLOAT64: value = (Obj*)Float64_new( InStream_Read_F64(dat_in)); break; case FType_INT32: value = (Obj*)Int32_new( (int32_t)InStream_Read_C32(dat_in)); break; case FType_INT64: value = (Obj*)Int64_new( (int64_t)InStream_Read_C64(dat_in)); break; default: value = NULL; THROW(ERR, "Unrecognized type: %o", type); } // Store the value. Hash_Store_Utf8(fields, field_name, field_name_len, value); } FREEMEM(field_name); HitDoc *retval = HitDoc_new(fields, doc_id, 0.0); DECREF(fields); return retval; }
void addCommand(Command cmd) { commands = (Command*)REALLOCATE(commands, sizeof(Command) * (commandsCount + 1) ); commands[commandsCount++] = cmd; commandNumber++; }
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; }