diff options
-rw-r--r-- | Swiften/Base/Concat.h | 90 |
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; } } |