HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
file_view_win32_impl.hpp
1// Copyright Jhalak Patel 2021.
2// Copyright Take Vos 2019, 2021-2022.
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
5
6#pragma once
7
9
10#include "file_file.hpp"
11#include "../utility/utility.hpp"
12#include "../telemetry/telemetry.hpp"
13#include "../macros.hpp"
14#include <format>
15
16hi_export_module(hikogui.file.file_view : impl);
17
18namespace hi { inline namespace v1 {
19namespace detail {
20
22public:
23 file_view_impl(file_view_impl const&) = delete;
25 file_view_impl& operator=(file_view_impl const&) = delete;
26 file_view_impl& operator=(file_view_impl&&) = delete;
27
29 {
30 if (_data != nullptr) {
31 destroy_view(_data);
32 }
33 if (_mapping_handle) {
34 destroy_mapping(_mapping_handle);
35 }
36 }
37
39 _file(std::move(file)), _offset(offset), _size(size)
40 {
41 if (_size == 0) {
42 _size = _file->size() - _offset;
43 }
44
45 if (_offset + _size > _file->size()) {
46 throw io_error("Requested mapping is beyond file size.");
47 }
48
49 if (_file->size() == 0) {
50 // Don't map a zero byte file.
51 _data = nullptr;
52
53 } else {
54 _mapping_handle = make_mapping(file_handle(), access_mode(), _offset + _size);
55 try {
56 _data = make_view(_mapping_handle, access_mode(), _offset, _size);
57 } catch (...) {
58 destroy_mapping(_mapping_handle);
59 throw;
60 }
61 }
62 }
63
64 [[nodiscard]] std::size_t offset() const noexcept
65 {
66 return _offset;
67 }
68
69 [[nodiscard]] std::size_t size() const noexcept
70 {
71 return _size;
72 }
73
74 [[nodiscard]] hi::access_mode access_mode() const noexcept
75 {
76 hi_assert_not_null(_file);
77 return _file->access_mode();
78 }
79
80 [[nodiscard]] void_span void_span() const noexcept
81 {
82 hi_assert_not_null(_file);
83 hi_assert(to_bool(_file->access_mode() & access_mode::write));
84 return {_data, _size};
85 }
86
87 [[nodiscard]] const_void_span const_void_span() const noexcept
88 {
89 return {_data, _size};
90 }
91
92 [[nodiscard]] bool unmapped() const noexcept
93 {
94 if (_file != nullptr) {
95 if (_file->closed()) {
96 _file = nullptr;
97 return true;
98 } else {
99 return false;
100 }
101 } else {
102 return true;
103 }
104 }
105
106 void unmap()
107 {
108 if (_data) {
109 destroy_view(_data);
110 _data = nullptr;
111 _size = 0;
112 destroy_mapping(_mapping_handle);
113 _mapping_handle = nullptr;
114 }
115 _file = nullptr;
116 }
117
118 void flush(hi::void_span span) const noexcept
119 {
120 if (not FlushViewOfFile(span.data(), span.size())) {
121 hi_log_error_once("file::error::flush-view", "Could not flush file. '{}'", get_last_error_message());
122 }
123 }
124
125private:
126 mutable HANDLE _mapping_handle = nullptr;
127 mutable std::shared_ptr<file_impl> _file;
128 std::size_t _offset;
129 std::size_t _size;
130 void *_data = nullptr;
131
132 [[nodiscard]] HANDLE file_handle() noexcept
133 {
134 hi_assert_not_null(_file);
135 return _file->file_handle();
136 }
137
138 static void destroy_mapping(HANDLE mapping)
139 {
140 if (not CloseHandle(mapping)) {
141 throw io_error(std::format("Could not close file mapping object on file '{}'", get_last_error_message()));
142 }
143 }
144
145 [[nodiscard]] static HANDLE make_mapping(HANDLE file, hi::access_mode access_mode, std::size_t size)
146 {
147 hi_assert(size != 0);
148
150 if (to_bool(access_mode & hi::access_mode::read) and to_bool(access_mode & hi::access_mode::write)) {
152 } else if (to_bool(access_mode & hi::access_mode::read)) {
154 } else {
155 throw io_error("Illegal access mode when mapping file.");
156 }
157
158 DWORD size_high = size >> 32;
159 DWORD size_low = size & 0xffffffff;
160
161 if (auto r = CreateFileMappingW(file, NULL, protect, size_high, size_low, nullptr)) {
162 return r;
163 } else {
164 throw io_error(std::format("Could not create file mapping. '{}'", get_last_error_message()));
165 }
166 }
167
168 static void destroy_view(void *data)
169 {
170 if (not UnmapViewOfFile(data)) {
171 throw io_error(std::format("Could not unmap view on file '{}'", get_last_error_message()));
172 }
173 }
174
175 [[nodiscard]] static void *make_view(HANDLE mapping, hi::access_mode access_mode, std::size_t offset, std::size_t size)
176 {
177 hi_assert(size != 0);
178
182 } else if (to_bool(access_mode & access_mode::read)) {
184 } else {
185 throw io_error(std::format("Illegal access mode when viewing file."));
186 }
187
188 DWORD offset_high = offset >> 32;
189 DWORD offset_low = offset & 0xffffffff;
190
192 return r;
193 } else {
194 throw io_error(std::format("Could not map view of file. '{}'", get_last_error_message()));
195 }
196 }
197};
198
199} // namespace detail
200}} // namespace hi::v1
Rules for working with win32 headers.
access_mode
The mode in which way to open a file.
Definition access_mode.hpp:17
@ read
Allow read access to a file.
@ write
Allow write access to a file.
@ flush
Align the text naturally based on the writing direction of each paragraph.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
std::string get_last_error_message()
Get the OS error message from the last error received on this thread.
Definition exception_win32_impl.hpp:31
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A File object.
Definition file_file_intf.hpp:30
Definition file_view_win32_impl.hpp:21
Exception thrown during I/O on an error.
Definition exception_intf.hpp:172
T move(T... args)