// // libscio.hpp // libscio // // Created by Bob Polis at 2020-02-14 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #ifndef _libscio_H_ #define _libscio_H_ #include #include #include #include #include #include #include namespace sc { namespace io { class fdiobuf : public std::streambuf { public: fdiobuf(int fd) : _fd(fd) {} fdiobuf() : _fd(-1) {} int fd() const { return _fd; } void fd(int fd) { _fd = fd; } protected: int _fd; char _ch {}; // input int_type underflow() override; std::streamsize xsgetn(char* s, std::streamsize n) override; // output int_type overflow(int_type c) override; std::streamsize xsputn(const char* s, std::streamsize num) override; // stream offset positioning pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override; int_type pbackfail(int_type c = EOF) override; }; class fdostream : public std::ostream { public: fdostream() : std::ostream(&_outbuf), _outbuf(-1) {} fdostream(int fd) : std::ostream(&_outbuf), _outbuf(fd) {} // no copying fdostream(const fdostream&) = delete; fdostream& operator=(const fdostream&) = delete; // moving allowed fdostream(fdostream&& other); fdostream& operator=(fdostream&& other); // cleanup: fdostream is RAII class for open file descriptor virtual ~fdostream(); int fd() const { return _outbuf.fd(); } void fd(int fd) { _outbuf.fd(fd); } bool is_open() const { return _outbuf.fd() != -1; } void close(); protected: fdiobuf _outbuf; }; class fdistream : public std::istream { public: fdistream() : std::istream(&_inbuf), _inbuf(-1) {} fdistream(int fd) : std::istream(&_inbuf), _inbuf(fd) {} // no copying fdistream(const fdistream&) = delete; fdistream& operator=(const fdistream&) = delete; // moving allowed fdistream(fdistream&& other); fdistream& operator=(fdistream&& other); // cleanup: fdistream is RAII class for open file descriptor virtual ~fdistream(); int fd() const { return _inbuf.fd(); } void fd(int fd) { _inbuf.fd(fd); } bool is_open() const { return _inbuf.fd() != -1; } void close(); protected: fdiobuf _inbuf; }; class fdstream : public std::iostream { public: fdstream() : std::iostream(&_iobuf) {} fdstream(int fd) : std::iostream(&_iobuf), _iobuf(fd) {} // no copying fdstream(const fdstream&) = delete; fdstream& operator=(const fdstream&) = delete; // moving allowed fdstream(fdstream&& other); fdstream& operator=(fdstream&& other); // cleanup: fdstream is RAII class for open file descriptor virtual ~fdstream(); int fd() const { return _iobuf.fd(); } void fd(int fd) { _iobuf.fd(fd); } bool is_open() const { return _iobuf.fd() != -1; } void close(); protected: fdiobuf _iobuf {-1}; }; struct socket_address { std::string address; int port; }; class socketstream : public std::iostream { public: socketstream(); socketstream(int domain, int type); // copying forbidden socketstream(const socketstream&) = delete; socketstream& operator=(const socketstream&) = delete; // moving allowed socketstream(socketstream&& other); socketstream& operator=(socketstream&& other); // cleanup: socketstream is RAII class for open socket virtual ~socketstream(); bool is_open() { return _iobuf.fd() != -1; } void close(); // server void make_server(const socket_address& sa); socketstream accept() const; // client void connect(const socket_address& host); // convenience: human-readable addresses std::string address() const; // address/endpoint conversion methods void endpoint_from_address(const socket_address& address, struct sockaddr_storage* endpoint) const; socket_address address_from_endpoint(const struct sockaddr* endpoint) const; // getters & setters int socket() const { return _iobuf.fd(); } void socket(int sock) { _iobuf.fd(sock); } int domain() const { return _domain; } void domain(int dom) { _domain = dom; } int type() const { return _type; } void type(int typ) { _type = typ; } protected: fdiobuf _iobuf {-1}; int _domain {0}; int _type {0}; struct sockaddr_storage _sa; }; struct float_80 { unsigned char _val[10]; // big endian float_80(); float_80(double val); operator double() const; }; enum class byte_order { undefined, little_endian, big_endian }; class data_streamer { public: static byte_order cur_byte_order(); static inline void byte_swap(void* val, size_t n) { char* p = reinterpret_cast(val); for (size_t i = 0; i < n / 2; ++i) { std::swap(p[i], p[n - 1 - i]); } } template inline T get(std::istream& file) const { char buf[sizeof(T)]; file.read(buf, sizeof(T)); if (cur_byte_order() != _target_byte_order) { byte_swap(buf, sizeof(T)); } return *reinterpret_cast(buf); } template inline void put(T val, std::ostream& file) const { if (cur_byte_order() != _target_byte_order) { byte_swap(&val, sizeof(T)); } file.write(reinterpret_cast(&val), sizeof(T)); } data_streamer() = default; byte_order target_byte_order() const { return _target_byte_order; } void target_byte_order(byte_order new_byte_order) { _target_byte_order = new_byte_order; } std::string get4chars(std::istream& file) const; uint8_t getui8(std::istream& file) const { return static_cast(file.get()); } int8_t getsi8(std::istream& file) const { return file.get(); } uint16_t getui16(std::istream& file) const { return get(file); } int16_t getsi16(std::istream& file) const { return get(file); } uint32_t getui24(std::istream& file) const; int32_t getsi24(std::istream& file) const; uint32_t getui32(std::istream& file) const { return get(file); } int32_t getsi32(std::istream& file) const { return get(file); } uint64_t getui64(std::istream& file) const { return get(file); } int64_t getsi64(std::istream& file) const { return get(file); } float getf32(std::istream& file) const { return get(file); } double getf64(std::istream& file) const { return get(file); } double getf80(std::istream& file) const; void put4chars(const std::string& s, std::ostream& file) const; void putui8(uint8_t val, std::ostream& file) const { file.put(val); } void putsi8(int8_t val, std::ostream& file) const { file.put(val); } void putui16(uint16_t val, std::ostream& file) const { put(val, file); } void putsi16(int16_t val, std::ostream& file) const { put(val, file); } void putui24(uint32_t val, std::ostream& file) const; void putsi24(int32_t val, std::ostream& file) const; void putui32(uint32_t val, std::ostream& file) const { put(val, file); } void putsi32(int32_t val, std::ostream& file) const { put(val, file); } void putui64(uint64_t val, std::ostream& file) const { put(val, file); } void putsi64(int64_t val, std::ostream& file) const { put(val, file); } void putf32(float val, std::ostream& file) const { put(val, file); } void putf64(double val, std::ostream& file) const { put(val, file); } void putf80(double val, std::ostream& file) const; private: byte_order _target_byte_order {cur_byte_order()}; }; class byte_order_changer { public: byte_order_changer(data_streamer* ds, byte_order order); ~byte_order_changer(); byte_order_changer(byte_order_changer&& other); byte_order_changer& operator=(byte_order_changer&& other); byte_order_changer(const byte_order_changer&) = delete; byte_order_changer& operator=(const byte_order_changer&) = delete; private: data_streamer* _data_streamer {nullptr}; byte_order _saved_byte_order {byte_order::undefined}; }; class mapped_file { public: mapped_file(); mapped_file(const std::string& path); // no copying mapped_file(const mapped_file&) = delete; mapped_file& operator=(const mapped_file&) = delete; // moving allowed mapped_file(mapped_file&& other); mapped_file& operator=(mapped_file&& other); // cleanup: mapped_file is RAII class for memory mapping and file descriptor ~mapped_file(); // it's an error to open an already opened mapped_file // open() is meant to be used after default constructor void open(const std::string& path); // direct (read-only) access to mapped memory char* mapping() const { return _mapping; } size_t size() const { return _length; } private: int _fd {-1}; char* _mapping {nullptr}; size_t _length {0}; }; } } #endif // _libscio_H_