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 <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-08-17 08:07:30 +09:00
parent c699b211d7
commit 2113b7cd23
2 changed files with 35 additions and 19 deletions
-19
View File
@@ -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:
+35
View File
@@ -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));