From 2113b7cd23cbed04a5828142f46a59e0225accda Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 17 Aug 2025 08:07:30 +0900 Subject: [PATCH] mruby-dir: implement Dir.children in c for improved performance Moved Dir.children from Ruby to C implementation to eliminate Ruby loop overhead and string comparison inefficiencies. Uses existing skip_name_p helper to filter out "." and ".." entries efficiently in C. Co-authored-by: Claude --- mrbgems/mruby-dir/mrblib/dir.rb | 19 ------------------ mrbgems/mruby-dir/src/dir.c | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/mrbgems/mruby-dir/mrblib/dir.rb b/mrbgems/mruby-dir/mrblib/dir.rb index 358efd78c..71dd929f1 100644 --- a/mrbgems/mruby-dir/mrblib/dir.rb +++ b/mrbgems/mruby-dir/mrblib/dir.rb @@ -44,25 +44,6 @@ class Dir class << self - # - # call-seq: - # Dir.children(dirname) -> array - # - # Returns an array containing all of the filenames except for "." and ".." - # in the given directory. Will raise a SystemCallError if the named - # directory doesn't exist. - # - # Dir.children("testdir") #=> ["config.h", "main.rb"] - # - def children(path) - a = [] - self.open(path) do |d| - while s = d.read - a << s unless s == "." || s == ".." - end - end - a - end # # call-seq: diff --git a/mrbgems/mruby-dir/src/dir.c b/mrbgems/mruby-dir/src/dir.c index cfc7c3b0d..f0af492df 100644 --- a/mrbgems/mruby-dir/src/dir.c +++ b/mrbgems/mruby-dir/src/dir.c @@ -453,6 +453,40 @@ mrb_dir_entries(mrb_state *mrb, mrb_value klass) return ary; } +/* + * call-seq: + * Dir.children(dirname) -> array + * + * Returns an array containing all of the filenames except for "." and ".." + * in the given directory. Will raise a SystemCallError if the named + * directory doesn't exist. + */ +static mrb_value +mrb_dir_children(mrb_state *mrb, mrb_value klass) +{ + const char *path; + DIR *dir; + struct dirent *dp; + mrb_value ary; + + mrb_get_args(mrb, "z", &path); + + dir = opendir(path); + if (dir == NULL) { + mrb_sys_fail(mrb, path); + } + + ary = mrb_ary_new(mrb); + while ((dp = readdir(dir)) != NULL) { + if (!skip_name_p(dp->d_name)) { + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, dp->d_name)); + } + } + + closedir(dir); + return ary; +} + void mrb_mruby_dir_gem_init(mrb_state *mrb) { @@ -468,6 +502,7 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) mrb_define_class_method_id(mrb, d, MRB_SYM(chroot), mrb_dir_chroot, MRB_ARGS_REQ(1)); mrb_define_class_method_id(mrb, d, MRB_SYM_Q(empty), mrb_dir_empty, MRB_ARGS_REQ(1)); mrb_define_class_method_id(mrb, d, MRB_SYM(entries), mrb_dir_entries, MRB_ARGS_REQ(1)); + mrb_define_class_method_id(mrb, d, MRB_SYM(children), mrb_dir_children, MRB_ARGS_REQ(1)); mrb_define_method_id(mrb, d, MRB_SYM(close), mrb_dir_close, MRB_ARGS_NONE()); mrb_define_method_id(mrb, d, MRB_SYM(initialize), mrb_dir_init, MRB_ARGS_REQ(1));