summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Base/Concat.h90
1 files changed, 28 insertions, 62 deletions
diff --git a/Swiften/Base/Concat.h b/Swiften/Base/Concat.h
index df5d77b..8923a8f 100644
--- a/Swiften/Base/Concat.h
+++ b/Swiften/Base/Concat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2015 Isode Limited.
+ * Copyright (c) 2011-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -7,69 +7,35 @@
#pragma once
#include <algorithm>
+#include <type_traits>
namespace Swift {
- template<typename C>
- C concat(const C& c1, const C& c2) {
- C result;
- result.resize(c1.size() + c2.size());
- std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size());
- std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size());
- std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size());
- std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size());
- std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))))));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size());
- std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))))));
- return result;
- }
-
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7, const C& c8) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size() + c8.size());
- std::copy(c8.begin(), c8.end(), std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))))))));
- return result;
- }
+ template<typename V1, typename V2, typename... Rest>
+ std::size_t getReserveAmount(V1 const& v1, V2 const& v2, Rest const&... rest) SWIFTEN_NOEXCEPT
+ {
+ // Total size of the concatenated output is equal to sum of sizes of all the containers that were passed in.
+ // Two first can be accessed directly:
+ std::size_t sizeSum = v1.size() + v2.size();
+ // While the rest needs to be calculated in parameter pack expansion:
+ // http://stackoverflow.com/a/25683817/61574
+ // Pack expansion can occur inside a braced-init-list - dummy array is used for that (with side effect of accumulating the size)
+ int dummy[] = {0, ((sizeSum += rest.size()), void(), 0)...};
+
+ (void)dummy; // dummy is unused - suppress compiler warning
+ return sizeSum;
+}
- template<typename C>
- C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7, const C& c8, const C& c9) {
- C result;
- result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size() + c8.size() + c9.size());
- std::copy(c9.begin(), c9.end(), std::copy(c8.begin(), c8.end(), std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))))))));
- return result;
+ template<typename V1, typename V2, typename... Rest>
+ typename std::decay<V1>::type concat(V1&& v1, V2&& v2, Rest&&... rest) {
+ // Create the output container and reserve the required amount of space
+ typename std::decay<V1>::type v;
+ v.reserve(getReserveAmount(v1, v2, rest...));
+ // Insert the elements from input containers to output. Directly for the first two:
+ v.insert(v.cend(), v1.cbegin(), v1.cend());
+ v.insert(v.cend(), v2.cbegin(), v2.cend());
+ // Use pack expansion for the others:
+ int dummy[] = {0, ((v.insert(v.cend(), rest.cbegin(), rest.cend())), void(), 0 )...};
+ (void)dummy;
+ return v;
}
}