mirror of
https://github.com/radareorg/radare2.git
synced 2025-03-03 19:59:09 +00:00
Branch prediction optimizations (3/3) ##performance
This commit is contained in:
parent
433917e551
commit
872e02dff9
@ -35,11 +35,14 @@ static void __max_end(RBNode *node) {
|
||||
static int __bb_addr_cmp(const void *incoming, const RBNode *in_tree, void *user) {
|
||||
ut64 incoming_addr = *(ut64 *)incoming;
|
||||
const RAnalBlock *in_tree_block = container_of (in_tree, const RAnalBlock, _rb);
|
||||
if (incoming_addr < in_tree_block->addr) {
|
||||
return -1;
|
||||
}
|
||||
if (incoming_addr > in_tree_block->addr) {
|
||||
return 1;
|
||||
if (in_tree_block) {
|
||||
ut64 itaddr = in_tree_block->addr;
|
||||
if (incoming_addr < itaddr) {
|
||||
return -1;
|
||||
}
|
||||
if (incoming_addr > itaddr) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -383,17 +383,17 @@ R_API void r_anal_hint_free(RAnalHint *h) {
|
||||
|
||||
R_API R_NULLABLE R_BORROW const char *r_anal_hint_arch_at(RAnal *anal, ut64 addr, R_NULLABLE ut64 *hint_addr) {
|
||||
RBNode *node = r_rbtree_upper_bound (anal->arch_hints, &addr, ranged_hint_record_cmp, NULL);
|
||||
if (!node) {
|
||||
if (R_LIKELY (node)) {
|
||||
RAnalArchHintRecord *record = (RAnalArchHintRecord *)container_of (node, RAnalRangedHintRecordBase, rb);
|
||||
if (hint_addr) {
|
||||
*hint_addr = UT64_MAX;
|
||||
*hint_addr = record->base.addr;
|
||||
}
|
||||
return NULL;
|
||||
return record->arch;
|
||||
}
|
||||
RAnalArchHintRecord *record = (RAnalArchHintRecord *)container_of (node, RAnalRangedHintRecordBase, rb);
|
||||
if (hint_addr) {
|
||||
*hint_addr = record->base.addr;
|
||||
*hint_addr = UT64_MAX;
|
||||
}
|
||||
return record->arch;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
R_API int r_anal_hint_bits_at(RAnal *anal, ut64 addr, R_NULLABLE ut64 *hint_addr) {
|
||||
|
@ -2756,6 +2756,56 @@ static void set_opdir(RAnalOp *op, cs_insn *insn) {
|
||||
}
|
||||
}
|
||||
|
||||
static void inscmp(RAnalOp *op, ut64 addr, cs_insn *insn, int regsz) {
|
||||
switch (INSOP(0).type) {
|
||||
case X86_OP_MEM:
|
||||
op->disp = INSOP(0).mem.disp;
|
||||
op->refptr = INSOP(0).size;
|
||||
if (INSOP(0).mem.base == X86_REG_RIP) {
|
||||
op->ptr = addr + insn->size + op->disp;
|
||||
} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
|
||||
op->stackop = R_ANAL_STACK_SET;
|
||||
op->stackptr = regsz;
|
||||
op->type |= R_ANAL_OP_TYPE_REG;
|
||||
} else if (INSOP(0).mem.segment == X86_REG_INVALID && INSOP(0).mem.base == X86_REG_INVALID
|
||||
&& INSOP(0).mem.index == X86_REG_INVALID && INSOP(0).mem.scale == 1) { // [<addr>]
|
||||
op->ptr = op->disp;
|
||||
}
|
||||
if (INSOP(1).type == X86_OP_IMM) {
|
||||
op->val = INSOP(1).imm;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (INSOP(1).type) {
|
||||
case X86_OP_MEM:
|
||||
op->disp = INSOP(1).mem.disp;
|
||||
op->refptr = INSOP(1).size;
|
||||
if (INSOP(1).mem.base == X86_REG_RIP) {
|
||||
op->ptr = addr + insn->size + op->disp;
|
||||
} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
|
||||
op->type |= R_ANAL_OP_TYPE_REG;
|
||||
op->stackop = R_ANAL_STACK_SET;
|
||||
op->stackptr = regsz;
|
||||
} else if (INSOP(1).mem.segment == X86_REG_INVALID
|
||||
&& INSOP(1).mem.base == X86_REG_INVALID
|
||||
&& INSOP(1).mem.index == X86_REG_INVALID
|
||||
&& INSOP(1).mem.scale == 1) { // [<addr>]
|
||||
op->ptr = op->disp;
|
||||
}
|
||||
if (INSOP(0).type == X86_OP_IMM) {
|
||||
op->val = INSOP(0).imm;
|
||||
}
|
||||
break;
|
||||
case X86_OP_IMM:
|
||||
op->val = op->ptr = INSOP(1).imm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void anop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
|
||||
int bits = a->config->bits;
|
||||
struct Getarg gop = {
|
||||
@ -3140,59 +3190,12 @@ static void anop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh
|
||||
case X86_INS_CMPSQ:
|
||||
case X86_INS_CMPSB:
|
||||
case X86_INS_CMPSS:
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
inscmp (op, addr, insn, regsz);
|
||||
break;
|
||||
case X86_INS_TEST:
|
||||
if (insn->id == X86_INS_TEST) {
|
||||
op->type = R_ANAL_OP_TYPE_ACMP; //compare via and
|
||||
} else {
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
}
|
||||
switch (INSOP(0).type) {
|
||||
case X86_OP_MEM:
|
||||
op->disp = INSOP(0).mem.disp;
|
||||
op->refptr = INSOP(0).size;
|
||||
if (INSOP(0).mem.base == X86_REG_RIP) {
|
||||
op->ptr = addr + insn->size + op->disp;
|
||||
} else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) {
|
||||
op->stackop = R_ANAL_STACK_SET;
|
||||
op->stackptr = regsz;
|
||||
op->type |= R_ANAL_OP_TYPE_REG;
|
||||
} else if (INSOP(0).mem.segment == X86_REG_INVALID && INSOP(0).mem.base == X86_REG_INVALID
|
||||
&& INSOP(0).mem.index == X86_REG_INVALID && INSOP(0).mem.scale == 1) { // [<addr>]
|
||||
op->ptr = op->disp;
|
||||
}
|
||||
if (INSOP(1).type == X86_OP_IMM) {
|
||||
op->val = INSOP(1).imm;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (INSOP(1).type) {
|
||||
case X86_OP_MEM:
|
||||
op->disp = INSOP(1).mem.disp;
|
||||
op->refptr = INSOP(1).size;
|
||||
if (INSOP(1).mem.base == X86_REG_RIP) {
|
||||
op->ptr = addr + insn->size + op->disp;
|
||||
} else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) {
|
||||
op->type |= R_ANAL_OP_TYPE_REG;
|
||||
op->stackop = R_ANAL_STACK_SET;
|
||||
op->stackptr = regsz;
|
||||
} else if (INSOP(1).mem.segment == X86_REG_INVALID
|
||||
&& INSOP(1).mem.base == X86_REG_INVALID
|
||||
&& INSOP(1).mem.index == X86_REG_INVALID
|
||||
&& INSOP(1).mem.scale == 1) { // [<addr>]
|
||||
op->ptr = op->disp;
|
||||
}
|
||||
if (INSOP(0).type == X86_OP_IMM) {
|
||||
op->val = INSOP(0).imm;
|
||||
}
|
||||
break;
|
||||
case X86_OP_IMM:
|
||||
op->val = op->ptr = INSOP(1).imm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
op->type = R_ANAL_OP_TYPE_ACMP; // compare via and
|
||||
inscmp (op, addr, insn, regsz);
|
||||
break;
|
||||
case X86_INS_LEA:
|
||||
op->type = R_ANAL_OP_TYPE_LEA;
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <r_list.h>
|
||||
|
||||
#define ACCESS_CMP(x, y) ((st64)((ut64)(x) - ((RAnalVarAccess *)y)->offset))
|
||||
// XXX this helper function is crap and shouldnt be used
|
||||
#define STR_EQUAL(s1, s2) (s1 && s2 && !strcmp (s1, s2))
|
||||
|
||||
R_API bool r_anal_var_display(RAnal *anal, RAnalVar *var) {
|
||||
r_return_val_if_fail (anal && var, false);
|
||||
@ -30,16 +32,17 @@ R_API bool r_anal_var_display(RAnal *anal, RAnalVar *var) {
|
||||
R_LOG_ERROR ("register not found");
|
||||
}
|
||||
break;
|
||||
case R_ANAL_VAR_KIND_BPV: {
|
||||
const st32 real_delta = var->delta + var->fcn->bp_off;
|
||||
const ut32 udelta = R_ABS (real_delta);
|
||||
const char sign = real_delta >= 0 ? '+' : '-';
|
||||
if (usePxr) {
|
||||
anal->cb_printf ("pxr $w @%s%c0x%x\n", anal->reg->name[R_REG_NAME_BP], sign, udelta);
|
||||
} else {
|
||||
anal->cb_printf ("pf %s @%s%c0x%x\n", fmt, anal->reg->name[R_REG_NAME_BP], sign, udelta);
|
||||
case R_ANAL_VAR_KIND_BPV:
|
||||
{
|
||||
const st32 real_delta = var->delta + var->fcn->bp_off;
|
||||
const ut32 udelta = R_ABS (real_delta);
|
||||
const char sign = real_delta >= 0 ? '+' : '-';
|
||||
if (usePxr) {
|
||||
anal->cb_printf ("pxr $w @%s%c0x%x\n", anal->reg->name[R_REG_NAME_BP], sign, udelta);
|
||||
} else {
|
||||
anal->cb_printf ("pf %s @%s%c0x%x\n", fmt, anal->reg->name[R_REG_NAME_BP], sign, udelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_ANAL_VAR_KIND_SPV: {
|
||||
ut32 udelta = R_ABS (var->delta + var->fcn->maxstack);
|
||||
@ -856,6 +859,7 @@ static bool var_add_structure_fields_to_list(RAnal *a, RAnalVar *av, RList *list
|
||||
}
|
||||
|
||||
static const char *get_regname(RAnal *anal, RAnalValue *value) {
|
||||
// R2_590 - this is underperforming hard
|
||||
const char *name = NULL;
|
||||
if (value && value->reg && value->reg->name) {
|
||||
name = value->reg->name;
|
||||
@ -1082,7 +1086,33 @@ beach:
|
||||
;
|
||||
}
|
||||
|
||||
static bool is_reg_in_src(const char *regname, RAnal *anal, RAnalOp *op);
|
||||
#if 0
|
||||
static bool is_reg_in_src(const char *regname, RAnal *anal, RAnalOp *op) {
|
||||
RAnalValue *src0 = r_vector_at (&op->srcs, 0);
|
||||
RAnalValue *src1 = r_vector_at (&op->srcs, 1);
|
||||
RAnalValue *src2 = r_vector_at (&op->srcs, 2);
|
||||
const char* opsreg0 = src0 ? get_regname (anal, src0) : NULL;
|
||||
const char* opsreg1 = src1 ? get_regname (anal, src1) : NULL;
|
||||
const char* opsreg2 = src2 ? get_regname (anal, src2) : NULL;
|
||||
return (STR_EQUAL (regname, opsreg0)) || (STR_EQUAL (regname, opsreg1)) || (STR_EQUAL (regname, opsreg2));
|
||||
}
|
||||
#else
|
||||
static bool is_reg_in_src(const char *regname, RAnal *anal, RAnalOp *op) {
|
||||
r_return_val_if_fail (regname && anal && op, false);
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
RAnalValue *src = r_vector_at (&op->srcs, i);
|
||||
if (!src) {
|
||||
return false;
|
||||
}
|
||||
const char *srcreg = get_regname (anal, src);
|
||||
if (srcreg && !strcmp (regname, srcreg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool op_affect_dst(RAnalOp* op) {
|
||||
switch (op->type) {
|
||||
@ -1108,10 +1138,9 @@ static inline bool op_affect_dst(RAnalOp* op) {
|
||||
}
|
||||
}
|
||||
|
||||
#define STR_EQUAL(s1, s2) (s1 && s2 && !strcmp (s1, s2))
|
||||
|
||||
static inline bool arch_destroys_dst(const char *arch) {
|
||||
return (STR_EQUAL (arch, "arm") || STR_EQUAL (arch, "riscv") || STR_EQUAL (arch, "ppc"));
|
||||
r_return_val_if_fail (arch, false);
|
||||
return (!strcmp (arch, "arm") || !strcmp (arch, "riscv") || !strcmp (arch, "ppc"));
|
||||
}
|
||||
|
||||
static bool is_used_like_arg(const char *regname, const char *opsreg, const char *opdreg, RAnalOp *op, RAnal *anal) {
|
||||
@ -1155,16 +1184,6 @@ static bool is_used_like_arg(const char *regname, const char *opsreg, const char
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_reg_in_src(const char *regname, RAnal *anal, RAnalOp *op) {
|
||||
RAnalValue *src0 = r_vector_at (&op->srcs, 0);
|
||||
RAnalValue *src1 = r_vector_at (&op->srcs, 1);
|
||||
RAnalValue *src2 = r_vector_at (&op->srcs, 2);
|
||||
const char* opsreg0 = src0 ? get_regname (anal, src0) : NULL;
|
||||
const char* opsreg1 = src1 ? get_regname (anal, src1) : NULL;
|
||||
const char* opsreg2 = src2 ? get_regname (anal, src2) : NULL;
|
||||
return (STR_EQUAL (regname, opsreg0)) || (STR_EQUAL (regname, opsreg1)) || (STR_EQUAL (regname, opsreg2));
|
||||
}
|
||||
|
||||
R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int *reg_set, int *count) {
|
||||
int i, argc = 0;
|
||||
r_return_if_fail (anal && op && fcn);
|
||||
@ -1273,21 +1292,23 @@ R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int
|
||||
|
||||
for (i = 0; i < max_count; i++) {
|
||||
const char *regname = r_anal_cc_arg (anal, fcn->cc, i);
|
||||
if (regname) {
|
||||
if (!regname) {
|
||||
// WIP break;
|
||||
} else {
|
||||
int delta = 0;
|
||||
RRegItem *ri = NULL;
|
||||
RAnalVar *var = NULL;
|
||||
bool is_used_like_an_arg = is_used_like_arg (regname, opsreg, opdreg, op, anal);
|
||||
if (reg_set[i] != 2 && is_used_like_an_arg) {
|
||||
const bool is_arg = is_used_like_arg (regname, opsreg, opdreg, op, anal);
|
||||
if (is_arg && reg_set[i] != 2) {
|
||||
ri = r_reg_get (anal->reg, regname, -1);
|
||||
if (ri) {
|
||||
delta = ri->index;
|
||||
r_unref (ri);
|
||||
}
|
||||
}
|
||||
if (reg_set[i] == 1 && is_used_like_an_arg) {
|
||||
if (is_arg && reg_set[i] == 1) {
|
||||
var = r_anal_function_get_var (fcn, R_ANAL_VAR_KIND_REG, delta);
|
||||
} else if (reg_set[i] != 2 && is_used_like_an_arg) {
|
||||
} else if (is_arg && reg_set[i] != 2) {
|
||||
const char *vname = NULL;
|
||||
char *type = NULL;
|
||||
char *name = NULL;
|
||||
@ -1321,8 +1342,8 @@ R_API void r_anal_extract_rarg(RAnal *anal, RAnalOp *op, RAnalFunction *fcn, int
|
||||
|
||||
const char *selfreg = r_anal_cc_self (anal, fcn->cc);
|
||||
if (selfreg) {
|
||||
bool is_used_like_an_arg = is_used_like_arg (selfreg, opsreg, opdreg, op, anal);
|
||||
if (reg_set[i] != 2 && is_used_like_an_arg) {
|
||||
bool is_arg = is_used_like_arg (selfreg, opsreg, opdreg, op, anal);
|
||||
if (is_arg && reg_set[i] != 2) {
|
||||
int delta = 0;
|
||||
char *vname = strdup ("self");
|
||||
RRegItem *ri = r_reg_get (anal->reg, selfreg, -1);
|
||||
@ -1383,9 +1404,7 @@ R_API void r_anal_extract_vars(RAnal *anal, RAnalFunction *fcn, RAnalOp *op) {
|
||||
}
|
||||
|
||||
static RList *var_generate_list(RAnal *a, RAnalFunction *fcn, int kind) {
|
||||
if (!a || !fcn) {
|
||||
return NULL;
|
||||
}
|
||||
r_return_val_if_fail (a && fcn, NULL);
|
||||
RList *list = r_list_new ();
|
||||
if (kind < 1) {
|
||||
kind = R_ANAL_VAR_KIND_BPV; // by default show vars
|
||||
@ -1534,6 +1553,7 @@ static int var_comparator(const RAnalVar *a, const RAnalVar *b) {
|
||||
}
|
||||
|
||||
R_API void r_anal_var_list_show(RAnal *anal, RAnalFunction *fcn, int kind, int mode, PJ *pj) {
|
||||
r_return_if_fail (anal && fcn);
|
||||
bool newstack = anal->opt.var_newstack;
|
||||
RList *list = r_anal_var_list (anal, fcn, kind);
|
||||
RAnalVar *var;
|
||||
|
@ -20,16 +20,12 @@ static RBinSymbol *__getMethod(RBinFile *bf, const char *klass, const char *meth
|
||||
}
|
||||
|
||||
static RBinString *__stringAt(RBinFile *bf, RList *ret, ut64 addr) {
|
||||
if (addr != 0 && addr != UT64_MAX) {
|
||||
if (R_LIKELY (addr != 0 && addr != UT64_MAX)) {
|
||||
return ht_up_find (bf->o->strings_db, addr, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ut64 binobj_a2b(RBinObject *bo, ut64 addr) {
|
||||
return addr + (bo ? bo->baddr_shift : 0);
|
||||
}
|
||||
|
||||
static void print_string(RBinFile *bf, RBinString *string, int raw, PJ *pj) {
|
||||
r_return_if_fail (bf && string);
|
||||
|
||||
@ -1130,7 +1126,7 @@ R_API RBinField *r_bin_file_add_field(RBinFile *binfile, const char *classname,
|
||||
R_API ut64 r_bin_file_get_vaddr(RBinFile *bf, ut64 paddr, ut64 vaddr) {
|
||||
r_return_val_if_fail (bf && bf->o, paddr);
|
||||
if (bf->o->info && bf->o->info->has_va) {
|
||||
return binobj_a2b (bf->o, vaddr);
|
||||
return bf->o->baddr_shift + vaddr;
|
||||
}
|
||||
return paddr;
|
||||
}
|
||||
|
@ -49,10 +49,6 @@ static const char *__getname(RBin *bin, int type, int idx, bool sd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ut64 binobj_a2b(RBinObject *o, ut64 addr) {
|
||||
return o ? addr + o->baddr_shift : addr;
|
||||
}
|
||||
|
||||
// TODO: move these two function do a different file
|
||||
R_API RBinXtrData *r_bin_xtrdata_new(RBuffer *buf, ut64 offset, ut64 size, ut32 file_count, RBinXtrMetadata *metadata) {
|
||||
RBinXtrData *data = R_NEW0 (RBinXtrData);
|
||||
@ -713,18 +709,16 @@ R_API RList *r_bin_get_sections(RBin *bin) {
|
||||
}
|
||||
|
||||
R_API RBinSection *r_bin_get_section_at(RBinObject *o, ut64 off, int va) {
|
||||
r_return_val_if_fail (o, NULL);
|
||||
RBinSection *section;
|
||||
RListIter *iter;
|
||||
ut64 from, to;
|
||||
|
||||
r_return_val_if_fail (o, NULL);
|
||||
// TODO: must be O(1) .. use sdb here
|
||||
r_list_foreach (o->sections, iter, section) {
|
||||
if (section->is_segment) {
|
||||
continue;
|
||||
}
|
||||
from = va ? binobj_a2b (o, section->vaddr) : section->paddr;
|
||||
to = from + (va ? section->vsize: section->size);
|
||||
ut64 from = va ? o->baddr_shift + section->vaddr : section->paddr;
|
||||
ut64 to = from + (va ? section->vsize: section->size);
|
||||
if (off >= from && off < to) {
|
||||
return section;
|
||||
}
|
||||
@ -1281,10 +1275,14 @@ R_API ut64 r_bin_get_vaddr(RBin *bin, ut64 paddr, ut64 vaddr) {
|
||||
return r_bin_file_get_vaddr (bin->cur, paddr, vaddr);
|
||||
}
|
||||
|
||||
// XXX remove this public api
|
||||
R_API ut64 r_bin_a2b(RBin *bin, ut64 addr) {
|
||||
r_return_val_if_fail (bin, UT64_MAX);
|
||||
RBinObject *o = r_bin_cur_object (bin);
|
||||
return binobj_a2b (o, addr);
|
||||
if (o) {
|
||||
return o->baddr_shift + addr;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
R_API ut64 r_bin_get_size(RBin *bin) {
|
||||
|
@ -1680,6 +1680,12 @@ static int var_cmd(RCore *core, const char *str) {
|
||||
int delta, type = *str, res = true;
|
||||
RAnalVar *v1;
|
||||
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, -1);
|
||||
if (!fcn) {
|
||||
if (str[0] == 'j') { // "afvj"
|
||||
r_cons_println ("{}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!str[0]) {
|
||||
if (fcn) {
|
||||
// "afv"
|
||||
@ -1911,8 +1917,12 @@ static int var_cmd(RCore *core, const char *str) {
|
||||
if (!pj) {
|
||||
return false;
|
||||
}
|
||||
r_anal_var_list_show (core->anal, fcn, type, str[1], pj);
|
||||
r_cons_println (pj_string (pj));
|
||||
if (fcn) {
|
||||
r_anal_var_list_show (core->anal, fcn, type, str[1], pj);
|
||||
r_cons_println (pj_string (pj));
|
||||
} else {
|
||||
R_LOG_ERROR ("No function");
|
||||
}
|
||||
pj_free (pj);
|
||||
break;
|
||||
case '.': // "afv[bsr]."
|
||||
|
@ -278,10 +278,9 @@ R_API bool r_rbtree_aug_update_sum(RBNode *root, void *data, RBNode *node, RBCom
|
||||
if (cur == node) {
|
||||
break;
|
||||
}
|
||||
int direction = cmp (data, cur, cmp_user);
|
||||
const int direction = cmp (data, cur, cmp_user);
|
||||
cur = cur->child[(direction < 0)? 0: 1];
|
||||
}
|
||||
|
||||
for (; depth > 0; depth--) {
|
||||
sum (path[depth - 1]);
|
||||
}
|
||||
@ -294,7 +293,7 @@ R_API bool r_rbtree_delete(RBNode **root, void *data, RBComparator cmp, void *cm
|
||||
|
||||
R_API RBNode *r_rbtree_find(RBNode *x, void *data, RBComparator cmp, void *user) {
|
||||
while (x) {
|
||||
int direction = cmp (data, x, user);
|
||||
const int direction = cmp (data, x, user);
|
||||
if (direction < 0) {
|
||||
x = x->child[0];
|
||||
} else if (direction > 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user