1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#ifndef SOURCETOOLS_READ_MEMORY_MAPPED_READER_H
#define SOURCETOOLS_READ_MEMORY_MAPPED_READER_H
#include <vector>
#include <string>
#include <algorithm>
#include <sourcetools/core/macros.h>
#include <sourcetools/r/RHeaders.h>
#include <sourcetools/r/RUtils.h>
#ifndef _WIN32
# include <sourcetools/read/posix/FileConnection.h>
# include <sourcetools/read/posix/MemoryMappedConnection.h>
#else
# include <sourcetools/read/windows/FileConnection.h>
# include <sourcetools/read/windows/MemoryMappedConnection.h>
#endif
namespace sourcetools {
namespace detail {
class MemoryMappedReader
{
public:
class VectorReader
{
public:
explicit VectorReader(std::vector<std::string>* pData)
: pData_(pData)
{
}
template <typename T>
void operator()(const T& lhs, const T& rhs)
{
pData_->push_back(std::string(lhs, rhs));
}
private:
std::vector<std::string>* pData_;
};
static bool read(const char* path, std::string* pContent)
{
// Open file connection
FileConnection conn(path);
if (!conn.open())
return false;
// Get size of file
std::size_t size;
if (!conn.size(&size))
return false;
// Early return for empty files
if (UNLIKELY(size == 0))
return true;
// mmap the file
MemoryMappedConnection map(conn, size);
if (!map.open())
return false;
pContent->assign(map, size);
return true;
}
template <typename F>
static bool read_lines(const char* path, F f)
{
FileConnection conn(path);
if (!conn.open())
return false;
// Get size of file
std::size_t size;
if (!conn.size(&size))
return false;
// Early return for empty files
if (UNLIKELY(size == 0))
return true;
// mmap the file
MemoryMappedConnection map(conn, size);
if (!map.open())
return false;
// special case: just a '\n'
bool endsWithNewline = map[size - 1] == '\n';
if (size == 1 && endsWithNewline)
return true;
// Search for newlines
const char* lower = map;
const char* upper = map;
const char* end = map + size;
while (true)
{
upper = std::find(lower, end, '\n');
if (upper == end)
break;
// Handle '\r\n'
int CR = *(upper - 1) == '\r';
upper -= CR;
// Pass to functor
f(lower, upper);
// Update
lower = upper + 1 + CR;
}
// If this file ended with a newline, we're done
if (endsWithNewline)
return true;
// Otherwise, consume one more string, then we're done
f(lower, end);
return true;
}
static bool read_lines(const char* path, std::vector<std::string>* pContent)
{
VectorReader reader(pContent);
return read_lines(path, reader);
}
};
} // namespace detail
} // namespace sourcetools
#endif /* SOURCETOOLS_READ_MEMORY_MAPPED_READER_H */
|