Compiler.h: move to util/
[ncmpc-debian.git] / src / io / Path.hxx
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2018 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #ifndef IO_PATH_HXX
21 #define IO_PATH_HXX
22
23 #include "util/Compiler.h"
24
25 #include <string>
26
27 #include <string.h>
28
29 namespace PathDetail {
30
31 #ifdef _WIN32
32 static constexpr char SEPARATOR = '\\';
33 #else
34 static constexpr char SEPARATOR = '/';
35 #endif
36
37 gcc_pure
38 inline size_t
39 GetLength(const char *s) noexcept
40 {
41         return strlen(s);
42 }
43
44 gcc_pure
45 inline size_t
46 GetLength(const std::string &s) noexcept
47 {
48         return s.length();
49 }
50
51 template<typename... Args>
52 inline size_t
53 FillLengths(size_t *lengths, Args&&... args) noexcept;
54
55 template<typename First, typename... Args>
56 inline size_t
57 FillLengths(size_t *lengths, First &&first, Args&&... args) noexcept
58 {
59         size_t length = GetLength(std::forward<First>(first));
60         *lengths++ = length;
61         return length + FillLengths(lengths, std::forward<Args>(args)...);
62 }
63
64 template<>
65 inline size_t
66 FillLengths(size_t *) noexcept
67 {
68         return 0;
69 }
70
71 inline std::string &
72 Append(std::string &dest, const std::string &value, size_t length) noexcept
73 {
74         return dest.append(value, 0, length);
75 }
76
77 inline std::string &
78 Append(std::string &dest, const char *value, size_t length) noexcept
79 {
80         return dest.append(value, length);
81 }
82
83 template<typename... Args>
84 inline std::string &
85 AppendWithSeparators(std::string &dest, const size_t *lengths,
86                      Args&&... args) noexcept;
87
88 template<typename First, typename... Args>
89 inline std::string &
90 AppendWithSeparators(std::string &dest, const size_t *lengths,
91                      First &&first, Args&&... args) noexcept
92 {
93         dest.push_back(SEPARATOR);
94         return AppendWithSeparators(Append(dest, std::forward<First>(first),
95                                            *lengths),
96                                     lengths + 1,
97                                     std::forward<Args>(args)...);
98 }
99
100 template<>
101 inline std::string &
102 AppendWithSeparators(std::string &dest, const size_t *) noexcept
103 {
104         return dest;
105 }
106
107 } // namespace PathDetail
108
109 template<typename First, typename... Args>
110 std::string
111 BuildPath(First &&first, Args&&... args) noexcept
112 {
113         constexpr size_t n = sizeof...(args);
114
115         size_t lengths[n + 1];
116         const size_t total = PathDetail::FillLengths(lengths, first, args...);
117
118         std::string result;
119         result.reserve(total + n);
120         PathDetail::Append(result, std::forward<First>(first), lengths[0]);
121         PathDetail::AppendWithSeparators(result, lengths + 1,
122                                          std::forward<Args>(args)...);
123         return result;
124 }
125
126 #endif