minisat/File.h

140 lines
4.4 KiB
C++

#ifndef File_h
#define File_h
#ifndef Global_h
#include "Global.h"
#endif
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef _LARGEFILE64_SOURCE
#define lseek64 ::lseek
#define open64 ::open
#endif
//=================================================================================================
// A buffered file abstraction with only 'putChar()' and 'getChar()'.
#define File_BufSize 1024 // A small buffer seem to work just as fine as a big one (at least under Linux)
enum FileMode { READ, WRITE };
class Exception_EOF {};
// WARNING! This code is not thoroughly tested. May contain bugs!
class File {
int fd; // Underlying file descriptor.
FileMode mode; // Reading or writing.
uchar* buf; // Read or write buffer.
int size; // Size of buffer (at end of file, less than 'File_BufSize').
int pos; // Current position in buffer
bool own_fd; // Do we own the file descriptor? If so, will close file in destructor.
public:
#define DEFAULTS fd(-1), mode(READ), buf(NULL), size(-1), pos(0), own_fd(true)
File(void) : DEFAULTS {}
File(int fd, FileMode mode, bool own_fd = true) : DEFAULTS {
open(fd, mode, own_fd); }
File(cchar* name, cchar* mode) : DEFAULTS {
open(name, mode); }
#undef DEFAULTS
~File(void) {
close(); }
void open(int fd, FileMode mode, bool own_fd = true); // Low-level open. If 'own_fd' is FALSE, descriptor will not be closed by destructor.
void open(cchar* name, cchar* mode); // FILE* compatible interface.
void close(void);
bool null(void) { // TRUE if no file is opened.
return fd == -1; }
int releaseDescriptor(void) { // Don't run UNIX function 'close()' on descriptor in 'File's 'close()'.
if (mode == READ)
lseek64(fd, pos - size, SEEK_CUR);
own_fd = false;
return fd; }
FileMode getMode(void) {
return mode; }
void setMode(FileMode m) {
if (m == mode) return;
if (m == READ){
flush();
size = read(fd, buf, File_BufSize);
}else{
lseek64(fd, pos - size, SEEK_CUR);
size = -1; }
mode = m;
pos = 0; }
int getCharQ(void) { // Quick version with minimal overhead -- don't call this in the wrong mode!
#ifdef PARANOID
assert(mode == READ);
#endif
if (pos < size) return (uchar)buf[pos++];
if (size < File_BufSize) return EOF;
size = read(fd, buf, File_BufSize);
pos = 0;
if (size == 0) return EOF;
return (uchar)buf[pos++]; }
int putCharQ(int chr) { // Quick version with minimal overhead -- don't call this in the wrong mode!
#ifdef PARANOID
assert(mode == WRITE);
#endif
if (pos == File_BufSize)
write(fd, buf, File_BufSize),
pos = 0;
return buf[pos++] = (uchar)chr; }
int getChar(void) {
if (mode == WRITE) setMode(READ);
return getCharQ(); }
int putChar(int chr) {
if (mode == READ) setMode(WRITE);
return putCharQ(chr); }
bool eof(void) {
assert(mode == READ);
if (pos < size) return false;
if (size < File_BufSize) return true;
size = read(fd, buf, File_BufSize);
pos = 0;
if (size == 0) return true;
return false; }
void flush(void) {
assert(mode == WRITE);
write(fd, buf, pos);
pos = 0; }
void seek(int64 pos, int whence = SEEK_SET);
int64 tell(void);
};
//=================================================================================================
// Some nice helper functions:
void putUInt (File& out, uint64 val);
uint64 getUInt (File& in) throw(Exception_EOF);
static inline uint64 encode64(int64 val) { return (val >= 0) ? (uint64)val << 1 : (((uint64)(~val) << 1) | 1); }
static inline int64 decode64(uint64 val) { return ((val & 1) == 0) ? (int64)(val >> 1) : ~(int64)(val >> 1); }
static inline void putInt (File& out, int64 val) { putUInt(out, encode64(val)); }
static inline uint64 getInt (File& in) { return decode64(getUInt(in)); }
//=================================================================================================
#endif