mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge pull request #6709 from dearblue/mrb_ensure
This commit is contained in:
@@ -1615,6 +1615,10 @@ mrbmemset(void *s, int c, size_t n)
|
||||
|
||||
#define mrb_int_hash_func(mrb,key) (uint32_t)((key)^((key)<<2)^((key)>>2))
|
||||
|
||||
#define MRB_UNIQNAME(name) MRB_UNIQNAME_1(name, __LINE__)
|
||||
#define MRB_UNIQNAME_1(name, line) MRB_UNIQNAME_2(name, line)
|
||||
#define MRB_UNIQNAME_2(name, line) name##line
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
#endif /* MRUBY_H */
|
||||
|
||||
@@ -127,6 +127,42 @@ MRB_API mrb_value mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_val
|
||||
mrb_func_t rescue, mrb_value r_data,
|
||||
mrb_int len, struct RClass **classes);
|
||||
|
||||
/**
|
||||
* Calls `func` via `mrb_protect_error()` and then always executes the user block exactly once.
|
||||
* Even if a global jump (similar to a Ruby exception) occurs within `func`, the block will be executed,
|
||||
* and after the block's completion, the global jump will be re-thrown.
|
||||
*
|
||||
* By checking `mrb->exc != NULL` within the block, you can determine if a global jump occurred in `func`.
|
||||
*
|
||||
* If you want to suppress the global jump and continue processing, use `mrb_clear_error(mrb); break;`.
|
||||
*
|
||||
* - `mrb`: The mruby state reference
|
||||
* - `result_var`: Pre-defined mrb_value type variable (to receive `func`'s return value)
|
||||
* - `func`: Function to call (compatible with `mrb_protect_error_func`)
|
||||
* - `data`: User data to pass to `func`
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* mrb_value result;
|
||||
* MRB_ENSURE(mrb, result, body_func, userdata) {
|
||||
* // This block is always executed (equivalent to Ruby's ensure)
|
||||
*
|
||||
* if (mrb->exc) {
|
||||
* // Post-processing when an exception occurs
|
||||
* }
|
||||
*
|
||||
* // To ignore the global jump, use `mrb_clear_error(mrb); break;` here
|
||||
* }
|
||||
*/
|
||||
#define MRB_ENSURE(mrb, result_var, func, data) \
|
||||
for (mrb_bool MRB_UNIQNAME(_break_) = FALSE; \
|
||||
!MRB_UNIQNAME(_break_) && \
|
||||
(((result_var) = mrb_protect_error(mrb, func, data, &MRB_UNIQNAME(_break_))), \
|
||||
((mrb)->exc = (MRB_UNIQNAME(_break_) ? mrb_obj_ptr((result_var)) : NULL)), \
|
||||
TRUE); \
|
||||
(void)(MRB_UNIQNAME(_break_) && (mrb)->jmp && (mrb_exc_raise(mrb, result_var), TRUE)), \
|
||||
MRB_UNIQNAME(_break_) = TRUE)
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
#endif /* MRUBY_ERROR_H */
|
||||
|
||||
@@ -2,5 +2,4 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Array class extension'
|
||||
spec.add_dependency 'mruby-error'
|
||||
end
|
||||
|
||||
@@ -452,9 +452,9 @@ struct ary_subtract_ctx {
|
||||
};
|
||||
|
||||
static mrb_value
|
||||
ary_subtract_body(mrb_state *mrb, mrb_value data)
|
||||
ary_subtract_body(mrb_state *mrb, void *data)
|
||||
{
|
||||
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)mrb_cptr(data);
|
||||
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)data;
|
||||
|
||||
for (mrb_int i = 0; i < ctx->argc; i++) {
|
||||
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
|
||||
@@ -471,14 +471,6 @@ ary_subtract_body(mrb_state *mrb, mrb_value data)
|
||||
return ctx->result;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_subtract_ensure(mrb_state *mrb, mrb_value data)
|
||||
{
|
||||
struct ary_subtract_ctx *ctx = (struct ary_subtract_ctx *)mrb_cptr(data);
|
||||
ary_destroy_temp_set(mrb, ctx->set);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
|
||||
{
|
||||
@@ -502,8 +494,9 @@ ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_va
|
||||
ary_init_temp_set(mrb, set, total_len);
|
||||
|
||||
struct ary_subtract_ctx ctx = { set, self, result, argv_copies, argc };
|
||||
mrb_ensure(mrb, ary_subtract_body, mrb_cptr_value(mrb, &ctx),
|
||||
ary_subtract_ensure, mrb_cptr_value(mrb, &ctx));
|
||||
MRB_ENSURE(mrb, result, ary_subtract_body, &ctx) {
|
||||
ary_destroy_temp_set(mrb, set);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mrb_int self_len = RARRAY_LEN(self);
|
||||
@@ -588,9 +581,9 @@ struct ary_union_ctx {
|
||||
};
|
||||
|
||||
static mrb_value
|
||||
ary_union_body(mrb_state *mrb, mrb_value data)
|
||||
ary_union_body(mrb_state *mrb, void *data)
|
||||
{
|
||||
struct ary_union_ctx *ctx = (struct ary_union_ctx *)mrb_cptr(data);
|
||||
struct ary_union_ctx *ctx = (struct ary_union_ctx *)data;
|
||||
|
||||
/* Add unique elements from self */
|
||||
for (mrb_int i = 0; i < RARRAY_LEN(ctx->self_copy); i++) {
|
||||
@@ -618,14 +611,6 @@ ary_union_body(mrb_state *mrb, mrb_value data)
|
||||
return ctx->result;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_union_ensure(mrb_state *mrb, mrb_value data)
|
||||
{
|
||||
struct ary_union_ctx *ctx = (struct ary_union_ctx *)mrb_cptr(data);
|
||||
ary_destroy_temp_set(mrb, ctx->set);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_union_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
|
||||
{
|
||||
@@ -646,8 +631,9 @@ ary_union_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value
|
||||
ary_init_temp_set(mrb, set, total_len);
|
||||
|
||||
struct ary_union_ctx ctx = { set, self_copy, result, argv_copies, argc };
|
||||
mrb_ensure(mrb, ary_union_body, mrb_cptr_value(mrb, &ctx),
|
||||
ary_union_ensure, mrb_cptr_value(mrb, &ctx));
|
||||
MRB_ENSURE(mrb, result, ary_union_body, &ctx) {
|
||||
ary_destroy_temp_set(mrb, set);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use linear search for small arrays */
|
||||
@@ -717,9 +703,9 @@ struct ary_intersection_ctx {
|
||||
};
|
||||
|
||||
static mrb_value
|
||||
ary_intersection_body(mrb_state *mrb, mrb_value data)
|
||||
ary_intersection_body(mrb_state *mrb, void *data)
|
||||
{
|
||||
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)mrb_cptr(data);
|
||||
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)data;
|
||||
|
||||
for (mrb_int i = 0; i < ctx->argc; i++) {
|
||||
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
|
||||
@@ -737,14 +723,6 @@ ary_intersection_body(mrb_state *mrb, mrb_value data)
|
||||
return ctx->result;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_intersection_ensure(mrb_state *mrb, mrb_value data)
|
||||
{
|
||||
struct ary_intersection_ctx *ctx = (struct ary_intersection_ctx *)mrb_cptr(data);
|
||||
ary_destroy_temp_set(mrb, ctx->set);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value *argv)
|
||||
{
|
||||
@@ -768,8 +746,9 @@ ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mr
|
||||
ary_init_temp_set(mrb, set, total_len);
|
||||
|
||||
struct ary_intersection_ctx ctx = { set, self, result, argv_copies, argc };
|
||||
mrb_ensure(mrb, ary_intersection_body, mrb_cptr_value(mrb, &ctx),
|
||||
ary_intersection_ensure, mrb_cptr_value(mrb, &ctx));
|
||||
MRB_ENSURE(mrb, result, ary_intersection_body, &ctx) {
|
||||
ary_destroy_temp_set(mrb, set);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mrb_int self_len = RARRAY_LEN(self);
|
||||
@@ -869,9 +848,9 @@ struct ary_intersect_p_ctx {
|
||||
};
|
||||
|
||||
static mrb_value
|
||||
ary_intersect_p_body(mrb_state *mrb, mrb_value data)
|
||||
ary_intersect_p_body(mrb_state *mrb, void *data)
|
||||
{
|
||||
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)mrb_cptr(data);
|
||||
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)data;
|
||||
|
||||
ary_populate_temp_set(mrb, ctx->set, ctx->shorter_ary_copy);
|
||||
|
||||
@@ -886,14 +865,6 @@ ary_intersect_p_body(mrb_state *mrb, mrb_value data)
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_intersect_p_ensure(mrb_state *mrb, mrb_value data)
|
||||
{
|
||||
struct ary_intersect_p_ctx *ctx = (struct ary_intersect_p_ctx *)mrb_cptr(data);
|
||||
ary_destroy_temp_set(mrb, ctx->set);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_intersect_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -924,8 +895,10 @@ ary_intersect_p(mrb_state *mrb, mrb_value self)
|
||||
mrb_bool found = FALSE;
|
||||
|
||||
struct ary_intersect_p_ctx ctx = { set, shorter_ary_copy, longer_ary, &found };
|
||||
mrb_ensure(mrb, ary_intersect_p_body, mrb_cptr_value(mrb, &ctx),
|
||||
ary_intersect_p_ensure, mrb_cptr_value(mrb, &ctx));
|
||||
mrb_value result;
|
||||
MRB_ENSURE(mrb, result, ary_intersect_p_body, &ctx) {
|
||||
ary_destroy_temp_set(mrb, set);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return mrb_true_value();
|
||||
@@ -1089,9 +1062,9 @@ struct ary_uniq_bang_ctx {
|
||||
};
|
||||
|
||||
static mrb_value
|
||||
ary_uniq_bang_body(mrb_state *mrb, mrb_value data)
|
||||
ary_uniq_bang_body(mrb_state *mrb, void *data)
|
||||
{
|
||||
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)mrb_cptr(data);
|
||||
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)data;
|
||||
|
||||
ary_populate_temp_set(mrb, ctx->set, ctx->self_copy);
|
||||
|
||||
@@ -1110,14 +1083,6 @@ ary_uniq_bang_body(mrb_state *mrb, mrb_value data)
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_uniq_bang_ensure(mrb_state *mrb, mrb_value data)
|
||||
{
|
||||
struct ary_uniq_bang_ctx *ctx = (struct ary_uniq_bang_ctx *)mrb_cptr(data);
|
||||
ary_destroy_temp_set(mrb, ctx->set);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
ary_uniq_bang(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -1139,8 +1104,10 @@ ary_uniq_bang(mrb_state *mrb, mrb_value self)
|
||||
ary_init_temp_set(mrb, set, len);
|
||||
|
||||
struct ary_uniq_bang_ctx ctx = { set, self_copy, self, &write_pos, len };
|
||||
mrb_ensure(mrb, ary_uniq_bang_body, mrb_cptr_value(mrb, &ctx),
|
||||
ary_uniq_bang_ensure, mrb_cptr_value(mrb, &ctx));
|
||||
mrb_value result;
|
||||
MRB_ENSURE(mrb, result, ary_uniq_bang_body, &ctx) {
|
||||
ary_destroy_temp_set(mrb, set);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (mrb_int read_pos = 0; read_pos < len; read_pos++) {
|
||||
|
||||
@@ -2127,16 +2127,11 @@ static void
|
||||
mpz_mul_all_ones(mpz_ctx_t *ctx, mpz_t *w, size_t n, size_t m)
|
||||
{
|
||||
struct mpz_mul_all_ones_data d = {ctx, w, n, m, {0,0,0}, {0,0,0}};
|
||||
mrb_bool error = FALSE;
|
||||
|
||||
mrb_value exc = mrb_protect_error(MPZ_MRB(ctx), mpz_mul_all_ones_body, &d, &error);
|
||||
|
||||
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
|
||||
mpz_clear(ctx, &d.a);
|
||||
mpz_clear(ctx, &d.b);
|
||||
|
||||
if (error) {
|
||||
mrb_exc_raise(MPZ_MRB(ctx), exc);
|
||||
mrb_value exc;
|
||||
MRB_ENSURE(MPZ_MRB(ctx), exc, mpz_mul_all_ones_body, &d) {
|
||||
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
|
||||
mpz_clear(ctx, &d.a);
|
||||
mpz_clear(ctx, &d.b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3731,18 +3726,14 @@ mpz_get_str_dc(mpz_ctx_t *ctx, char *s, mpz_t *x)
|
||||
d.num_digits = num_digits;
|
||||
d.num_powers = 0;
|
||||
|
||||
mrb_bool error = FALSE;
|
||||
mrb_value exc = mrb_protect_error(MPZ_MRB(ctx), mpz_get_str_dc_body, &d, &error);
|
||||
|
||||
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
|
||||
for (size_t i = 0; i < d.num_powers; i++) {
|
||||
mpz_clear(ctx, &d.pow5[i]);
|
||||
}
|
||||
mpz_clear(ctx, &d.tmp);
|
||||
dc_scratch_clear(ctx, &d.scratch);
|
||||
|
||||
if (error) {
|
||||
mrb_exc_raise(MPZ_MRB(ctx), exc);
|
||||
mrb_value exc;
|
||||
MRB_ENSURE(MPZ_MRB(ctx), exc, mpz_get_str_dc_body, &d) {
|
||||
/* Cleanup always runs (mpz_clear is safe on zero-initialized mpz_t) */
|
||||
for (size_t i = 0; i < d.num_powers; i++) {
|
||||
mpz_clear(ctx, &d.pow5[i]);
|
||||
}
|
||||
mpz_clear(ctx, &d.tmp);
|
||||
dc_scratch_clear(ctx, &d.scratch);
|
||||
}
|
||||
|
||||
/* Remove leading zeros (but keep at least one digit) */
|
||||
|
||||
@@ -252,11 +252,11 @@ binding_eval_prepare(mrb_state *mrb, mrb_value binding, const char *expr, mrb_in
|
||||
d.cxt->upper = proc;
|
||||
d.pstate = mrb_parse_nstring(mrb, expr, exprlen, d.cxt);
|
||||
|
||||
mrb_bool error;
|
||||
mrb_value ret = mrb_protect_error(mrb, binding_eval_prepare_body, &d, &error);
|
||||
if (d.pstate) mrb_parser_free(d.pstate);
|
||||
if (d.cxt) mrb_ccontext_free(mrb, d.cxt);
|
||||
if (error) mrb_exc_raise(mrb, ret);
|
||||
mrb_value ret;
|
||||
MRB_ENSURE(mrb, ret, binding_eval_prepare_body, &d) {
|
||||
if (d.pstate) mrb_parser_free(d.pstate);
|
||||
if (d.cxt) mrb_ccontext_free(mrb, d.cxt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user