Add File::size and make File's ctor take StringRef.

This commit is contained in:
Victor Zverovich 2014-09-12 10:50:16 -07:00
parent f175591923
commit e34e9fa0c7
3 changed files with 51 additions and 4 deletions

View File

@ -53,6 +53,20 @@
#endif // _WIN32 #endif // _WIN32
#if FMT_GCC_VERSION >= 407
# define FMT_UNUSED __attribute__((unused))
#else
# define FMT_UNUSED
#endif
#if FMT_USE_STATIC_ASSERT
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
#else
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
# define FMT_STATIC_ASSERT(cond, message) \
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
namespace { namespace {
#ifdef _WIN32 #ifdef _WIN32
// Return type of read and write functions. // Return type of read and write functions.
@ -98,13 +112,13 @@ int fmt::BufferedFile::fileno() const {
return fd; return fd;
} }
fmt::File::File(const char *path, int oflag) { fmt::File::File(fmt::StringRef path, int oflag) {
int mode = S_IRUSR | S_IWUSR; int mode = S_IRUSR | S_IWUSR;
#ifdef _WIN32 #ifdef _WIN32
fd_ = -1; fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path, oflag, _SH_DENYNO, mode)); FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
#else #else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path, oflag, mode))); FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif #endif
if (fd_ == -1) if (fd_ == -1)
throw SystemError(errno, "cannot open file {}", path); throw SystemError(errno, "cannot open file {}", path);
@ -128,6 +142,25 @@ void fmt::File::close() {
throw SystemError(errno, "cannot close file"); throw SystemError(errno, "cannot close file");
} }
fmt::LongLong fmt::File::size() const {
#ifdef _WIN32
LARGE_INTEGER size = {};
if (!GetFileSizeEx(_get_osfhandle(fd_), &size))
throw WindowsError(GetLastError(), "cannot get file size");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(size.QuadPart),
"return type of File::size is not large enough");
return size.QuadPart;
#else
typedef struct stat Stat;
Stat file_stat = Stat();
if (fstat(fd_, &file_stat) == -1)
throw SystemError(errno, "cannot get file attributes");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
"return type of File::size is not large enough");
return file_stat.st_size;
#endif
}
std::size_t fmt::File::read(void *buffer, std::size_t count) { std::size_t fmt::File::read(void *buffer, std::size_t count) {
RWResult result = 0; RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));

View File

@ -206,7 +206,7 @@ class File {
File() FMT_NOEXCEPT(true) : fd_(-1) {} File() FMT_NOEXCEPT(true) : fd_(-1) {}
// Opens a file and constructs a File object representing this file. // Opens a file and constructs a File object representing this file.
File(const char *path, int oflag); File(fmt::StringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
@ -277,6 +277,9 @@ class File {
// Closes the file. // Closes the file.
void close(); void close();
// Returns the file size.
fmt::LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer. // Attempts to read count bytes from the file into the specified buffer.
std::size_t read(void *buffer, std::size_t count); std::size_t read(void *buffer, std::size_t count);

View File

@ -194,6 +194,17 @@ TEST(FileTest, CloseNoRetry) {
close_count = 0; close_count = 0;
} }
TEST(FileTest, Size) {
BufferedFile bf("test", "w");
std::string content = "top secret, destroy before reading";
bf.print(content);
bf.close();
File f("test", File::RDONLY);
EXPECT_EQ(content.size(), f.size());
// TODO: test if size can handle large file sizes
// TODO: test FMT_STATIC_ASSERT
}
TEST(FileTest, ReadRetry) { TEST(FileTest, ReadRetry) {
File read_end, write_end; File read_end, write_end;
File::pipe(read_end, write_end); File::pipe(read_end, write_end);