static VALUE range_bsearch(VALUE range) { VALUE beg, end; int smaller, satisfied = 0; /* Implementation notes: * Floats are handled by mapping them to 64 bits integers. * Apart from sign issues, floats and their 64 bits integer have the * same order, assuming they are represented as exponent followed * by the mantissa. This is true with or without implicit bit. * * Finding the average of two ints needs to be careful about * potential overflow (since float to long can use 64 bits) * as well as the fact that -1/2 can be 0 or -1 in C89. * * Note that -0.0 is mapped to the same int as 0.0 as we don't want * (-1...0.0).bsearch to yield -0.0. */ #define BSEARCH_CHECK(val) \ do { \ VALUE v = rb_yield(val); \ if (FIXNUM_P(v)) { \ if (FIX2INT(v) == 0) return val; \ smaller = FIX2INT(v) < 0; \ } \ else if (v == Qtrue) { \ satisfied = 1; \ smaller = 1; \ } \ else if (v == Qfalse || v == Qnil) { \ smaller = 0; \ } \ else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \ int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \ if (!cmp) return val; \ smaller = cmp < 0; \ } \ else { \ rb_raise(rb_eTypeError, "wrong argument type %s" \ " (must be numeric, true, false or nil)", \ rb_obj_classname(v)); \ } \ } while (0) #define BSEARCH(conv) \ do { \ RETURN_ENUMERATOR(range, 0, 0); \ if (EXCL(range)) high--; \ org_high = high; \ while (low < high) { \ mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \ : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \ BSEARCH_CHECK(conv(mid)); \ if (smaller) { \ high = mid; \ } \ else { \ low = mid + 1; \ } \ } \ if (low == org_high) { \ BSEARCH_CHECK(conv(low)); \ if (!smaller) return Qnil; \ } \ if (!satisfied) return Qnil; \ return conv(low); \ } while (0) beg = RANGE_BEG(range); end = RANGE_END(range); if (FIXNUM_P(beg) && FIXNUM_P(end)) { long low = FIX2LONG(beg); long high = FIX2LONG(end); long mid, org_high; BSEARCH(INT2FIX); } #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T) else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) { int64_t low = double_as_int64(RFLOAT_VALUE(rb_Float(beg))); int64_t high = double_as_int64(RFLOAT_VALUE(rb_Float(end))); int64_t mid, org_high; BSEARCH(int64_as_double_to_num); } #endif else if (is_integer_p(beg) && is_integer_p(end)) { VALUE low = rb_to_int(beg); VALUE high = rb_to_int(end); VALUE mid, org_high; RETURN_ENUMERATOR(range, 0, 0); if (EXCL(range)) high = rb_funcall(high, '-', 1, INT2FIX(1)); org_high = high; while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) { mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2)); BSEARCH_CHECK(mid); if (smaller) { high = mid; } else { low = rb_funcall(mid, '+', 1, INT2FIX(1)); } } if (rb_equal(low, org_high)) { BSEARCH_CHECK(low); if (!smaller) return Qnil; } if (!satisfied) return Qnil; return low; } else { rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg)); } return range; }
bool panda_dispatch_args( char *const *args, int args_length, const panda_tweak_assembler *const *const assembler_args, size_t assembler_args_length, const panda_tweak_general *const *const general_args, size_t general_args_length, PandaTweakGeneral tweak, void *user_data, panda_tweak_assembler_opt * options, size_t options_length, size_t *options_used, int *args_unused) { int c; size_t it; char optlist[MAX_OPT_LIST + 1]; char seen_options[MAX_OPT_LIST + 1]; size_t seen_options_length = 0; const panda_tweak_general **general_tweak; const panda_tweak_assembler **assembler_tweak; size_t opt_it; #ifdef __GLIBC__ optind = 0; #else optind = 1; #endif opt_it = 0; *options_used = 0; MAYBE(args_unused) = 0; c = '\0'; for (it = 0; it < general_args_length; it++) { if (general_args[it]->flag <= c) { fprintf(stderr, "Internal error: general arguments in a bad order.\n"); abort(); } c = optlist[opt_it++] = general_args[it]->flag; if (general_args[it]->takes_argument != NULL) optlist[opt_it++] = ':'; if (opt_it >= MAX_OPT_LIST) { fprintf(stderr, "Internal error: too many options.\n"); abort(); } } c = '\0'; for (it = 0; it < assembler_args_length; it++) { if (assembler_args[it]->flag <= c) { fprintf(stderr, "Internal error: assembler arguments in a bad order.\n"); abort(); } c = optlist[opt_it++] = assembler_args[it]->flag; if (assembler_args[it]->takes_argument != NULL) optlist[opt_it++] = ':'; if (opt_it >= MAX_OPT_LIST) { fprintf(stderr, "Internal error: too many options.\n"); abort(); } } optlist[opt_it] = '\0'; /* Process command line arguments. */ while ((c = getopt(args_length, args, optlist)) != -1) { if (c == '?') { if (strchr(optlist, optopt) != NULL) { if ((general_tweak = BSEARCH(&optopt, general)) != NULL) { fprintf(stderr, "Option -%c requires an argument %s.\n", optopt, (*general_tweak)->takes_argument); } else if ((assembler_tweak = BSEARCH(&optopt, assembler)) != NULL) { fprintf(stderr, "Option -%c requires an argument %s.\n", optopt, (*assembler_tweak)->takes_argument); } else { fprintf(stderr, "Unhandled command line argument -%c requires an argument. This is a bug.\n", (int) optopt); } } else if (isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", (unsigned int) optopt); } CLEANUP(); return false; } else { if ((general_tweak = BSEARCH(&c, general)) != NULL) { if ((*general_tweak)->takes_argument != NULL || !(*general_tweak)->repeatable) { if (memchr(seen_options, c, seen_options_length) != NULL) { fprintf(stderr, "Command line argument -%c may not be repeated.\n", (int) c); CLEANUP(); return false; } if (seen_options_length == MAX_OPT_LIST) { fprintf(stderr, "Too many command line arguments.\n"); CLEANUP(); return false; } seen_options[seen_options_length++] = c; } if (!tweak(user_data, c, (*general_tweak)->takes_argument != NULL ? optarg : NULL)) { CLEANUP(); return false; } } else if ((assembler_tweak = BSEARCH(&c, assembler)) != NULL) { if ((*assembler_tweak)->takes_argument == NULL || !(*assembler_tweak)->repeatable) { if (memchr(seen_options, c, seen_options_length) != NULL) { fprintf(stderr, "Command line argument -%c may not be repeated.\n", (int) c); CLEANUP(); return false; } if (seen_options_length == MAX_OPT_LIST) { fprintf(stderr, "Too many command line arguments.\n"); CLEANUP(); return false; } seen_options[seen_options_length++] = c; } it = (*options_used)++; if (it >= options_length) { fprintf(stderr, "Too many command line arguments.\n"); CLEANUP(); return false; } options[it].tweak = *assembler_tweak; if ((*assembler_tweak)->takes_argument != NULL) { options[it].arg = malloc(strlen(optarg) + 1); memcpy(options[it].arg, optarg, strlen(optarg) + 1); } else { options[it].arg = NULL; } } else { fprintf(stderr, "Unhandled command line argument -%c. This is a bug.\n", (int) c); CLEANUP(); return false; } } } MAYBE(args_unused) = optind; if (optind < args_length && (((int) args[optind][0]) & 0x80) != 0) { fprintf(stderr, "You pasted stuff from the man page. Replace the dashes with hyphens.\n"); CLEANUP(); return false; } return true; }