C++ Utilities 5.31.1
Useful C++ classes and routines such as argument parser, IO and conversion utilities
Loading...
Searching...
No Matches
copy.h
Go to the documentation of this file.
1#ifndef IOUTILITIES_COPY_H
2#define IOUTILITIES_COPY_H
3
5#if defined(CPP_UTILITIES_USE_PLATFORM_SPECIFIC_API_FOR_OPTIMIZING_COPY_HELPER) && defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) \
6 && defined(PLATFORM_LINUX)
7#define CPP_UTILITIES_USE_SEND_FILE
9#endif
10
11#ifdef CPP_UTILITIES_USE_SEND_FILE
12#include <errno.h>
13#include <sys/sendfile.h>
14#endif
15
16#include <cstdint>
17#include <functional>
18#include <iostream>
19#ifdef CPP_UTILITIES_USE_SEND_FILE
20#include <algorithm>
21#include <cstring>
22#endif
23
24namespace CppUtilities {
25
31template <std::size_t bufferSize> class CPP_UTILITIES_EXPORT CopyHelper {
32public:
33 CopyHelper();
34 void copy(std::istream &input, std::ostream &output, std::uint64_t count);
35 void callbackCopy(std::istream &input, std::ostream &output, std::uint64_t count, const std::function<bool(void)> &isAborted,
36 const std::function<void(double)> &callback);
37 void copy(NativeFileStream &input, NativeFileStream &output, std::uint64_t count);
38 void callbackCopy(NativeFileStream &input, NativeFileStream &output, std::uint64_t count, const std::function<bool(void)> &isAborted,
39 const std::function<void(double)> &callback);
40 char *buffer();
41
42private:
43 char m_buffer[bufferSize];
44};
45
49template <std::size_t bufferSize> CopyHelper<bufferSize>::CopyHelper()
50{
51}
52
58template <std::size_t bufferSize> void CopyHelper<bufferSize>::copy(std::istream &input, std::ostream &output, std::uint64_t count)
59{
60 while (count > bufferSize) {
61 input.read(m_buffer, bufferSize);
62 output.write(m_buffer, bufferSize);
63 count -= bufferSize;
64 }
65 input.read(m_buffer, static_cast<std::streamsize>(count));
66 output.write(m_buffer, static_cast<std::streamsize>(count));
67}
68
79template <std::size_t bufferSize>
80void CopyHelper<bufferSize>::callbackCopy(std::istream &input, std::ostream &output, std::uint64_t count, const std::function<bool(void)> &isAborted,
81 const std::function<void(double)> &callback)
82{
83 const auto totalBytes = count;
84 while (count > bufferSize) {
85 input.read(m_buffer, bufferSize);
86 output.write(m_buffer, bufferSize);
87 count -= bufferSize;
88 if (isAborted()) {
89 return;
90 }
91 callback(static_cast<double>(totalBytes - count) / static_cast<double>(totalBytes));
92 }
93 input.read(m_buffer, static_cast<std::streamsize>(count));
94 output.write(m_buffer, static_cast<std::streamsize>(count));
95 callback(1.0);
96}
97
105template <std::size_t bufferSize> void CopyHelper<bufferSize>::copy(NativeFileStream &input, NativeFileStream &output, std::uint64_t count)
106{
107#ifdef CPP_UTILITIES_USE_SEND_FILE
108 if (output.fileDescriptor() != -1 && input.fileDescriptor() != -1 && output.fileDescriptor() != input.fileDescriptor()) {
109 const auto inputTellg = output.tellg();
110 const auto inputTellp = output.tellp();
111 const auto outputTellg = output.tellg();
112 const auto outputTellp = output.tellp();
113 input.flush();
114 output.flush();
115 const auto totalBytes = static_cast<std::streamoff>(count);
116 while (count) {
117 const auto bytesCopied = ::sendfile64(output.fileDescriptor(), input.fileDescriptor(), nullptr, count);
118 if (bytesCopied < 0) {
119 if ((errno == EINVAL || errno == ENOSYS) && static_cast<std::uint64_t>(totalBytes) == count) {
120 // try again the unoptimized version, maybe the filesystem doesn't support sendfile
121 goto unoptimized_version;
122 }
123 throw std::ios_base::failure(argsToString("sendfile64() failed: ", std::strerror(errno)));
124 }
125 count -= static_cast<std::uint64_t>(bytesCopied);
126 }
127 input.sync();
128 output.sync();
129 output.seekg(outputTellg + totalBytes);
130 output.seekp(outputTellp + totalBytes);
131 input.seekg(inputTellg + totalBytes);
132 input.seekp(inputTellp + totalBytes);
133 return;
134 }
135unoptimized_version:
136#endif
137 copy(static_cast<std::istream &>(input), static_cast<std::ostream &>(output), count);
138}
139
151template <std::size_t bufferSize>
153 const std::function<bool(void)> &isAborted, const std::function<void(double)> &callback)
154{
155#ifdef CPP_UTILITIES_USE_SEND_FILE
156 if (output.fileDescriptor() != -1 && input.fileDescriptor() != -1 && output.fileDescriptor() != input.fileDescriptor()) {
157 const auto inputTellg = output.tellg();
158 const auto inputTellp = output.tellp();
159 const auto outputTellg = output.tellg();
160 const auto outputTellp = output.tellp();
161 input.flush();
162 output.flush();
163 const auto totalBytes = static_cast<std::streamoff>(count);
164 while (count) {
165 const auto bytesToCopy = static_cast<std::size_t>(std::min(count, static_cast<std::uint64_t>(bufferSize)));
166 const auto bytesCopied = ::sendfile64(output.fileDescriptor(), input.fileDescriptor(), nullptr, bytesToCopy);
167 if (bytesCopied < 0) {
168 if ((errno == EINVAL || errno == ENOSYS) && static_cast<std::uint64_t>(totalBytes) == count) {
169 // try again the unoptimized version, maybe the filesystem doesn't support sendfile
170 goto unoptimized_version;
171 }
172 throw std::ios_base::failure(argsToString("sendfile64() failed: ", std::strerror(errno)));
173 }
174 count -= static_cast<std::uint64_t>(bytesCopied);
175 if (isAborted()) {
176 return;
177 }
178 callback(static_cast<double>(totalBytes - static_cast<std::streamoff>(count)) / static_cast<double>(totalBytes));
179 }
180 input.sync();
181 output.sync();
182 output.seekg(outputTellg + totalBytes);
183 output.seekp(outputTellp + totalBytes);
184 input.seekg(inputTellg + totalBytes);
185 input.seekp(inputTellp + totalBytes);
186 callback(1.0);
187 return;
188 }
189unoptimized_version:
190#endif
191 callbackCopy(static_cast<std::istream &>(input), static_cast<std::ostream &>(output), count, isAborted, callback);
192}
193
197template <std::size_t bufferSize> char *CopyHelper<bufferSize>::buffer()
198{
199 return m_buffer;
200}
201} // namespace CppUtilities
202
203#endif // IOUTILITIES_COPY_H
char * buffer()
Returns the internal buffer.
Definition copy.h:197
void copy(std::istream &input, std::ostream &output, std::uint64_t count)
Copies count bytes from input to output.
Definition copy.h:58
void callbackCopy(std::istream &input, std::ostream &output, std::uint64_t count, const std::function< bool(void)> &isAborted, const std::function< void(double)> &callback)
Copies count bytes from input to output.
Definition copy.h:80
CopyHelper()
Constructs a new copy helper.
Definition copy.h:49
#define CPP_UTILITIES_EXPORT
Marks the symbol to be exported by the c++utilities library.
Definition global.h:14
Contains all utilities provided by the c++utilities library.
std::fstream NativeFileStream
StringType argsToString(Args &&...args)