util: backport std::experimental::ostream_joiner
Change-Id: I4d12269ac41f07d224772abc0e50039be519fdcc
Refs: #3962
diff --git a/src/encoding/nfd-constants.cpp b/src/encoding/nfd-constants.cpp
index 2b9f8ff..b502a9c 100644
--- a/src/encoding/nfd-constants.cpp
+++ b/src/encoding/nfd-constants.cpp
@@ -119,36 +119,25 @@
return os << "none";
}
- bool isFirst = true;
- auto printToken = [&os, &isFirst] (const std::string& token) {
- if (isFirst) {
- isFirst = false;
- }
- else {
- os << '|';
- }
- os << token;
- };
-
static const std::map<RouteFlags, std::string> knownBits = {
{ROUTE_FLAG_CHILD_INHERIT, "child-inherit"},
- {ROUTE_FLAG_CAPTURE, "capture"}};
+ {ROUTE_FLAG_CAPTURE, "capture"}
+ };
+
+ auto join = make_ostream_joiner(os, '|');
for (const auto& pair : knownBits) {
RouteFlags bit = ROUTE_FLAGS_NONE;
std::string token;
std::tie(bit, token) = pair;
if ((routeFlags & bit) != 0) {
- printToken(token);
+ join = token;
routeFlags = static_cast<RouteFlags>(routeFlags & ~bit);
}
}
if (routeFlags != ROUTE_FLAGS_NONE) {
- if (!isFirst) {
- os << '|';
- }
- os << AsHex{routeFlags};
+ join = AsHex{routeFlags};
}
return os;
diff --git a/src/exclude.cpp b/src/exclude.cpp
index 7007daf..0f339e0 100644
--- a/src/exclude.cpp
+++ b/src/exclude.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+ * Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -24,7 +24,7 @@
#include "exclude.hpp"
#include "encoding/block-helpers.hpp"
-#include <boost/range/adaptors.hpp>
+#include <boost/range/adaptor/reversed.hpp>
namespace ndn {
@@ -317,19 +317,13 @@
std::ostream&
operator<<(std::ostream& os, const Exclude& exclude)
{
- bool isFirst = true;
+ auto join = make_ostream_joiner(os, ',');
for (const Exclude::Entry& entry : exclude.m_entries | boost::adaptors::reversed) {
if (!entry.first.isNegInf) {
- if (!isFirst)
- os << ",";
- entry.first.component.toUri(os);
- isFirst = false;
+ join = entry.first.component;
}
if (entry.second) {
- if (!isFirst)
- os << ",";
- os << "*";
- isFirst = false;
+ join = '*';
}
}
return os;
diff --git a/src/mgmt/nfd/fib-entry.cpp b/src/mgmt/nfd/fib-entry.cpp
index e3633aa..db3b69f 100644
--- a/src/mgmt/nfd/fib-entry.cpp
+++ b/src/mgmt/nfd/fib-entry.cpp
@@ -269,13 +269,9 @@
os << "FibEntry(Prefix: " << entry.getPrefix() << ",\n"
<< " NextHops: [";
- bool first = true;
- for (const auto& nh : entry.getNextHopRecords()) {
- if (!first)
- os << ",\n ";
- first = false;
- os << nh;
- }
+ std::copy(entry.getNextHopRecords().begin(), entry.getNextHopRecords().end(),
+ make_ostream_joiner(os, ",\n "));
+
os << "]\n";
return os << " )";
diff --git a/src/mgmt/nfd/rib-entry.cpp b/src/mgmt/nfd/rib-entry.cpp
index c7ec47a..315b4bd 100644
--- a/src/mgmt/nfd/rib-entry.cpp
+++ b/src/mgmt/nfd/rib-entry.cpp
@@ -348,13 +348,9 @@
os << "RibEntry(Prefix: " << entry.getName() << ",\n"
<< " Routes: [";
- bool isFirst = true;
- for (const auto& route : entry.getRoutes()) {
- if (!isFirst)
- os << ",\n ";
- isFirst = false;
- os << route;
- }
+ std::copy(entry.getRoutes().begin(), entry.getRoutes().end(),
+ make_ostream_joiner(os, ",\n "));
+
os << "]\n";
return os << " )";
diff --git a/src/util/backports-ostream-joiner.hpp b/src/util/backports-ostream-joiner.hpp
new file mode 100644
index 0000000..384f24a
--- /dev/null
+++ b/src/util/backports-ostream-joiner.hpp
@@ -0,0 +1,129 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+/** \file
+ * \brief Backport of ostream_joiner from the Library Fundamentals v2 TS
+ * \sa http://en.cppreference.com/w/cpp/experimental/ostream_joiner
+ */
+
+#ifndef NDN_UTIL_BACKPORTS_OSTREAM_JOINER_HPP
+#define NDN_UTIL_BACKPORTS_OSTREAM_JOINER_HPP
+
+#include "../common.hpp"
+
+#if __cplusplus >= 201402L
+# ifdef __has_include
+# if __has_include(<experimental/iterator>)
+# include <experimental/iterator>
+# if __cpp_lib_experimental_ostream_joiner >= 201411
+# define NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER
+# endif
+# endif
+# endif
+#endif
+
+#ifdef NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER
+
+namespace ndn {
+using std::experimental::ostream_joiner;
+using std::experimental::make_ostream_joiner;
+} // namespace ndn
+
+#else
+
+#include <iterator>
+
+namespace ndn {
+
+template<typename DelimT,
+ typename CharT = char,
+ typename Traits = std::char_traits<CharT>>
+class ostream_joiner
+{
+public:
+ typedef CharT char_type;
+ typedef Traits traits_type;
+ typedef std::basic_ostream<CharT, Traits> ostream_type;
+ typedef std::output_iterator_tag iterator_category;
+ typedef void value_type;
+ typedef void difference_type;
+ typedef void pointer;
+ typedef void reference;
+
+ ostream_joiner(ostream_type& os, const DelimT& delimiter)
+ noexcept(std::is_nothrow_copy_constructible<DelimT>::value)
+ : m_os(std::addressof(os)), m_delim(delimiter)
+ {
+ }
+
+ ostream_joiner(ostream_type& os, DelimT&& delimiter)
+ noexcept(std::is_nothrow_move_constructible<DelimT>::value)
+ : m_os(std::addressof(os)), m_delim(std::move(delimiter))
+ {
+ }
+
+ template<typename T>
+ ostream_joiner&
+ operator=(const T& value)
+ {
+ if (!m_isFirst) {
+ *m_os << m_delim;
+ }
+ m_isFirst = false;
+ *m_os << value;
+ return *this;
+ }
+
+ ostream_joiner&
+ operator*() noexcept
+ {
+ return *this;
+ }
+
+ ostream_joiner&
+ operator++() noexcept
+ {
+ return *this;
+ }
+
+ ostream_joiner&
+ operator++(int) noexcept
+ {
+ return *this;
+ }
+
+private:
+ ostream_type* m_os;
+ DelimT m_delim;
+ bool m_isFirst = true;
+};
+
+template<typename CharT, typename Traits, typename DelimT>
+inline ostream_joiner<typename std::decay<DelimT>::type, CharT, Traits>
+make_ostream_joiner(std::basic_ostream<CharT, Traits>& os, DelimT&& delimiter)
+{
+ return {os, std::forward<DelimT>(delimiter)};
+}
+
+} // namespace ndn
+
+#endif // NDN_CXX_HAVE_EXPERIMENTAL_OSTREAM_JOINER
+#endif // NDN_UTIL_BACKPORTS_OSTREAM_JOINER_HPP
diff --git a/src/util/backports.hpp b/src/util/backports.hpp
index acb03e6..1d0a92a 100644
--- a/src/util/backports.hpp
+++ b/src/util/backports.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2015-2016 Regents of the University of California.
+ * Copyright (c) 2015-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -28,11 +28,9 @@
#include <boost/lexical_cast.hpp>
#endif
-#include <algorithm>
-
namespace ndn {
-#if __cpp_lib_make_unique
+#if __cpp_lib_make_unique >= 201304
using std::make_unique;
#else
template<typename T, typename ...Args>
@@ -75,5 +73,6 @@
} // namespace ndn
#include "backports-optional.hpp"
+#include "backports-ostream-joiner.hpp"
#endif // NDN_UTIL_BACKPORTS_HPP
diff --git a/tests/unit-tests/util/backports.t.cpp b/tests/unit-tests/util/backports.t.cpp
index 6d8dfd2..21afb0d 100644
--- a/tests/unit-tests/util/backports.t.cpp
+++ b/tests/unit-tests/util/backports.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2013-2016 Regents of the University of California.
+ * Copyright (c) 2013-2017 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -22,6 +22,7 @@
#include "util/backports.hpp"
#include "boost-test.hpp"
+#include <numeric>
namespace ndn {
namespace tests {
@@ -267,6 +268,40 @@
BOOST_AUTO_TEST_SUITE_END() // Optional
+BOOST_AUTO_TEST_CASE(OstreamJoiner)
+{
+ boost::test_tools::output_test_stream os;
+
+ auto joiner1 = ostream_joiner<char>(os, ' ');
+ auto joiner2 = make_ostream_joiner(os, ' ');
+ static_assert(std::is_same<decltype(joiner1), decltype(joiner2)>::value, "");
+
+ std::vector<int> v(5);
+ std::iota(v.begin(), v.end(), 1);
+ std::copy(v.begin(), v.end(), joiner2);
+ BOOST_CHECK(os.is_equal("1 2 3 4 5"));
+
+ auto joiner3 = make_ostream_joiner(os, "...");
+ std::copy(v.begin(), v.end(), joiner3);
+ BOOST_CHECK(os.is_equal("1...2...3...4...5"));
+
+ joiner3 = "one";
+ BOOST_CHECK(os.is_equal("one"));
+ joiner3 = "two";
+ BOOST_CHECK(os.is_equal("...two"));
+ ++joiner3 = "three";
+ BOOST_CHECK(os.is_equal("...three"));
+ joiner3++ = "four";
+ BOOST_CHECK(os.is_equal("...four"));
+
+ std::copy(v.begin(), v.end(), make_ostream_joiner(os, ""));
+ BOOST_CHECK(os.is_equal("12345"));
+
+ std::string delimiter("_");
+ std::copy(v.begin(), v.end(), make_ostream_joiner(os, delimiter));
+ BOOST_CHECK(os.is_equal("1_2_3_4_5"));
+}
+
BOOST_AUTO_TEST_SUITE_END() // TestBackports
BOOST_AUTO_TEST_SUITE_END() // Util