Finish work on deducing this, for now

This commit is contained in:
2025-02-27 23:58:57 +01:00
parent 38ab48b188
commit eb285643ed
14 changed files with 159 additions and 219 deletions

View File

@ -1,48 +1,48 @@
#pragma once #pragma once
#include "asl/base/utility.hpp" #include "asl/base/utility.hpp"
#include "asl/base/functional.hpp" #include "asl/base/functional.hpp"
namespace asl namespace asl
{ {
template<invocable Callback> template<invocable Callback>
class DeferCallback class DeferCallback
{ {
Callback m_callback; Callback m_callback;
bool m_moved = false; bool m_moved = false;
public: public:
template<typename T> template<typename T>
explicit DeferCallback(T&& callback) : m_callback(ASL_FWD(callback)) explicit DeferCallback(T&& callback) : m_callback(ASL_FWD(callback))
{ {
} }
ASL_DELETE_COPY(DeferCallback); ASL_DELETE_COPY(DeferCallback);
DeferCallback(DeferCallback&& other) : DeferCallback(DeferCallback&& other) :
m_callback(ASL_MOVE(other.m_callback)), m_moved(exchange(other.m_moved, true)) m_callback(ASL_MOVE(other.m_callback)), m_moved(exchange(other.m_moved, true))
{ {
} }
DeferCallback& operator=(DeferCallback&&) = delete; DeferCallback& operator=(DeferCallback&&) = delete;
~DeferCallback() ~DeferCallback()
{ {
if (!m_moved) { invoke(m_callback); } if (!m_moved) { invoke(m_callback); }
} }
}; };
struct DeferFactory struct DeferFactory
{ {
template<invocable Callback> template<invocable Callback>
DeferCallback<Callback> operator<<(Callback&& callback) const DeferCallback<Callback> operator<<(Callback&& callback) const
{ {
return DeferCallback<Callback>(ASL_FWD(callback)); return DeferCallback<Callback>(ASL_FWD(callback));
} }
}; };
} // namespace asl } // namespace asl
#define ASL_DEFER auto ASL_CONCAT(_defer_, __COUNTER__) = ::asl::DeferFactory{} << #define ASL_DEFER auto ASL_CONCAT(_defer_, __COUNTER__) = ::asl::DeferFactory{} <<

View File

@ -1,32 +1,32 @@
#include "asl/base/defer.hpp" #include "asl/base/defer.hpp"
#include "asl/testing/testing.hpp" #include "asl/testing/testing.hpp"
ASL_TEST(defer) ASL_TEST(defer)
{ {
uint32_t a = 0; uint32_t a = 0;
{ {
ASL_DEFER [&a]() { a |= 1; }; ASL_DEFER [&a]() { a |= 1; };
ASL_TEST_EXPECT(a == 0); ASL_TEST_EXPECT(a == 0);
{ {
ASL_DEFER [&a]() { a |= 2; }; ASL_DEFER [&a]() { a |= 2; };
ASL_DEFER [&a]() { a |= 4; }; ASL_DEFER [&a]() { a |= 4; };
ASL_TEST_EXPECT(a == 0); ASL_TEST_EXPECT(a == 0);
} }
ASL_TEST_EXPECT(a == 6); ASL_TEST_EXPECT(a == 6);
{ {
ASL_DEFER [&a]() { a |= 8; }; ASL_DEFER [&a]() { a |= 8; };
ASL_TEST_EXPECT(a == 6); ASL_TEST_EXPECT(a == 6);
} }
ASL_TEST_EXPECT(a == 14); ASL_TEST_EXPECT(a == 14);
ASL_DEFER [&a]() { a |= 16; }; ASL_DEFER [&a]() { a |= 16; };
ASL_TEST_EXPECT(a == 14); ASL_TEST_EXPECT(a == 14);
} }
ASL_TEST_EXPECT(a == 31); ASL_TEST_EXPECT(a == 31);
} }

View File

@ -8,8 +8,7 @@ template<typename T> static constexpr int identify(T&&) { return 4; }
struct IdentifySelf struct IdentifySelf
{ {
template<typename Self> constexpr int get(this auto&& self) { return identify(ASL_FWD(self)); }
constexpr int get(this Self&& self) { return identify(ASL_FWD(self)); }
}; };
static int get_const_lref(const IdentifySelf& i) { return ASL_FWD(i).get(); } static int get_const_lref(const IdentifySelf& i) { return ASL_FWD(i).get(); }

View File

@ -381,39 +381,31 @@ public:
return *init; return *init;
} }
// @Todo(C++23) Use deducing this auto data(this auto&& self)
const T* data() const
{ {
using return_type = un_ref_t<copy_cref_t<decltype(self), T>>*;
if constexpr (kInlineCapacity == 0) if constexpr (kInlineCapacity == 0)
{ {
return m_data; return return_type{ self.m_data };
} }
else else
{ {
return is_on_heap() ? m_data : reinterpret_cast<const T*>(this); return self.is_on_heap() ? return_type{ self.m_data } : reinterpret_cast<return_type>(&self);
} }
} }
T* data() constexpr auto begin(this auto&& self)
{ {
if constexpr (kInlineCapacity == 0) using type = un_ref_t<copy_cref_t<decltype(self), T>>;
{ return contiguous_iterator<type>{self.data()};
return m_data;
}
else
{
return is_on_heap() ? m_data : reinterpret_cast<T*>(this);
}
} }
// @Todo(C++23) Use deducing this constexpr auto end(this auto&& self)
constexpr contiguous_iterator<const T> begin() const { return contiguous_iterator{data()}; } {
constexpr contiguous_iterator<const T> end() const { return contiguous_iterator{data() + size()}; } using type = un_ref_t<copy_cref_t<decltype(self), T>>;
return contiguous_iterator<type>{self.data() + self.size()};
}
constexpr contiguous_iterator<T> begin() { return contiguous_iterator{data()}; }
constexpr contiguous_iterator<T> end() { return contiguous_iterator{data() + size()}; }
// @Todo(C++23) Deducing this
constexpr operator span<const T>() const // NOLINT(*-explicit-conversions) constexpr operator span<const T>() const // NOLINT(*-explicit-conversions)
{ {
return as_span(); return as_span();
@ -424,27 +416,16 @@ public:
return as_span(); return as_span();
} }
constexpr span<const T> as_span() const constexpr auto as_span(this auto&& self)
{ {
return span<const T>{data(), size()}; using type = un_ref_t<copy_cref_t<decltype(self), T>>;
return span<type>{self.data(), self.size()};
} }
constexpr span<T> as_span() constexpr auto&& operator[](this auto&& self, isize_t i)
{ {
return span<T>{data(), size()}; ASL_ASSERT(i >= 0 && i <= self.size());
} return ASL_FWD_LIKE(decltype(self), ASL_FWD(self).data()[i]);
// @Todo(C++23) Use deducing this
constexpr T& operator[](isize_t i)
{
ASL_ASSERT(i >= 0 && i <= size());
return data()[i];
}
constexpr const T& operator[](isize_t i) const
{
ASL_ASSERT(i >= 0 && i <= size());
return data()[i];
} }
template<typename H> template<typename H>

