From 233d58c81a3b5bc9b6d01d4555302d588d9f3e59 Mon Sep 17 00:00:00 2001
From: Sandipan Mohanty <s.mohanty@fz-juelich.de>
Date: Fri, 13 May 2022 12:00:33 +0200
Subject: [PATCH] Provide range_output.hh

---
 code/include/range_output.hh | 113 +++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 code/include/range_output.hh

diff --git a/code/include/range_output.hh b/code/include/range_output.hh
new file mode 100644
index 0000000..65508ea
--- /dev/null
+++ b/code/include/range_output.hh
@@ -0,0 +1,113 @@
+#pragma once
+#include <algorithm>
+#include <iomanip>
+#include <iosfwd>
+#include <cxx20ranges>
+#include <string>
+
+namespace output {
+template <class C>
+concept RawArray = std::is_array_v<C>;
+template <class C>
+concept ArrayClass = requires(C c)
+{
+    { c[1ul] };
+    { c.size() };
+};
+
+template <class C>
+concept StringLike = std::convertible_to<C, std::string_view>;
+
+namespace {
+    //auto size(const Container auto& C) { return C.size(); }
+    auto size(const RawArray auto& C) { return std::extent_v<std::remove_cvref_t<decltype(C)>>; }
+}
+
+template <class C>
+concept ArrayLike = (not StringLike<C>)and(ArrayClass<C> or RawArray<C>);
+
+template <class T>
+void write_possibly_quoted(std::ostream& os, T&& t)
+{
+    if constexpr (StringLike<T>) {
+        os << std::quoted(t);
+    } else {
+        os << t;
+    }
+}
+
+std::ostream& operator<<(std::ostream& os, const ArrayLike auto& c)
+{
+    os << "[";
+    auto sz = size(c);
+    for (size_t i {}; i != sz; ++i) {
+        write_possibly_quoted(os, c[i]);
+        if (i + 1 < sz)
+            os << ", ";
+    }
+    return os << "]";
+}
+
+template <class T>
+requires(not StringLike<T> and sr::range<T>)
+    std::ostream&
+    operator<<(std::ostream& os, T&& r)
+{
+    os << "[";
+    for (auto el : r) {
+        write_possibly_quoted(os, el);
+        os << ", ";
+    }
+    return os << "]";
+}
+template <class SepType>
+class rprinter {
+    std::ostream* strmptr = nullptr;
+    SepType sep;
+
+public:
+    rprinter(SepType s)
+        : sep { s }
+    {
+    }
+    rprinter(const rprinter&) noexcept = default;
+    std::ostream& stream() { return *strmptr; }
+    void stream(std::ostream& os) { strmptr = &os; }
+    const auto& separator() const noexcept { return sep; }
+};
+template <>
+class rprinter<void> {
+    std::ostream* strmptr = nullptr;
+
+public:
+    std::ostream& stream() { return *strmptr; }
+    void stream(std::ostream& os) { strmptr = &os; }
+};
+
+template <class T>
+rprinter<T> operator<<(std::ostream& os, rprinter<T> r)
+{
+    r.stream(os);
+    return { r };
+}
+template <class T>
+std::ostream& operator<<(rprinter<T> vp, sr::range auto&& t)
+{
+    if constexpr (std::is_same_v<T, void>) {
+        for (auto&& el : t)
+            vp.stream() << el;
+    } else {
+        if (not sr::empty(t)) {
+            vp.stream() << *sr::begin(t);
+            sr::for_each(t | sv::drop(1), [&vp](auto&& el) {
+                vp.stream() << vp.separator() << el;
+            });
+        }
+    }
+    return vp.stream();
+}
+
+inline rprinter<void> unseparated;
+inline rprinter<const char*> comma_separated { ", " };
+
+}
-- 
GitLab