Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 79 additions & 24 deletions ext/version_sorter/version_sorter.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,43 +171,75 @@ parse_version_number(const char *string)
return version;
}

struct sort_context {
VALUE rb_self;
VALUE rb_version_array;
compare_callback_t *cmp;
struct version_number **versions;
};

static VALUE
rb_version_sort_1(VALUE rb_self, VALUE rb_version_array, compare_callback_t cmp)
rb_version_sort_1_cb(VALUE arg)
{
struct version_number **versions;
struct sort_context *context = (struct sort_context *)arg;
long length, i;
VALUE *rb_version_ptr;

Check_Type(rb_version_array, T_ARRAY);

length = RARRAY_LEN(rb_version_array);
if (!length)
return rb_ary_new();

versions = xcalloc(length, sizeof(struct version_number *));

length = RARRAY_LEN(context->rb_version_array);
for (i = 0; i < length; ++i) {
VALUE rb_version, rb_version_string;

rb_version = rb_ary_entry(rb_version_array, i);
rb_version = rb_ary_entry(context->rb_version_array, i);
if (rb_block_given_p())
rb_version_string = rb_yield(rb_version);
else
rb_version_string = rb_version;

versions[i] = parse_version_number(StringValueCStr(rb_version_string));
versions[i]->rb_version = rb_version;
context->versions[i] = parse_version_number(StringValueCStr(rb_version_string));
context->versions[i]->rb_version = rb_version;
}

qsort(context->versions, length, sizeof(struct version_number *), context->cmp);
rb_version_ptr = RARRAY_PTR(context->rb_version_array);

for (i = 0; i < length; ++i) {
rb_version_ptr[i] = context->versions[i]->rb_version;
}

qsort(versions, length, sizeof(struct version_number *), cmp);
rb_version_ptr = RARRAY_PTR(rb_version_array);
return context->rb_version_array;
}

static VALUE
rb_version_sort_1(VALUE rb_self, VALUE rb_version_array, compare_callback_t cmp)
{
long length, i;
int exception;

Check_Type(rb_version_array, T_ARRAY);

length = RARRAY_LEN(rb_version_array);
if (!length)
return rb_ary_new();

struct sort_context context = {
rb_self,
rb_version_array,
cmp,
xcalloc(length, sizeof(struct version_number *)),
};

VALUE result = rb_protect(rb_version_sort_1_cb, (VALUE)&context, &exception);

for (i = 0; i < length; ++i) {
rb_version_ptr[i] = versions[i]->rb_version;
xfree(versions[i]);
xfree(context.versions[i]);
}
xfree(versions);
return rb_version_array;
xfree(context.versions);

if (exception) {
rb_jump_tag(exception);
}

return result;
}

static VALUE
Expand All @@ -234,16 +266,39 @@ rb_version_sort_r_bang(VALUE rb_self, VALUE rb_versions)
return rb_version_sort_1(rb_self, rb_versions, version_compare_cb_r);
}

struct compare_context {
VALUE rb_version_a, rb_version_b;
struct version_number *version_a, *version_b;
};

static VALUE
rb_version_compare_cb(VALUE arg)
{
struct compare_context *context = (struct compare_context *)arg;

context->version_a = parse_version_number(StringValueCStr(context->rb_version_a));
context->version_b = parse_version_number(StringValueCStr(context->rb_version_b));

return INT2NUM(version_compare_cb(&context->version_a, &context->version_b));
}

static VALUE
rb_version_compare(VALUE rb_self, VALUE rb_version_a, VALUE rb_version_b)
{
struct version_number *version_a = parse_version_number(StringValueCStr(rb_version_a));
struct version_number *version_b = parse_version_number(StringValueCStr(rb_version_b));
int exception;
struct compare_context context = {
rb_version_a, rb_version_b,
NULL, NULL,
};

VALUE result = INT2NUM(version_compare_cb(&version_a, &version_b));
VALUE result = rb_protect(rb_version_compare_cb, (VALUE)&context, &exception);

xfree(version_a);
xfree(version_b);
xfree(context.version_a);
xfree(context.version_b);

if (exception) {
rb_jump_tag(exception);
}

return result;
}
Expand Down