View File

@ -147,31 +147,18 @@ public:
// NOLINTEND(*-pointer-arithmetic) // NOLINTEND(*-pointer-arithmetic)
} }
// @Todo(C++23) Deducing this
template<typename U> template<typename U>
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U> auto get(this auto&& self, const U& value)
const V* get(const U& value) const requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
{ {
isize_t index = Base::find_slot_lookup(value); using return_type = un_ref_t<copy_cref_t<decltype(self), V>>*;
isize_t index = self.find_slot_lookup(value);
if (index >= 0) if (index >= 0)
{ {
// NOLINTNEXTLINE(*-pointer-arithmetic) // NOLINTNEXTLINE(*-pointer-arithmetic)
return &Base::m_values[index].as_init_unsafe().value; return return_type{ &self.m_values[index].as_init_unsafe().value };
} }
return nullptr; return return_type{ nullptr };
}
template<typename U>
requires key_hasher<KeyHasher, U> && key_comparator<KeyComparator, K, U>
V* get(const U& value)
{
isize_t index = Base::find_slot_lookup(value);
if (index >= 0)
{
// NOLINTNEXTLINE(*-pointer-arithmetic)
return &Base::m_values[index].as_init_unsafe().value;
}
return nullptr;
} }
}; };

View File

@ -76,14 +76,16 @@ public:
} }
} }
constexpr T* head() const constexpr auto head(this auto&& self)
{ {
return m_head; using return_type = un_ref_t<copy_cref_t<decltype(self), T>>*;
return return_type{ self.m_head };
} }
constexpr T* tail() const constexpr auto tail(this auto&& self)
{ {
return m_head != nullptr ? m_head->m_prev : nullptr; using return_type = un_ref_t<copy_cref_t<decltype(self), T>>*;
return return_type{ self.m_head != nullptr ? self.m_head->m_prev : nullptr };
} }
void detach(T* node) void detach(T* node)
@ -169,25 +171,16 @@ public:
using iterator = generic_iterator<T>; using iterator = generic_iterator<T>;
using const_iterator = generic_iterator<const T>; using const_iterator = generic_iterator<const T>;
// @Todo(C++23) Deduplicate with deducing-this maybe auto begin(this auto&& self)
const_iterator begin() const
{ {
return const_iterator{ head(), is_empty() }; using iterator_type = select_t<is_const<un_ref_t<decltype(self)>>, const_iterator, iterator>;
} return iterator_type{ self.head(), self.is_empty() };
const_iterator end() const
{
return const_iterator{ head(), true };
} }
iterator begin() auto end(this auto&& self)
{ {
return iterator{ head(), is_empty() }; using iterator_type = select_t<is_const<un_ref_t<decltype(self)>>, const_iterator, iterator>;
} return iterator_type{ self.head(), true };
iterator end()
{
return iterator{ head(), true };
} }
}; };

