Exemple #1
0
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;
}
Exemple #2
0
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;
}