sink.hpp (3774B)
1 #ifndef UUID_8EC8FF70_7F93_4281_9370_FF756B846775 2 #define UUID_8EC8FF70_7F93_4281_9370_FF756B846775 3 #pragma once 4 5 #include "utils.hpp" 6 7 #include <libshit/check.hpp> 8 #include <libshit/meta.hpp> 9 #include <libshit/meta_utils.hpp> 10 #include <libshit/nonowning_string.hpp> 11 #include <libshit/shared_ptr.hpp> 12 #include <libshit/lua/dynamic_object.hpp> 13 14 #include <cstring> 15 #include <boost/endian/arithmetic.hpp> 16 #include <boost/filesystem/path.hpp> 17 18 namespace Neptools 19 { 20 21 LIBSHIT_GEN_EXCEPTION_TYPE(SinkOverflow, std::logic_error); 22 23 class Sink : public Libshit::RefCounted, public Libshit::Lua::DynamicObject 24 { 25 LIBSHIT_DYNAMIC_OBJECT; 26 public: 27 static Libshit::NotNull<Libshit::RefCountedPtr<Sink>> ToFile( 28 boost::filesystem::path fname, FilePosition size, bool try_mmap = true); 29 static Libshit::NotNull<Libshit::RefCountedPtr<Sink>> ToStdOut(); 30 31 FilePosition Tell() const noexcept { return offset + buf_put; } 32 33 template <typename Checker = Libshit::Check::Assert, typename T> 34 LIBSHIT_NOLUA void WriteGen(const T& x) 35 { Write<Checker>({reinterpret_cast<const char*>(&x), Libshit::EmptySizeof<T>}); } 36 37 template <typename Checker = Libshit::Check::Assert> 38 void Write(Libshit::StringView data) 39 { 40 LIBSHIT_CHECK(SinkOverflow, offset+buf_put+data.length() <= size, 41 "Sink overflow during write"); 42 auto cp = std::min(data.length(), size_t(buf_size - buf_put)); 43 memcpy(buf+buf_put, data.data(), cp); 44 data.remove_prefix(cp); 45 buf_put += cp; 46 47 if (!data.empty()) Write_(data); 48 } 49 50 template <typename Checker = Libshit::Check::Assert> 51 void Pad(FileMemSize len) 52 { 53 LIBSHIT_CHECK(SinkOverflow, offset+buf_put+len <= size, 54 "Sink overflow during pad"); 55 auto cp = std::min(len, buf_size - buf_put); 56 memset(buf+buf_put, 0, cp); 57 buf_put += cp; 58 len -= cp; 59 60 if (len) Pad_(len); 61 } 62 63 virtual void Flush() {} 64 65 #define NEPTOOLS_GEN(bits) \ 66 template <typename Checker = Libshit::Check::Assert> \ 67 void WriteLittleUint##bits (boost::endian::little_uint##bits##_t i) \ 68 { WriteGen<Checker>(i); } 69 NEPTOOLS_GEN(8) NEPTOOLS_GEN(16) NEPTOOLS_GEN(32) NEPTOOLS_GEN(64) 70 #undef NEPTOOLS_GEN 71 72 template <typename Checker = Libshit::Check::Assert> 73 void WriteCString(Libshit::NonowningString str) 74 { Write<Checker>({str.c_str(), str.size()+1}); } 75 76 protected: 77 Sink(FilePosition size) : size{size} {} 78 79 Byte* buf = nullptr; 80 FilePosition offset = 0, size; 81 FileMemSize buf_put = 0, buf_size; 82 83 private: 84 virtual void Write_(Libshit::StringView data) = 0; 85 virtual void Pad_(FileMemSize len) = 0; 86 } LIBSHIT_LUAGEN(post_register: %q( 87 // hack to get close call __gc 88 lua_getfield(bld, -2, "__gc"); 89 bld.SetField("close"); 90 )); 91 92 class MemorySink final : public Sink 93 { 94 LIBSHIT_DYNAMIC_OBJECT; 95 public: 96 97 LIBSHIT_NOLUA 98 MemorySink(Byte* buffer, FileMemSize size) : Sink{size} 99 { this->buf = buffer; this->buf_size = size; } 100 101 LIBSHIT_NOLUA 102 MemorySink(std::unique_ptr<Byte[]> buffer, FileMemSize size) 103 : Sink{size}, uniq_buf{std::move(buffer)} 104 { this->buf = uniq_buf.get(); this->buf_size = size; } 105 106 MemorySink(FileMemSize size) : Sink{size}, uniq_buf{new Byte[size]} 107 { buf = uniq_buf.get(); buf_size = size; } 108 109 LIBSHIT_LUAGEN(name: "to_string") 110 Libshit::StringView GetStringView() const noexcept 111 { return {buf, buf_size}; } 112 113 LIBSHIT_NOLUA 114 std::unique_ptr<Byte[]> Release() noexcept { return std::move(uniq_buf); } 115 116 private: 117 std::unique_ptr<Byte[]> uniq_buf; 118 119 void Write_(Libshit::StringView) override; 120 void Pad_(FileMemSize) override; 121 }; 122 123 } 124 #endif