View File

@ -13,7 +13,7 @@ struct IntNode : public asl::intrusive_list_node<IntNode>
ASL_TEST(empty_list) ASL_TEST(empty_list)
{ {
asl::IntrusiveList<IntNode> list; const asl::IntrusiveList<IntNode> list;
ASL_TEST_EXPECT(list.is_empty()); ASL_TEST_EXPECT(list.is_empty());
ASL_TEST_EXPECT(list.head() == nullptr); ASL_TEST_EXPECT(list.head() == nullptr);
ASL_TEST_EXPECT(list.tail() == nullptr); ASL_TEST_EXPECT(list.tail() == nullptr);

View File

@ -14,12 +14,12 @@ ASL_TEST(custom_writer)
{ {
asl::StringWriter string_writer{}; asl::StringWriter string_writer{};
asl::log::DefaultLogger<asl::StringWriter<>&> logger(string_writer); asl::log::DefaultLogger<asl::StringWriter<>&> logger(string_writer);
asl::log::register_logger(&logger); asl::log::register_logger(&logger);
ASL_DEFER [&logger]() { ASL_DEFER [&logger]() {
asl::log::unregister_logger(&logger); asl::log::unregister_logger(&logger);
}; };
ASL_LOG_INFO("Hello"); ASL_LOG_INFO("Hello");
auto sv = string_writer.as_string_view(); auto sv = string_writer.as_string_view();

View File

@ -37,34 +37,21 @@ public:
m_buffer.clear(); m_buffer.clear();
} }
// @Todo(C++23) Deducing this auto push(this auto&& self, string_view sv) -> decltype(self)
requires (!is_const<un_ref_t<decltype(self)>>)
StringBuilder& push(string_view sv) &
{ {
isize_t old_size = m_buffer.size(); isize_t old_size = self.m_buffer.size();
m_buffer.resize_zero(old_size + sv.size()); self.m_buffer.resize_zero(old_size + sv.size());
asl::memcpy(m_buffer.data() + old_size, sv.data(), sv.size()); // NOLINTNEXTLINE(*-pointer-arithmetic)
return *this; asl::memcpy(self.m_buffer.data() + old_size, sv.data(), sv.size());
return ASL_FWD(self);
} }
StringBuilder&& push(string_view sv) && auto push(this auto&& self, char c) -> decltype(self)
requires (!is_const<un_ref_t<decltype(self)>>)
{ {
isize_t old_size = m_buffer.size(); self.m_buffer.push(c);
m_buffer.resize_zero(old_size + sv.size()); return ASL_FWD(self);
asl::memcpy(m_buffer.data() + old_size, sv.data(), sv.size());
return ASL_MOVE(*this);
}
StringBuilder& push(char c) &
{
m_buffer.push(c);
return *this;
}
StringBuilder&& push(char c) &&
{
m_buffer.push(c);
return ASL_MOVE(*this);
} }
string<Allocator> finish() && string<Allocator> finish() &&
@ -73,14 +60,14 @@ public:
} }
template<allocator StringAllocator = Allocator> template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string() string<StringAllocator> as_string() const
requires default_constructible<StringAllocator> requires default_constructible<StringAllocator>
{ {
return string<StringAllocator>{as_string_view()}; return string<StringAllocator>{as_string_view()};
} }
template<allocator StringAllocator = Allocator> template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string(Allocator allocator) string<StringAllocator> as_string(Allocator allocator) const
{ {
return string<StringAllocator>{as_string_view(), ASL_MOVE(allocator)}; return string<StringAllocator>{as_string_view(), ASL_MOVE(allocator)};
} }
@ -121,14 +108,14 @@ public:
} }
template<allocator StringAllocator = Allocator> template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string() string<StringAllocator> as_string() const
requires default_constructible<StringAllocator> requires default_constructible<StringAllocator>
{ {
return m_builder.as_string(); return m_builder.as_string();
} }
template<allocator StringAllocator = Allocator> template<allocator StringAllocator = Allocator>
string<StringAllocator> as_string(Allocator allocator) string<StringAllocator> as_string(Allocator allocator) const
{ {
return m_builder.as_string(ASL_MOVE(allocator)); return m_builder.as_string(ASL_MOVE(allocator));
} }
@ -136,8 +123,8 @@ public:
StringWriter() -> StringWriter<>; StringWriter() -> StringWriter<>;
template<allocator Allocator = DefaultAllocator, formattable... Args> template<allocator Allocator = DefaultAllocator>
string<Allocator> format_to_string(string_view fmt, const Args&... args) string<Allocator> format_to_string(string_view fmt, const formattable auto&... args)
requires default_constructible<Allocator> requires default_constructible<Allocator>
{ {
StringWriter writer{}; StringWriter writer{};
@ -145,8 +132,8 @@ string<Allocator> format_to_string(string_view fmt, const Args&... args)
return ASL_MOVE(writer).finish(); return ASL_MOVE(writer).finish();
} }
template<allocator Allocator = DefaultAllocator, formattable... Args> template<allocator Allocator = DefaultAllocator>
string<Allocator> format_to_string(Allocator allocator, string_view fmt, const Args&... args) string<Allocator> format_to_string(Allocator allocator, string_view fmt, const formattable auto&... args)
{ {
StringWriter writer{ASL_MOVE(allocator)}; StringWriter writer{ASL_MOVE(allocator)};
format(&writer, fmt, args...); format(&writer, fmt, args...);

View File

@ -45,7 +45,7 @@ static void report_assert_failure(const char* msg, const asl::source_location& s
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
{ {
asl::set_assert_failure_handler(report_assert_failure, nullptr); asl::set_assert_failure_handler(report_assert_failure, nullptr);
int fail = 0; int fail = 0;
int pass = 0; int pass = 0;

View File

@ -17,9 +17,8 @@ public:
constexpr maybe_uninit() requires trivially_default_constructible<T> = default; constexpr maybe_uninit() requires trivially_default_constructible<T> = default;
constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT
template<typename... Args> explicit constexpr maybe_uninit(in_place_t, auto&&... args)
explicit constexpr maybe_uninit(in_place_t, Args&&... args) requires constructible_from<T, decltype(args)...>
requires constructible_from<T, Args&&...>
: m_value{ASL_FWD(args)...} : m_value{ASL_FWD(args)...}
{} {}
@ -39,17 +38,15 @@ public:
constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT
// @Safety Value must not have been initialized yet // @Safety Value must not have been initialized yet
template<typename... Args> constexpr void construct_unsafe(auto&&... args)
constexpr void construct_unsafe(Args&&... args) requires constructible_from<T, decltype(args)...>
requires constructible_from<T, Args&&...>
{ {
construct_at<T>(&m_value, ASL_FWD(args)...); construct_at<T>(&m_value, ASL_FWD(args)...);
} }
// @Safety Value must have been initialized // @Safety Value must have been initialized
template<typename U> constexpr void assign_unsafe(auto&& value)
constexpr void assign_unsafe(U&& value) requires assignable_from<T&, decltype(value)>
requires assignable_from<T&, U&&>
{ {
m_value = ASL_FWD(value); m_value = ASL_FWD(value);
} }
@ -64,10 +61,9 @@ public:
} }
// @Safety Value must have been initialized // @Safety Value must have been initialized
template<typename Self> constexpr auto&& as_init_unsafe(this auto&& self)
constexpr auto&& as_init_unsafe(this Self&& self)
{ {
return ASL_FWD_LIKE(decltype(self), ASL_FWD(self).m_value); return ASL_FWD(self).m_value;
} }
}; };

View File

@ -365,8 +365,7 @@ public:
} }
} }
template<typename Self> constexpr auto&& value(this auto&& self)
constexpr auto&& value(this Self&& self)
{ {
ASL_ASSERT_RELEASE(self.has_value()); ASL_ASSERT_RELEASE(self.has_value());
return ASL_FWD(self).m_payload.as_init_unsafe(); return ASL_FWD(self).m_payload.as_init_unsafe();
@ -386,19 +385,18 @@ public:
return has_value() ? ASL_MOVE(value()) : static_cast<T>(ASL_FWD(other_value)); return has_value() ? ASL_MOVE(value()) : static_cast<T>(ASL_FWD(other_value));
} }
template<typename... Args> constexpr T& emplace(auto&&... args) &
constexpr T& emplace(Args&&... args) & requires constructible_from<T, decltype(args)...>
requires constructible_from<T, Args&&...>
{ {
if (has_value()) { reset(); } if (has_value()) { reset(); }
construct(ASL_FWD(args)...); construct(ASL_FWD(args)...);
return value(); return value();
} }
template<typename F, typename Self> template<typename F>
constexpr auto and_then(this Self&& self, F&& f) constexpr auto and_then(this auto&& self, F&& f)
{ {
using Result = invoke_result_t<F, copy_cref_t<Self&&, T>>; using Result = invoke_result_t<F, copy_cref_t<decltype(self), T>>;
static_assert(is_option<Result>); static_assert(is_option<Result>);
if (self.has_value()) if (self.has_value())
@ -408,10 +406,10 @@ public:
return Result{ asl::nullopt }; return Result{ asl::nullopt };
} }
template<typename F, typename Self> template<typename F>
constexpr auto transform(this Self&& self, F&& f) constexpr auto transform(this auto&& self, F&& f)
{ {
using Result = invoke_result_t<F, copy_cref_t<Self&&, T>>; using Result = invoke_result_t<F, copy_cref_t<decltype(self), T>>;
if (self.has_value()) if (self.has_value())
{ {
return option<un_cvref_t<Result>>{ return option<un_cvref_t<Result>>{

View File

@ -129,8 +129,7 @@ public:
constexpr status&& throw_status() && { return ASL_MOVE(m_status); } constexpr status&& throw_status() && { return ASL_MOVE(m_status); }
template<typename Self> constexpr auto&& value(this auto&& self)
constexpr auto&& value(this Self&& self)
{ {
ASL_ASSERT_RELEASE(self.ok()); ASL_ASSERT_RELEASE(self.ok());
return ASL_FWD(self).m_value.as_init_unsafe(); return ASL_FWD(self).m_value.as_init_unsafe();

View File

@ -1 +1 @@
license