Repositories / jai.git

jai.git

Clone (read-only): git clone http://git.guha-anderson.com/git/jai.git

Branch

make it work with clang libc++

Author
David Mazieres <dm@uun.org>
Date
2026-03-28 13:21:10 -0700
Commit
19b73f553a7f0ac6d5ccc332ab9973f6548492f2
Makefile.am
index eed0201..9144168 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ AM_CXXFLAGS = $(MOUNT_CFLAGS) $(LIBACL_CFLAGS)
 
 jai_SOURCES = complete.cc cred.cc default_conf.cc fs.cc jai.cc	\
 options.cc argtype.h config.h cred.h defer.h err.h fs.h jai.h	\
-options.h
+move_only_function.h options.h
 jai_LDADD = $(MOUNT_LIBS) $(LIBACL_LIBS)
 
 man1_MANS = jai.1
configure.ac
index 16288af..dea2d03 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,15 +12,9 @@ AC_PROG_CXX
 # Require C++23
 CXXFLAGS="$CXXFLAGS $CXXLANG"
 AC_LANG_PUSH([C++])
-AC_MSG_CHECKING(for working C++23 features)
+AC_MSG_CHECKING(for a working C++23 library)
 AC_COMPILE_IFELSE(
-  [AC_LANG_PROGRAM([
-#include <functional>
-#include <print>
-  ], [
-std::move_only_function<void()> f = []{};
-f();
-  ])],
+  [AC_LANG_PROGRAM([#include <print>], [])],
   [AC_MSG_RESULT(yes)],
   [AC_MSG_ERROR([a C++23 compiler is required])])
 AC_LANG_POP([C++])
defer.h
index f9f775c..879085b 100644
--- a/defer.h
+++ b/defer.h
@@ -3,6 +3,7 @@
 #pragma once
 
 #include "argtype.h"
+#include "move_only_function.h"
 
 #include <concepts>
 #include <functional>
@@ -78,5 +79,5 @@ struct NullaryInvoker {
 };
 } // namespace detail
 // Deferred cleanup action
-using Defer = RaiiHelper<detail::NullaryInvoker{},
-                         std::move_only_function<void()>, nullptr>;
+using Defer =
+    RaiiHelper<detail::NullaryInvoker{}, move_only_function<void()>, nullptr>;
move_only_function.h
new file mode 100644
index 0000000..a426f05
--- /dev/null
+++ b/move_only_function.h
@@ -0,0 +1,57 @@
+// -*-C++-*-
+
+#pragma once
+
+#include <functional>
+
+#if __cpp_lib_move_only_function >= 202110L
+
+using std::move_only_function;
+
+#else // std::move_only_function unimplemented
+
+#include <memory>
+
+template<typename F> struct move_only_function;
+
+template<typename R, typename... Args, bool NE>
+class move_only_function<R(Args...) noexcept(NE)> {
+public:
+  struct Invoker {
+    virtual ~Invoker() = default;
+    virtual R operator()(Args... args) noexcept(NE) = 0;
+  };
+  template<typename F> struct Impl : Invoker {
+    F f_;
+    // Impl(F f) : f_(std::move(f)) {}
+    template<typename RF> Impl(RF &&f) : f_(std::forward<RF>(f)) {}
+    R operator()(Args... args) noexcept(NE) override
+    {
+      return std::invoke(f_, std::forward<Args>(args)...);
+    }
+  };
+  template<typename F> Impl(F &&) -> Impl<std::decay_t<F>>;
+
+  std::unique_ptr<Invoker> inv_;
+
+public:
+  move_only_function() noexcept = default;
+  move_only_function(std::nullptr_t) noexcept {};
+  move_only_function(move_only_function &&) noexcept = default;
+
+  template<std::invocable<Args...> F>
+  move_only_function(F f) : inv_(new Impl{std::move(f)})
+  {}
+
+  move_only_function &operator=(move_only_function &&) noexcept = default;
+
+  R operator()(Args ...args) noexcept(NE)
+  {
+    return (*inv_)(std::forward<Args>(args)...);
+  }
+
+  explicit operator bool() noexcept { return inv_; }
+  bool operator==(std::nullptr_t) noexcept { return !inv_; }
+};
+
+#endif // std::move_only_function unimplemented
options.cc
index abf0255..dab7857 100644
--- a/options.cc
+++ b/options.cc
@@ -1,6 +1,8 @@
 
 #include "options.h"
 
+#include <algorithm>
+
 void
 Options::parse_file(std::string_view text, std::string_view errpath)
 {