Skip to content

Commit 7e1d15a

Browse files
committed
Sync bela
1 parent fea8c41 commit 7e1d15a

File tree

3 files changed

+243
-1
lines changed

3 files changed

+243
-1
lines changed

vendor/bela.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
https://github.com/fcharlie/bela/tree/b07adc5868de825dca0f2ddcb9ebb9726942f94a
1+
https://github.com/fcharlie/bela/tree/b90164e04799c805a675c41de9ec081c67b1f5ba

vendor/bela/include/bela/comutils.hpp

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,245 @@ class comstr {
133133
BSTR str;
134134
};
135135

136+
class last_error_context {
137+
bool m_dismissed = false;
138+
DWORD m_error = 0;
139+
140+
public:
141+
last_error_context() noexcept : last_error_context(::GetLastError()) {}
142+
143+
explicit last_error_context(DWORD error) noexcept : m_error(error) {}
144+
145+
last_error_context(last_error_context &&other) noexcept { operator=(std::move(other)); }
146+
147+
last_error_context &operator=(last_error_context &&other) noexcept {
148+
m_dismissed = std::exchange(other.m_dismissed, true);
149+
m_error = other.m_error;
150+
151+
return *this;
152+
}
153+
154+
~last_error_context() noexcept {
155+
if (!m_dismissed) {
156+
::SetLastError(m_error);
157+
}
158+
}
159+
160+
//! last_error_context doesn't own a concrete resource, so therefore
161+
//! it just disarms its destructor and returns void.
162+
void release() noexcept {
163+
BELA_ASSERT(!m_dismissed);
164+
m_dismissed = true;
165+
}
166+
167+
[[nodiscard]] auto value() const noexcept { return m_error; }
168+
};
169+
170+
namespace details {
171+
typedef std::integral_constant<size_t, 0> pointer_access_all; // get(), release(), addressof(), and '&' are available
172+
typedef std::integral_constant<size_t, 1> pointer_access_noaddress; // get() and release() are available
173+
typedef std::integral_constant<size_t, 2> pointer_access_none; // the raw pointer is not available
174+
175+
template <bool is_fn_ptr, typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
176+
struct close_invoke_helper {
177+
BELA_FORCE_INLINE static void close(pointer_storage_t value) noexcept { std::invoke(close_fn, value); }
178+
inline static void close_reset(pointer_storage_t value) noexcept {
179+
auto preserveError = last_error_context();
180+
std::invoke(close_fn, value);
181+
}
182+
};
183+
184+
template <typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
185+
struct close_invoke_helper<true, close_fn_t, close_fn, pointer_storage_t> {
186+
BELA_FORCE_INLINE static void close(pointer_storage_t value) noexcept { close_fn(value); }
187+
inline static void close_reset(pointer_storage_t value) noexcept {
188+
auto preserveError = last_error_context();
189+
close_fn(value);
190+
}
191+
};
192+
193+
template <typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
194+
using close_invoker =
195+
close_invoke_helper<std::is_pointer_v<close_fn_t> ? std::is_function_v<std::remove_pointer_t<close_fn_t>> : false,
196+
close_fn_t, close_fn, pointer_storage_t>;
197+
198+
template <typename pointer_t, // The handle type
199+
typename close_fn_t, // The handle close function type
200+
close_fn_t close_fn, // * and function pointer
201+
typename pointer_access_t = pointer_access_all, // all, noaddress or none to control pointer method access
202+
typename pointer_storage_t =
203+
pointer_t, // The type used to store the handle (usually the same as the handle itself)
204+
typename invalid_t = pointer_t, // The invalid handle value type
205+
invalid_t invalid = invalid_t{}, // * and its value (default ZERO value)
206+
typename pointer_invalid_t =
207+
std::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
208+
struct resource_policy : close_invoker<close_fn_t, close_fn, pointer_storage_t> {
209+
typedef pointer_storage_t pointer_storage;
210+
typedef pointer_t pointer;
211+
typedef pointer_invalid_t pointer_invalid;
212+
typedef pointer_access_t pointer_access;
213+
BELA_FORCE_INLINE static pointer_storage invalid_value() { return (pointer)invalid; }
214+
BELA_FORCE_INLINE static bool is_valid(pointer_storage value) noexcept {
215+
return (static_cast<pointer>(value) != (pointer)invalid);
216+
}
217+
};
218+
219+
// This class provides the pointer storage behind the implementation of unique_any_t utilizing the given
220+
// resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug
221+
// into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event
222+
// to be a unique_any formed class, but also expose methods like SetEvent directly.
223+
224+
template <typename Policy> class unique_storage {
225+
protected:
226+
typedef Policy policy;
227+
typedef typename policy::pointer_storage pointer_storage;
228+
typedef typename policy::pointer pointer;
229+
typedef unique_storage<policy> base_storage;
230+
231+
public:
232+
unique_storage() noexcept : m_ptr(policy::invalid_value()) {}
233+
234+
explicit unique_storage(pointer_storage ptr) noexcept : m_ptr(ptr) {}
235+
236+
unique_storage(unique_storage &&other) noexcept : m_ptr(std::move(other.m_ptr)) {
237+
other.m_ptr = policy::invalid_value();
238+
}
239+
240+
~unique_storage() noexcept {
241+
if (policy::is_valid(m_ptr)) {
242+
policy::close(m_ptr);
243+
}
244+
}
245+
246+
[[nodiscard]] bool is_valid() const noexcept { return policy::is_valid(m_ptr); }
247+
248+
void reset(pointer_storage ptr = policy::invalid_value()) noexcept {
249+
if (policy::is_valid(m_ptr)) {
250+
policy::close_reset(m_ptr);
251+
}
252+
m_ptr = ptr;
253+
}
254+
255+
void reset(std::nullptr_t) noexcept {
256+
static_assert(std::is_same<typename policy::pointer_invalid, std::nullptr_t>::value,
257+
"reset(nullptr): valid only for handle types using nullptr as the invalid value");
258+
reset();
259+
}
260+
261+
[[nodiscard]] pointer get() const noexcept { return static_cast<pointer>(m_ptr); }
262+
263+
pointer_storage release() noexcept {
264+
static_assert(!std::is_same<typename policy::pointer_access, pointer_access_none>::value,
265+
"release(): the raw handle value is not available for this resource class");
266+
auto ptr = m_ptr;
267+
m_ptr = policy::invalid_value();
268+
return ptr;
269+
}
270+
271+
pointer_storage *addressof() noexcept {
272+
static_assert(std::is_same<typename policy::pointer_access, pointer_access_all>::value,
273+
"addressof(): the address of the raw handle is not available for this resource class");
274+
return &m_ptr;
275+
}
276+
277+
protected:
278+
void replace(unique_storage &&other) noexcept {
279+
reset(other.m_ptr);
280+
other.m_ptr = policy::invalid_value();
281+
}
282+
283+
private:
284+
pointer_storage m_ptr;
285+
};
286+
} // namespace details
287+
288+
template <typename struct_t, typename close_fn_t, close_fn_t close_fn, typename init_fn_t = std::nullptr_t,
289+
init_fn_t init_fn = std::nullptr_t()>
290+
class unique_struct : public struct_t {
291+
using closer = details::close_invoker<close_fn_t, close_fn, struct_t *>;
292+
293+
public:
294+
//! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is
295+
//! specified
296+
unique_struct() { call_init(use_default_init_fn()); }
297+
298+
//! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t
299+
explicit unique_struct(const struct_t &other) noexcept : struct_t(other) {}
300+
301+
//! Initializes the managed struct by taking the ownership of the other managed struct
302+
//! Then resets the other managed struct by calling the custom close function
303+
unique_struct(unique_struct &&other) noexcept : struct_t(other.release()) {}
304+
305+
//! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct
306+
//! Then resets the other managed struct by calling the custom close function
307+
unique_struct &operator=(unique_struct &&other) noexcept {
308+
if (this != std::addressof(other)) {
309+
reset(other.release());
310+
}
311+
return *this;
312+
}
313+
314+
//! Calls the custom close function
315+
~unique_struct() noexcept { closer::close(this); }
316+
317+
void reset(const unique_struct &) = delete;
318+
319+
//! Resets this managed struct by calling the custom close function and begins management of the other struct
320+
void reset(const struct_t &other) noexcept {
321+
closer::close_reset(this);
322+
struct_t::operator=(other);
323+
}
324+
325+
//! Resets this managed struct by calling the custom close function
326+
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function
327+
//! is specified
328+
void reset() noexcept {
329+
closer::close(this);
330+
call_init(use_default_init_fn());
331+
}
332+
333+
void swap(struct_t &) = delete;
334+
335+
//! Swaps the managed structs
336+
void swap(unique_struct &other) noexcept {
337+
struct_t self(*this);
338+
struct_t::operator=(other);
339+
*(other.addressof()) = self;
340+
}
341+
342+
//! Returns the managed struct
343+
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function
344+
//! is specified
345+
struct_t release() noexcept {
346+
struct_t value(*this);
347+
call_init(use_default_init_fn());
348+
return value;
349+
}
350+
351+
//! Returns address of the managed struct
352+
struct_t *addressof() noexcept { return this; }
353+
354+
//! Resets this managed struct by calling the custom close function
355+
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function
356+
//! is specified Returns address of the managed struct
357+
struct_t *reset_and_addressof() noexcept {
358+
reset();
359+
return this;
360+
}
361+
362+
unique_struct(const unique_struct &) = delete;
363+
unique_struct &operator=(const unique_struct &) = delete;
364+
unique_struct &operator=(const struct_t &) = delete;
365+
366+
private:
367+
typedef typename std::is_same<init_fn_t, std::nullptr_t>::type use_default_init_fn;
368+
369+
void call_init(std::true_type) { RtlZeroMemory(this, sizeof(*this)); }
370+
371+
void call_init(std::false_type) { init_fn(this); }
372+
};
373+
using unique_variant =
374+
unique_struct<VARIANT, decltype(&::VariantClear), ::VariantClear, decltype(&::VariantInit), ::VariantInit>;
136375
} // namespace bela
137376

138377
#endif

vendor/bela/test/win/pick.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <bela/picker.hpp>
22
#include <bela/terminal.hpp>
3+
#include <bela/comutils.hpp>
34

45
class dotcom_global_initializer {
56
public:
@@ -16,12 +17,14 @@ class dotcom_global_initializer {
1617
int wmain() {
1718
dotcom_global_initializer dot;
1819
bela::FPrintF(stderr, L"dotcom initialized.\n");
20+
bela::unique_variant v1;
1921
auto f = bela::FolderPicker(nullptr, nullptr);
2022
if (!f) {
2123
auto ec = bela::make_system_error_code();
2224
bela::FPrintF(stderr, L"Picker Folder error: %s\n", ec);
2325
return 1;
2426
}
2527
bela::FPrintF(stderr, L"Folder is: %s\n", *f);
28+
2629
return 0;
2730
}

0 commit comments

Comments
 (0)