summaryrefslogtreecommitdiff
path: root/regcomp.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2023-06-09 16:10:30 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2023-06-09 20:22:30 +0900
commitab6eb3786c94e69c561080cbb796c2381702a3a4 (patch)
tree2fe551edd62566939a7760439851fd7ad90b2d13 /regcomp.c
parentd54f66d1b4ce32d78b526b1ea9e3f213a763d07c (diff)
Optimize `Regexp#dup` and `Regexp.new(/RE/)`
When copying from another regexp, copy already built `regex_t` instead of re-compiling its source.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/7922
Diffstat (limited to 'regcomp.c')
-rw-r--r--regcomp.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/regcomp.c b/regcomp.c
index be85d85f93..b4dbddfa01 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -5671,6 +5671,80 @@ onig_free(regex_t* reg)
}
}
+static void*
+dup_copy(const void *ptr, size_t size)
+{
+ void *newptr = xmalloc(size);
+ if (IS_NOT_NULL(newptr)) {
+ memcpy(newptr, ptr, size);
+ }
+ return newptr;
+}
+
+extern int
+onig_reg_copy(regex_t** nreg, regex_t* oreg)
+{
+ if (IS_NOT_NULL(oreg)) {
+ regex_t *reg = *nreg = (regex_t* )xmalloc(sizeof(regex_t));
+ if (IS_NULL(reg)) return ONIGERR_MEMORY;
+
+ *reg = *oreg;
+
+# define COPY_FAILED(mem, size) IS_NULL(reg->mem = dup_copy(reg->mem, size))
+
+ if (IS_NOT_NULL(reg->exact)) {
+ size_t exact_size = reg->exact_end - reg->exact;
+ if (COPY_FAILED(exact, exact_size))
+ goto err;
+ (reg)->exact_end = (reg)->exact + exact_size;
+ }
+
+ if (IS_NOT_NULL(reg->int_map)) {
+ if (COPY_FAILED(int_map, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
+ goto err_int_map;
+ }
+ if (IS_NOT_NULL(reg->int_map_backward)) {
+ if (COPY_FAILED(int_map_backward, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
+ goto err_int_map_backward;
+ }
+ if (IS_NOT_NULL(reg->p)) {
+ if (COPY_FAILED(p, reg->alloc))
+ goto err_p;
+ }
+ if (IS_NOT_NULL(reg->repeat_range)) {
+ if (COPY_FAILED(repeat_range, reg->repeat_range_alloc * sizeof(OnigRepeatRange)))
+ goto err_repeat_range;
+ }
+ if (IS_NOT_NULL(reg->name_table)) {
+ if (IS_NULL(reg->name_table = st_copy(reg->name_table)))
+ goto err_name_table;
+ }
+ if (IS_NOT_NULL(reg->chain)) {
+ if (onig_reg_copy(&reg->chain, reg->chain))
+ goto err_chain;
+ }
+ return 0;
+# undef COPY_FAILED
+
+ err_chain:
+ onig_st_free_table(reg->name_table);
+ err_name_table:
+ xfree(reg->repeat_range);
+ err_repeat_range:
+ xfree(reg->p);
+ err_p:
+ xfree(reg->int_map_backward);
+ err_int_map_backward:
+ xfree(reg->int_map);
+ err_int_map:
+ xfree(reg->exact);
+ err:
+ xfree(reg);
+ return ONIGERR_MEMORY;
+ }
+ return 0;
+}
+
#ifdef RUBY
size_t
onig_memsize(const regex_t *reg)