From 8bfa172675019c2b5b3f2922ac2af86345cd6b87 Mon Sep 17 00:00:00 2001 From: Bob Polis Date: Wed, 14 Dec 2022 16:58:05 +0100 Subject: [PATCH] Split sources, made separate headers Makefile will autogenerate library header, excluding lines containing "@exclude" --- Makefile | 30 ++++-- premake.make | 13 +++ src/byte_order.hpp | 14 +++ src/byte_order_changer.cpp | 37 +++++++ src/byte_order_changer.hpp | 26 +++++ src/data_streamer.cpp | 204 +------------------------------------ src/data_streamer.hpp | 82 +++++++++++++++ src/fdiobuf.hpp | 40 ++++++++ src/fdistream.hpp | 37 +++++++ src/fdostream.hpp | 37 +++++++ src/fdstream.hpp | 37 +++++++ src/float80.cpp | 163 +++++++++++++++++++++++++++++ src/float80.hpp | 16 +++ src/imemfile.hpp | 39 +++++++ src/mapped_file.hpp | 41 ++++++++ src/memstreambuf.hpp | 45 ++++++++ src/socketstream.hpp | 65 ++++++++++++ 17 files changed, 718 insertions(+), 208 deletions(-) create mode 100644 src/byte_order.hpp create mode 100644 src/byte_order_changer.cpp create mode 100644 src/byte_order_changer.hpp create mode 100644 src/data_streamer.hpp create mode 100644 src/fdiobuf.hpp create mode 100644 src/fdistream.hpp create mode 100644 src/fdostream.hpp create mode 100644 src/fdstream.hpp create mode 100644 src/float80.cpp create mode 100644 src/float80.hpp create mode 100644 src/imemfile.hpp create mode 100644 src/mapped_file.hpp create mode 100644 src/memstreambuf.hpp create mode 100644 src/socketstream.hpp diff --git a/Makefile b/Makefile index 4648f61..174c08f 100644 --- a/Makefile +++ b/Makefile @@ -21,21 +21,21 @@ STATICLIB := $(LIBNAME).a BUILDDIR := build/intermediates/ PREFIX ?= /usr/local BINDIR ?= $(PREFIX)/bin +MANDIR ?= $(PREFIX)/man CONFIGDIR ?= $(PREFIX)/etc INCLUDEDIR ?= $(PREFIX)/include LIBDIR ?= $(PREFIX)/lib DATADIR ?= $(PREFIX)/share -MANDIR ?= $(DATADIR)/man DOCDIR ?= $(DATADIR)/$(LIBNAME)/doc SRCS := $(notdir $(wildcard src/*.cpp)) OBJS := $(SRCS:.cpp=.o) DEPS := $(SRCS:.cpp=.d) -HDRS := $(wildcard src/*.hpp) +HDRS ?= $(wildcard src/*.hpp) CXX ?= g++ -CXXFLAGS += -Wshadow -Wall -Wpedantic -Wextra -g -fno-strict-aliasing -std=c++17 -fPIC +CXXFLAGS += -Wshadow -Wall -Wpedantic -Wextra -g -std=c++17 -fPIC ifeq ($(DEBUG),1) CXXFLAGS += -D DEBUG -O0 CONFIG := debug @@ -81,6 +81,19 @@ endif $(OUTDIR)$(STATICLIB): $(OBJS) ar r $(OUTDIR)$(STATICLIB) $(addprefix $(BUILDDIR),$(OBJS)) +ifeq ($(GENERATELIBHEADER),1) +$(LIBNAME).hpp: $(HDRS) + @echo updating build/$(LIBNAME).hpp + @cp /dev/null build/$(LIBNAME).hpp + @for h in $(HDRS); \ + do \ + sed '/@exclude/d' $$h >> build/$(LIBNAME).hpp; \ + done +HEADERSRCDIR := build +else +HEADERSRCDIR := src +endif + test: $(MAKE) -C tests && tests/tests @@ -88,11 +101,16 @@ clean: $(RM) build $(MAKE) -C tests clean -install: $(OUTDIR)$(REALNAME) +ifeq ($(GENERATELIBHEADER),1) +install: $(LIBNAME).hpp +else +install: +endif $(INSTALL) -d $(LIBDIR) $(INSTALL) -m 644 $(OUTDIR)$(REALNAME) $(LIBDIR) - $(INSTALL) -d $(INCLUDEDIR) - $(INSTALL) -m 644 src/$(LIBNAME).hpp $(INCLUDEDIR) + $(INSTALL) -d $(INCLUDEDIR)/$(LIBNAME) + $(INSTALL) -m 644 $(HEADERSRCDIR)/$(LIBNAME).hpp $(INCLUDEDIR)/$(LIBNAME) + $(INSTALL) -m 644 $(HDRS) $(INCLUDEDIR)/$(LIBNAME) ifeq ($(UNAME_S),Darwin) cd $(LIBDIR) && ln -sf $(REALNAME) $(SONAME) endif diff --git a/premake.make b/premake.make index 2116d5c..509ae15 100644 --- a/premake.make +++ b/premake.make @@ -3,3 +3,16 @@ LDLIBS := -lscerror MAJOR := 1 MINOR := 1 PATCH := 0 + +HDRS := byte_order_changer.hpp \ +byte_order.hpp \ +data_streamer.hpp \ +fdiobuf.hpp \ +fdistream.hpp \ +fdostream.hpp \ +fdstream.hpp \ +float80.hpp \ +imemfile.hpp \ +mapped_file.hpp \ +memstreambuf.hpp \ +socketstream.hpp \ diff --git a/src/byte_order.hpp b/src/byte_order.hpp new file mode 100644 index 0000000..1065a69 --- /dev/null +++ b/src/byte_order.hpp @@ -0,0 +1,14 @@ +#ifndef BYTE_ORDER_H_ +#define BYTE_ORDER_H_ + +namespace sc { + namespace io { + enum class byte_order { + undefined, + little_endian, + big_endian + }; + } +} + +#endif // BYTE_ORDER_H_ diff --git a/src/byte_order_changer.cpp b/src/byte_order_changer.cpp new file mode 100644 index 0000000..af5fc91 --- /dev/null +++ b/src/byte_order_changer.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include "byte_order_changer.hpp" +#include "data_streamer.hpp" + +using namespace sc::io; + +byte_order_changer::byte_order_changer(data_streamer* ds, byte_order order) : _data_streamer {ds} { + if (ds == nullptr) { + std::cerr << "byte_order_changer: no data streamer given\n"; + return; + } + _saved_byte_order = _data_streamer->target_byte_order(); + _data_streamer->target_byte_order(order); +} + +byte_order_changer::~byte_order_changer() { + if (_data_streamer) { + _data_streamer->target_byte_order(_saved_byte_order); + } +} + +byte_order_changer::byte_order_changer(byte_order_changer&& other) { + _data_streamer = other._data_streamer; + _saved_byte_order = other._saved_byte_order; + other._data_streamer = nullptr; +} + +byte_order_changer& byte_order_changer::operator=(byte_order_changer&& other) { + if (&other != this) { + _data_streamer = other._data_streamer; + _saved_byte_order = other._saved_byte_order; + other._data_streamer = nullptr; + } + return *this; +} diff --git a/src/byte_order_changer.hpp b/src/byte_order_changer.hpp new file mode 100644 index 0000000..843ee36 --- /dev/null +++ b/src/byte_order_changer.hpp @@ -0,0 +1,26 @@ +#ifndef BYTE_ORDER_CHANGER_H_ +#define BYTE_ORDER_CHANGER_H_ + +#include "data_streamer.hpp" // @exclude + +namespace sc { + namespace io { + 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}; + }; + } +} + +#endif // BYTE_ORDER_CHANGER_H_ diff --git a/src/data_streamer.cpp b/src/data_streamer.cpp index 1c67247..2b2a53b 100644 --- a/src/data_streamer.cpp +++ b/src/data_streamer.cpp @@ -1,20 +1,11 @@ -// -// byte_order_stuff.cpp -// libscio -// -// Created by Bob Polis at 2020-02-14 -// Copyright (c) 2020 SwiftCoder. All rights reserved. -// - -#include "libscio.hpp" #include #include #include +#include "data_streamer.hpp" +#include "float80.hpp" using namespace sc::io; -// data_streamer --------------------------------------------------------------- - data_streamer::data_streamer(byte_order bo) : _target_byte_order(bo) {} byte_order data_streamer::cur_byte_order() { @@ -83,194 +74,3 @@ void data_streamer::putf80(double val, std::ostream& file) const { } file.write(reinterpret_cast(f80._val), sizeof(f80._val)); } - -// byte_order_changer ---------------------------------------------------------- - -byte_order_changer::byte_order_changer(data_streamer* ds, byte_order order) : _data_streamer {ds} { - if (ds == nullptr) { - std::cerr << "byte_order_changer: no data streamer given\n"; - return; - } - _saved_byte_order = _data_streamer->target_byte_order(); - _data_streamer->target_byte_order(order); -} - -byte_order_changer::~byte_order_changer() { - if (_data_streamer) { - _data_streamer->target_byte_order(_saved_byte_order); - } -} - -byte_order_changer::byte_order_changer(byte_order_changer&& other) { - _data_streamer = other._data_streamer; - _saved_byte_order = other._saved_byte_order; - other._data_streamer = nullptr; -} - -byte_order_changer& byte_order_changer::operator=(byte_order_changer&& other) { - if (&other != this) { - _data_streamer = other._data_streamer; - _saved_byte_order = other._saved_byte_order; - other._data_streamer = nullptr; - } - return *this; -} - -// float_80 -------------------------------------------------------------------- - -/*- - * Copyright (c) 2005, 2006 by Marco Trillo - * - * Permission is hereby granted, free of charge, to any - * person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the - * Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice - * shall be included in all copies or substantial portions of - * the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS - * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * Infinite & NAN values for non-IEEE systems - */ -#ifndef HUGE_VAL -#ifdef HUGE -#define INFINITE_VALUE HUGE -#define NAN_VALUE HUGE -#endif -#else -#define INFINITE_VALUE HUGE_VAL -#define NAN_VALUE HUGE_VAL -#endif - - -/* - * IEEE 754 Extended Precision - * - * Implementation here is the 80-bit extended precision - * format of Motorola 68881, Motorola 68882 and Motorola - * 68040 FPUs, as well as Intel 80x87 FPUs. - * - * See: - * http://www.freescale.com/files/32bit/doc/fact_sheet/BR509.pdf - */ -/* - * Exponent range: [-16383,16383] - * Precision for mantissa: 64 bits with no hidden bit - * Bias: 16383 - */ - -float_80::float_80() : float_80(0) {} - -float_80::float_80(double in) { - int sgn, exp, shift; - double fraction, t; - unsigned int lexp, hexp; - unsigned long low, high; - - if (in == 0.0) { - memset(_val, 0, 10); - return; - } - if (in < 0.0) { - in = fabs(in); - sgn = 1; - } else - sgn = 0; - - fraction = frexp(in, &exp); - - if (exp == 0 || exp > 16384) { - if (exp > 16384) /* infinite value */ - low = high = 0; - else { - low = 0x80000000; - high = 0; - } - exp = 32767; - goto done; - } - fraction = ldexp(fraction, 32); - t = floor(fraction); - low = (unsigned long) t; - fraction -= t; - t = floor(ldexp(fraction, 32)); - high = (unsigned long) t; - - /* Convert exponents < -16382 to -16382 (then they will be - * stored as -16383) */ - if (exp < -16382) { - shift = 0 - exp - 16382; - high >>= shift; - high |= (low << (32 - shift)); - low >>= shift; - exp = -16382; - } - exp += 16383 - 1; /* bias */ - -done: - lexp = ((unsigned int) exp) >> 8; - hexp = ((unsigned int) exp) & 0xFF; - - /* big endian */ - _val[0] = ((unsigned char) sgn) << 7; - _val[0] |= (unsigned char) lexp; - _val[1] = (unsigned char) hexp; - _val[2] = (unsigned char) (low >> 24); - _val[3] = (unsigned char) ((low >> 16) & 0xFF); - _val[4] = (unsigned char) ((low >> 8) & 0xFF); - _val[5] = (unsigned char) (low & 0xFF); - _val[6] = (unsigned char) (high >> 24); - _val[7] = (unsigned char) ((high >> 16) & 0xFF); - _val[8] = (unsigned char) ((high >> 8) & 0xFF); - _val[9] = (unsigned char) (high & 0xFF); -} - -float_80::operator double() const { - int sgn, exp; - unsigned long low, high; - double out; - - /* Extract the components from the big endian buffer */ - sgn = (int) (_val[0] >> 7); - exp = ((int) (_val[0] & 0x7F) << 8) | ((int) _val[1]); - low = (((unsigned long) _val[2]) << 24) - | (((unsigned long) _val[3]) << 16) - | (((unsigned long) _val[4]) << 8) | (unsigned long) _val[5]; - high = (((unsigned long) _val[6]) << 24) - | (((unsigned long) _val[7]) << 16) - | (((unsigned long) _val[8]) << 8) | (unsigned long) _val[9]; - - if (exp == 0 && low == 0 && high == 0) - return (sgn ? -0.0 : 0.0); - - switch (exp) { - case 32767: - if (low == 0 && high == 0) - return (sgn ? -INFINITE_VALUE : INFINITE_VALUE); - else - return (sgn ? -NAN_VALUE : NAN_VALUE); - default: - exp -= 16383; /* unbias exponent */ - - } - - out = ldexp((double) low, -31 + exp); - out += ldexp((double) high, -63 + exp); - - return (sgn ? -out : out); -} diff --git a/src/data_streamer.hpp b/src/data_streamer.hpp new file mode 100644 index 0000000..30d12c0 --- /dev/null +++ b/src/data_streamer.hpp @@ -0,0 +1,82 @@ +#ifndef DATA_STREAMER_H_ +#define DATA_STREAMER_H_ + +#include +#include +#include "byte_order.hpp" // @exclude + +namespace sc { + namespace io { + 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; + data_streamer(byte_order bo); + + 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()}; + }; + } +} + +#endif // DATA_STREAMER_H_ diff --git a/src/fdiobuf.hpp b/src/fdiobuf.hpp new file mode 100644 index 0000000..a8802e3 --- /dev/null +++ b/src/fdiobuf.hpp @@ -0,0 +1,40 @@ +#ifndef FDIOBUF_H_ +#define FDIOBUF_H_ + +#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; + }; + } +} + +#endif // FDIOBUF_H_ diff --git a/src/fdistream.hpp b/src/fdistream.hpp new file mode 100644 index 0000000..9374eb5 --- /dev/null +++ b/src/fdistream.hpp @@ -0,0 +1,37 @@ +#ifndef FDISTREAM_H_ +#define FDISTREAM_H_ + +#include +#include "fdiobuf.hpp" // @exclude + +namespace sc { + namespace io { + 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; + }; + } +} + +#endif // FDISTREAM_H_ diff --git a/src/fdostream.hpp b/src/fdostream.hpp new file mode 100644 index 0000000..8d24826 --- /dev/null +++ b/src/fdostream.hpp @@ -0,0 +1,37 @@ +#ifndef FDOSTREAM_H_ +#define FDOSTREAM_H_ + +#include +#include "fdiobuf.hpp" // @exclude + +namespace sc { + namespace io { + 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; + }; + } +} + +#endif // FDOSTREAM_H_ diff --git a/src/fdstream.hpp b/src/fdstream.hpp new file mode 100644 index 0000000..12e8987 --- /dev/null +++ b/src/fdstream.hpp @@ -0,0 +1,37 @@ +#ifndef FDSTREAM_H_ +#define FDSTREAM_H_ + +#include +#include "fdiobuf.hpp" // @exclude + +namespace sc { + namespace io { + 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}; + }; + } +} + +#endif // FDSTREAM_H_ diff --git a/src/float80.cpp b/src/float80.cpp new file mode 100644 index 0000000..eb2e97b --- /dev/null +++ b/src/float80.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include "float80.hpp" + +using namespace sc::io; + +/*- + * Copyright (c) 2005, 2006 by Marco Trillo + * + * Permission is hereby granted, free of charge, to any + * person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice + * shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Infinite & NAN values for non-IEEE systems + */ +#ifndef HUGE_VAL +#ifdef HUGE +#define INFINITE_VALUE HUGE +#define NAN_VALUE HUGE +#endif +#else +#define INFINITE_VALUE HUGE_VAL +#define NAN_VALUE HUGE_VAL +#endif + + +/* + * IEEE 754 Extended Precision + * + * Implementation here is the 80-bit extended precision + * format of Motorola 68881, Motorola 68882 and Motorola + * 68040 FPUs, as well as Intel 80x87 FPUs. + * + * See: + * http://www.freescale.com/files/32bit/doc/fact_sheet/BR509.pdf + */ +/* + * Exponent range: [-16383,16383] + * Precision for mantissa: 64 bits with no hidden bit + * Bias: 16383 + */ + +float_80::float_80() : float_80(0) {} + +float_80::float_80(double in) { + int sgn, exp, shift; + double fraction, t; + unsigned int lexp, hexp; + unsigned long low, high; + + if (in == 0.0) { + memset(_val, 0, 10); + return; + } + if (in < 0.0) { + in = fabs(in); + sgn = 1; + } else + sgn = 0; + + fraction = frexp(in, &exp); + + if (exp == 0 || exp > 16384) { + if (exp > 16384) /* infinite value */ + low = high = 0; + else { + low = 0x80000000; + high = 0; + } + exp = 32767; + goto done; + } + fraction = ldexp(fraction, 32); + t = floor(fraction); + low = (unsigned long) t; + fraction -= t; + t = floor(ldexp(fraction, 32)); + high = (unsigned long) t; + + /* Convert exponents < -16382 to -16382 (then they will be + * stored as -16383) */ + if (exp < -16382) { + shift = 0 - exp - 16382; + high >>= shift; + high |= (low << (32 - shift)); + low >>= shift; + exp = -16382; + } + exp += 16383 - 1; /* bias */ + +done: + lexp = ((unsigned int) exp) >> 8; + hexp = ((unsigned int) exp) & 0xFF; + + /* big endian */ + _val[0] = ((unsigned char) sgn) << 7; + _val[0] |= (unsigned char) lexp; + _val[1] = (unsigned char) hexp; + _val[2] = (unsigned char) (low >> 24); + _val[3] = (unsigned char) ((low >> 16) & 0xFF); + _val[4] = (unsigned char) ((low >> 8) & 0xFF); + _val[5] = (unsigned char) (low & 0xFF); + _val[6] = (unsigned char) (high >> 24); + _val[7] = (unsigned char) ((high >> 16) & 0xFF); + _val[8] = (unsigned char) ((high >> 8) & 0xFF); + _val[9] = (unsigned char) (high & 0xFF); +} + +float_80::operator double() const { + int sgn, exp; + unsigned long low, high; + double out; + + /* Extract the components from the big endian buffer */ + sgn = (int) (_val[0] >> 7); + exp = ((int) (_val[0] & 0x7F) << 8) | ((int) _val[1]); + low = (((unsigned long) _val[2]) << 24) + | (((unsigned long) _val[3]) << 16) + | (((unsigned long) _val[4]) << 8) | (unsigned long) _val[5]; + high = (((unsigned long) _val[6]) << 24) + | (((unsigned long) _val[7]) << 16) + | (((unsigned long) _val[8]) << 8) | (unsigned long) _val[9]; + + if (exp == 0 && low == 0 && high == 0) + return (sgn ? -0.0 : 0.0); + + switch (exp) { + case 32767: + if (low == 0 && high == 0) + return (sgn ? -INFINITE_VALUE : INFINITE_VALUE); + else + return (sgn ? -NAN_VALUE : NAN_VALUE); + default: + exp -= 16383; /* unbias exponent */ + + } + + out = ldexp((double) low, -31 + exp); + out += ldexp((double) high, -63 + exp); + + return (sgn ? -out : out); +} diff --git a/src/float80.hpp b/src/float80.hpp new file mode 100644 index 0000000..52b2f51 --- /dev/null +++ b/src/float80.hpp @@ -0,0 +1,16 @@ +#ifndef FLOAT80_H_ +#define FLOAT80_H_ + +namespace sc { + namespace io { + struct float_80 { + unsigned char _val[10]; // big endian + + float_80(); + float_80(double val); + operator double() const; + }; + } +} + +#endif // FLOAT80_H_ diff --git a/src/imemfile.hpp b/src/imemfile.hpp new file mode 100644 index 0000000..ae279b4 --- /dev/null +++ b/src/imemfile.hpp @@ -0,0 +1,39 @@ +#ifndef IMEMFILE_H_ +#define IMEMFILE_H_ + +#include +#include "mapped_file.hpp" // @exclude +#include "memstreambuf.hpp" // @exclude + +namespace sc { + namespace io { + class imemfile : public std::istream { + public: + imemfile() : std::istream(&_buf) {} + imemfile(const std::string& path); + + // no copying + imemfile(const imemfile&) = delete; + imemfile& operator=(const imemfile&) = delete; + + // move is allowed + imemfile(imemfile&& other); + imemfile& operator=(imemfile&&) = default; + + ~imemfile() = default; + + bool is_open() const { return _file.is_open(); } + void open(const std::string& path, std::ios_base::openmode mode + = std::ios_base::in | std::ios_base::binary); + + char* data() const { return _file.mapping(); } + size_t size() const { return _file.size(); } + + private: + mapped_file _file; + memstreambuf _buf; + }; + } +} + +#endif // IMEMFILE_H_ diff --git a/src/mapped_file.hpp b/src/mapped_file.hpp new file mode 100644 index 0000000..5612526 --- /dev/null +++ b/src/mapped_file.hpp @@ -0,0 +1,41 @@ +#ifndef MAPPED_FILE_H_ +#define MAPPED_FILE_H_ + +#include + +namespace sc { + namespace io { + class mapped_file { + public: + mapped_file() = default; + 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); + bool is_open() const { return _fd != -1; } + + // 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 // MAPPED_FILE_H_ diff --git a/src/memstreambuf.hpp b/src/memstreambuf.hpp new file mode 100644 index 0000000..78a228e --- /dev/null +++ b/src/memstreambuf.hpp @@ -0,0 +1,45 @@ +#ifndef MEMSTREAMBUF_H_ +#define MEMSTREAMBUF_H_ + +#include + +namespace sc { + namespace io { + class memstreambuf : public std::streambuf { + public: + memstreambuf() = default; + void init(char* mem, size_t size); + + memstreambuf(char* mem, size_t size); + + void mem(char* m) { _mem = m; } + char* mem() const { return _mem; } + void size(size_t sz) { _size = sz; } + size_t size() const { return _size; } + + protected: + // input + int_type underflow() override; + int_type uflow() 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; + + private: + char* _mem {nullptr}; + size_t _size {0}; + }; + } +} + +#endif // MEMSTREAMBUF_H_ diff --git a/src/socketstream.hpp b/src/socketstream.hpp new file mode 100644 index 0000000..4b5d395 --- /dev/null +++ b/src/socketstream.hpp @@ -0,0 +1,65 @@ +#ifndef SOCKETSTREAM_H_ +#define SOCKETSTREAM_H_ + +#include +#include +#include "fdiobuf.hpp" // @exclude + +namespace sc { + namespace io { + 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; + }; + } +} + +#endif // SOCKETSTREAM_H_