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