From 5f68ad764a2d16a199bbd5df0539609bcd69f898 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Tue, 17 Mar 2020 08:29:19 -0700
Subject: [PATCH] add printable_iter

---
 stdio.hpp          | 79 ++++++++++++++++------------------------------
 test/src/common.cc | 11 +++++++
 2 files changed, 39 insertions(+), 51 deletions(-)

diff --git a/stdio.hpp b/stdio.hpp
index 80d6e6b..6cca73b 100644
--- a/stdio.hpp
+++ b/stdio.hpp
@@ -80,14 +80,6 @@ namespace rlib {
     void println();
     template <typename... Args>
     void print(Args... args);
-    template <typename Iterable, typename Printable>
-    void print_iter(Iterable arg, Printable spliter);
-    template <typename Iterable, typename Printable>
-    void println_iter(Iterable arg, Printable spliter);
-    template <typename Iterable>
-    void print_iter(Iterable arg);
-    template <typename Iterable>
-    void println_iter(Iterable arg);
     template <typename... Args>
     size_t printf(const std::string &fmt, Args... args);
     template <typename... Args>
@@ -100,6 +92,23 @@ namespace rlib {
             static bool instance = true;
             return instance;
         }
+
+        template <typename Iterable, typename Printable>
+        struct _printable_iterable : private std::pair<Iterable, Printable> {
+            using std::pair<Iterable, Printable>::pair;
+            const Iterable &arg() const {return std::pair<Iterable, Printable>::first;}
+            const Printable &spliter() const {return std::pair<Iterable, Printable>::second;}
+        };
+    }
+
+    // 2 more interfaces...
+    template <typename Iterable, typename Printable>
+    const impl::_printable_iterable<Iterable, Printable> printable_iter(Iterable arg, Printable spliter) {
+        return impl::_printable_iterable<Iterable, Printable>(arg, spliter);
+    }
+    template <typename Iterable>
+    const impl::_printable_iterable<Iterable, char> printable_iter(Iterable arg) {
+        return impl::_printable_iterable<Iterable, char>(arg, ' ');
     }
 
     inline bool sync_with_stdio(bool sync = true) noexcept {
@@ -122,18 +131,18 @@ namespace rlib {
     template <typename PrintFinalT>
     void print(std::ostream &os, PrintFinalT reqArg)
     {
-        os << reqArg;
+        os << std::forward<PrintFinalT>(reqArg);
     }
     template <typename Required, typename... Optional>
     void print(std::ostream &os, Required reqArgs, Optional... optiArgs)
     {
         os << reqArgs << ' ';
-        print(os, optiArgs ...);
+        print(os, std::forward<Optional>(optiArgs) ...);
     }
     template <typename... Optional>
     void println(std::ostream &os, Optional... optiArgs)
     {
-        print(os, optiArgs ...);
+        print(os, std::forward<Optional>(optiArgs) ...);
         println(os);
     }
     template <> 
@@ -142,29 +151,6 @@ namespace rlib {
         os << rlib::endl;
     }
 
-    template <typename Iterable, typename Printable>
-    void print_iter(std::ostream &os, Iterable arg, Printable spliter)
-    {
-        for(const auto & i : arg)
-            os << i << spliter;
-    }
-    template <typename Iterable, typename Printable>
-    void println_iter(std::ostream &os, Iterable arg, Printable spliter)
-    {
-        print_iter(os, arg, spliter);
-        println(os);
-    }
-    template <typename Iterable>
-    void print_iter(std::ostream &os, Iterable arg)
-    {
-        print_iter(os, arg, ' ');
-    }
-    template <typename Iterable>
-    void println_iter(std::ostream &os, Iterable arg)
-    {
-        println_iter(os, arg, ' ');
-    }
-
     template <typename... Args>
     size_t printf(std::ostream &os, const std::string &fmt, Args... args)
     {
@@ -195,22 +181,6 @@ namespace rlib {
     void print(Args... args) {
         return print(std::cout, std::forward<Args>(args) ...);
     }
-    template <typename Iterable, typename Printable>
-    void print_iter(Iterable arg, Printable spliter) {
-        return print_iter(std::cout, std::forward<Iterable>(arg), spliter);
-    }
-    template <typename Iterable, typename Printable>
-    void println_iter(Iterable arg, Printable spliter) {
-        return println_iter(std::cout, std::forward<Iterable>(arg), spliter);
-    }
-    template <typename Iterable>
-    void print_iter(Iterable arg) {
-        return print_iter(std::cout, std::forward<Iterable>(arg));
-    }
-    template <typename Iterable>
-    void println_iter(Iterable arg) {
-        return println_iter(std::cout, std::forward<Iterable>(arg));
-    }
     template <typename... Args>
     size_t printf(const std::string &fmt, Args... args) {
         return printf(std::cout, fmt, std::forward<Args>(args) ...);
@@ -237,7 +207,14 @@ namespace rlib {
             std::ostream &, impl::print_wrapper<StreamType>>::type;
         return print(static_cast<ostream_or_data>(os), std::forward<Args>(args) ...);
     }
-}
+} // end namespace rlib
 
+template <typename Iterable, typename Printable>
+std::ostream& operator<< (std::ostream& stream, const rlib::impl::_printable_iterable<Iterable, Printable> &p) {
+    for(auto val : p.arg()) {
+        stream << val << p.spliter();
+    }
+    return stream;
+}
 
 #endif
diff --git a/test/src/common.cc b/test/src/common.cc
index e038767..c17ab4f 100644
--- a/test/src/common.cc
+++ b/test/src/common.cc
@@ -62,6 +62,10 @@ struct rlib_test_printable {
         return stream;
     }
 };
+struct rlib_test_iterable : public std::vector<float> {
+    using std::vector<float>::vector;
+};
+
 TEST_CASE("stdio.hpp") {
     std::stringstream test_ss;
     rlib::print(test_ss, '>');
@@ -72,6 +76,13 @@ TEST_CASE("stdio.hpp") {
     rlib::printfln(test_ss, "hello, {}.", "godaddy");
     REQUIRE(rlib::scanln(test_ss) == ">a b 123 0.25 2");
     REQUIRE(rlib::scanln(test_ss) == "1hello, godaddy.");
+
+    rlib_test_iterable v{1.2, 6.666, 12, -11.11};
+    std::string answer = "1.21.2 6.666 12 -11.11 6.6661.2 6.666 12 -11.11 121.2 6.666 12 -11.11 -11.111.2 6.666 12 -11.11 ";
+    std::stringstream ss1, ss2;
+    rlib::println(ss1, rlib::printable_iter(v, rlib::printable_iter(v)));
+    rlib::print(ss2, rlib::printable_iter(v, rlib::printable_iter(v)));
+    rlib::println(ss1.str() == answer + '\n', ss2.str() == answer);
 }
 
 
-- 
GitLab