Compare commits
5 commits
b872cc940b
...
d6608aa6b4
Author | SHA1 | Date | |
---|---|---|---|
|
d6608aa6b4 | ||
|
8b0ef87f17 | ||
|
bda4a77c86 | ||
|
8d56bc31ab | ||
|
734628e604 |
|
@ -10,8 +10,16 @@ namespace util {
|
|||
template <typename... Ts>
|
||||
inline constexpr auto format(std::string_view fmt, Ts&&... args)
|
||||
-> std::string {
|
||||
#if defined(__cpp_if_consteval) && defined(doesnt_work_yet_in_clang_14)
|
||||
if
|
||||
consteval { return std::format(fmt, args...); }
|
||||
else {
|
||||
return std::vformat(fmt, std::make_format_args(std::forward<Ts>(args)...));
|
||||
}
|
||||
#else
|
||||
return std::vformat(fmt, std::make_format_args(std::forward<Ts>(args)...));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename Context>
|
||||
using has_formatter =
|
||||
|
|
|
@ -180,151 +180,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *> struct BaseIterator {
|
||||
using value_type = V;
|
||||
using reference = V &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
I base_iter;
|
||||
|
||||
BaseIterator(const I &iter) : base_iter(iter) {}
|
||||
BaseIterator(I &&iter) : base_iter(std::move(iter)) {}
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct InputOrOutputIterator : public BaseIterator<V, I> {
|
||||
InputOrOutputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
InputOrOutputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator*() const -> void {}
|
||||
|
||||
auto constexpr operator++(int) -> InputOrOutputIterator {
|
||||
const auto ret = *this;
|
||||
this->base_iter++;
|
||||
return ret;
|
||||
}
|
||||
auto constexpr operator++() -> InputOrOutputIterator & {
|
||||
this ++;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct InputIterator : public InputOrOutputIterator<V, I>,
|
||||
public std::input_iterator_tag {
|
||||
InputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
InputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator*() const -> const V & { return *this->base_iter; }
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct OutputIterator : public InputOrOutputIterator<V, I>,
|
||||
public std::output_iterator_tag {
|
||||
OutputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
OutputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator*() -> V & { return *this->base_iter; }
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct ForwardIterator : public InputIterator<V, I>,
|
||||
public std::forward_iterator_tag {
|
||||
ForwardIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
ForwardIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator==(const ForwardIterator &rhs) const -> bool {
|
||||
return this->base_iter == rhs.base_iter;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct BidirectionalIterator : public ForwardIterator<V, I>,
|
||||
public std::bidirectional_iterator_tag {
|
||||
BidirectionalIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
BidirectionalIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator--(int) -> BidirectionalIterator {
|
||||
const auto ret = *this;
|
||||
this->base_iter--;
|
||||
return ret;
|
||||
}
|
||||
auto constexpr operator--() -> BidirectionalIterator & {
|
||||
this --;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename V, typename I = V *>
|
||||
struct RandomAccessIterator : public BidirectionalIterator<V, I>,
|
||||
public std::random_access_iterator_tag {
|
||||
using difference_type = typename BaseIterator<V, I>::difference_type;
|
||||
|
||||
RandomAccessIterator(const I &iter) : BaseIterator<V, I>(iter) {}
|
||||
RandomAccessIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
|
||||
|
||||
auto constexpr operator<=>(const RandomAccessIterator &rhs) const
|
||||
-> std::strong_ordering {
|
||||
return this->base_iter <=> rhs.base_iter;
|
||||
}
|
||||
|
||||
auto constexpr operator-(const RandomAccessIterator &rhs) const
|
||||
-> difference_type {
|
||||
return this->base_iter - rhs.base_iter;
|
||||
}
|
||||
auto constexpr operator+(const difference_type &n) const
|
||||
-> RandomAccessIterator {
|
||||
return RandomAccessIterator(this->base_iter + n);
|
||||
}
|
||||
friend auto constexpr operator+(const difference_type &n,
|
||||
const RandomAccessIterator &rhs)
|
||||
-> RandomAccessIterator {
|
||||
return rhs + n;
|
||||
}
|
||||
auto constexpr operator-(const difference_type &n) const
|
||||
-> RandomAccessIterator {
|
||||
return RandomAccessIterator(this->base_iter - n);
|
||||
}
|
||||
|
||||
auto operator+=(const difference_type &n) -> RandomAccessIterator & {
|
||||
*this = RandomAccessIterator(this->base_iter + n);
|
||||
return *this;
|
||||
}
|
||||
auto operator-=(const difference_type &n) -> RandomAccessIterator & {
|
||||
*this = RandomAccessIterator(this->base_iter - n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto constexpr operator[](const difference_type &n) const -> const V & {
|
||||
return this->base_iter[n];
|
||||
}
|
||||
auto operator[](const difference_type &n) -> V & {
|
||||
return this->base_iter[n];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename I>
|
||||
using Iterator = std::conditional_t<
|
||||
std::random_access_iterator<I>,
|
||||
RandomAccessIterator<std::iter_value_t<I>, I>,
|
||||
std::conditional_t<
|
||||
std::bidirectional_iterator<I>,
|
||||
BidirectionalIterator<std::iter_value_t<I>, I>,
|
||||
std::conditional_t<
|
||||
std::forward_iterator<I>, ForwardIterator<std::iter_value_t<I>, I>,
|
||||
std::conditional_t<
|
||||
std::output_iterator<I, decltype(*std::declval<I>())>,
|
||||
OutputIterator<std::iter_value_t<I>, I>,
|
||||
std::conditional_t<
|
||||
std::input_iterator<I>,
|
||||
InputIterator<std::iter_value_t<I>, I>,
|
||||
std::conditional_t<
|
||||
std::input_or_output_iterator<I>,
|
||||
InputOrOutputIterator<std::iter_value_t<I>, I>,
|
||||
RandomAccessIterator<I, I *>>>>>>>;
|
||||
|
||||
template <std::ranges::range R>
|
||||
using RangeIterator = Iterator<std::ranges::iterator_t<R>>;
|
||||
template <typename T, typename I>
|
||||
concept iterator = std::same_as<typename iterator_t<I>::value_type, T>;
|
||||
|
||||
} // namespace util
|
||||
|
||||
|
|
|
@ -17,11 +17,30 @@ template <std::invocable F> struct generated_iterator {
|
|||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
value_type value{};
|
||||
F generator{};
|
||||
F generator;
|
||||
|
||||
// TODO: make 1 constructor that generates a value, move/copy value in all
|
||||
// other constructors
|
||||
generated_iterator() = default;
|
||||
generated_iterator(F gen) : generator(gen), value(gen()) {}
|
||||
generated_iterator(F &&gen) : generator(std::move(gen)), value(gen()) {}
|
||||
explicit generated_iterator(F &&gen)
|
||||
: generator(std::move(gen)), value(gen()) {}
|
||||
|
||||
generated_iterator(const generated_iterator &other)
|
||||
: generator(other.generator), value(other.value) {}
|
||||
generated_iterator(generated_iterator &&other)
|
||||
: generator(std::move(other.generator)), value(std::move(other.value)) {}
|
||||
|
||||
auto operator=(const generated_iterator &other) -> generated_iterator & {
|
||||
generator = other.generator;
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator=(generated_iterator &&other) -> generated_iterator & {
|
||||
generator = std::move(other.generator);
|
||||
value = std::move(other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto generate_new_value() -> void { value = generator(); }
|
||||
|
||||
|
@ -47,13 +66,14 @@ template <std::invocable F> struct generated_iterator {
|
|||
|
||||
template <std::invocable F>
|
||||
class generated_view : rg::view_interface<generated_view<F>> {
|
||||
F generator = {};
|
||||
detail::generated_iterator<F> iter_{};
|
||||
|
||||
public:
|
||||
constexpr generated_view() = default;
|
||||
constexpr generated_view(F generator) : generator(std::move(generator)) {}
|
||||
constexpr generated_view(F generator)
|
||||
: iter_(detail::generated_iterator(std::move(generator))) {}
|
||||
|
||||
constexpr auto begin() const { return detail::generated_iterator(generator); }
|
||||
constexpr auto begin() const { return iter_; }
|
||||
constexpr auto end() const { return std::unreachable_sentinel; }
|
||||
};
|
||||
|
||||
|
|
65
include/transmute.hpp
Normal file
65
include/transmute.hpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace util {
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_const : std::type_identity<T2> {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_const<const T1, T2> : std::type_identity<const T2> {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using copy_const_t = typename copy_const<T1, T2>::type;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_volatile : std::type_identity<T2> {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_volatile<volatile T1, T2> : std::type_identity<volatile T2> {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using copy_volatile_t = typename copy_volatile<T1, T2>::type;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_cv : std::type_identity<copy_const_t<T1, copy_volatile_t<T1, T2>>> {
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using copy_cv_t = typename copy_cv<T1, T2>::type;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct copy_reference : std::type_identity<T2> {};
|
||||
template <typename T1, typename T2>
|
||||
struct copy_reference<T1 &, T2>
|
||||
: std::type_identity<std::add_lvalue_reference_t<T2>> {};
|
||||
template <typename T1, typename T2>
|
||||
struct copy_reference<T1 &&, T2>
|
||||
: std::type_identity<std::add_rvalue_reference_t<T2>> {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using copy_reference_t = typename copy_reference<T1, T2>::type;
|
||||
|
||||
template <typename T1, typename T2>
|
||||
using copy_cvref_t = copy_reference_t<
|
||||
T1, copy_reference_t<T2, copy_cv_t<std::remove_reference_t<T1>, T2>>>;
|
||||
|
||||
template <typename T2>
|
||||
constexpr inline auto transmute(auto &&t1) -> copy_cvref_t<decltype(t1), T2> {
|
||||
return std::forward<copy_cvref_t<decltype(t1), T2>>(
|
||||
reinterpret_cast<copy_cvref_t<decltype(t1), T2>>(t1));
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
constexpr inline auto transmute(auto &t1) -> copy_cvref_t<decltype(t1), T2> {
|
||||
return std::forward<copy_cvref_t<decltype(t1), T2>>(
|
||||
reinterpret_cast<copy_cvref_t<decltype(t1), T2>>(t1));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
constexpr inline auto transmute(T1 t1) -> T2 {
|
||||
return std::forward<T2>(reinterpret_cast<T2>(t1));
|
||||
}
|
||||
|
||||
} // namespace util
|
111
src/main.cc
111
src/main.cc
|
@ -4,7 +4,6 @@
|
|||
#include "ranges/enumerate.hpp"
|
||||
#include "ranges/first.hpp"
|
||||
#include "ranges/generated.hpp"
|
||||
#include "tagged_union.hpp"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
@ -19,35 +18,78 @@
|
|||
#include <vector>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace util::bitflag_operators;
|
||||
|
||||
enum class E {
|
||||
A = 0x1,
|
||||
B = 0x10,
|
||||
C = 0x100,
|
||||
D = 0x1000,
|
||||
};
|
||||
#include "iterator.hpp"
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
printf("Hello, Alloy!\n");
|
||||
auto test_iterator_t() {
|
||||
int *ptr = nullptr;
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
using int_ptr_iterator_t = util::iterator_t<int *>;
|
||||
auto a = int_ptr_iterator_t(arr);
|
||||
|
||||
const auto a = E::A;
|
||||
const auto ab = E::A | E::B;
|
||||
const auto all = E::A | E::B | E::C | E::D;
|
||||
const auto three = a[3];
|
||||
a += 2;
|
||||
*a = 6;
|
||||
|
||||
auto vec = std::vector<int>({1, 2, 3, 4, 5});
|
||||
for (auto &&e : arr) {
|
||||
util::println("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
auto range = vec | std::views::filter([](auto &i) { return i % 2; });
|
||||
auto infinite_range = util::views::from([] {return 1;}) | std::views::take(5);
|
||||
auto test_enumerate_view() {
|
||||
auto enumerated = util::views::from([] { return 1; }) |
|
||||
util::views::enumerate | std::views::take(10);
|
||||
|
||||
auto map =
|
||||
vec | util::views::enumerate | util::views::collect<std::map<int, int>>;
|
||||
auto b = std::ranges::begin(enumerated);
|
||||
|
||||
for (auto &&[i, e] : map) {
|
||||
for (auto &&[i, e] : enumerated) {
|
||||
util::println("[{}] {}", i, e);
|
||||
}
|
||||
|
||||
auto random = util::views::from([] {
|
||||
for (auto &&[i, e] : enumerated | util::views::enumerate) {
|
||||
util::println("[{}] {}", i, e.value);
|
||||
}
|
||||
|
||||
auto transformed_enumerate =
|
||||
util::views::from([] { return 1; }) |
|
||||
std::views::transform([](auto &&i) { return i + 1; }) |
|
||||
util::views::enumerate | std::views::take(10);
|
||||
|
||||
for (auto &&[i, e] : transformed_enumerate) {
|
||||
util::println("[{}] {}", i, e);
|
||||
}
|
||||
}
|
||||
|
||||
auto test_generated_view() {
|
||||
{
|
||||
const auto view = util::views::from([] { return 's'; });
|
||||
auto it = std::ranges::begin(view);
|
||||
|
||||
util::assert_eq(*it, *it);
|
||||
util::assert_eq(*it, 's');
|
||||
}
|
||||
|
||||
{
|
||||
auto count = 0;
|
||||
const auto view = util::views::from([&] { return count++; });
|
||||
auto it = std::ranges::begin(view);
|
||||
|
||||
util::assert_eq(*it, *it);
|
||||
util::assert_ne(*it++, *it++);
|
||||
util::assert_ne(*it + 1, *++it);
|
||||
}
|
||||
}
|
||||
|
||||
auto test_collect() {
|
||||
auto vec = std::vector<int>({1, 2, 3, 4, 5});
|
||||
auto range = vec | std::views::filter([](auto &i) { return i % 2; });
|
||||
|
||||
const auto set = util::collect<std::set<int>>(range);
|
||||
}
|
||||
|
||||
auto test_first() {
|
||||
const auto random =
|
||||
util::views::from([] {
|
||||
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY"
|
||||
[std::rand() %
|
||||
std::strlen(
|
||||
|
@ -55,20 +97,29 @@ int main(int argc, const char *argv[]) {
|
|||
}) |
|
||||
std::views::take(10) | util::views::collect<std::string>;
|
||||
|
||||
auto first = random | util::views::first;
|
||||
|
||||
const auto first = random | util::views::first;
|
||||
util::println("{}", first);
|
||||
util::println("{}", random);
|
||||
|
||||
for (auto&& i : infinite_range) {
|
||||
util::print("{}\n", i);
|
||||
}
|
||||
|
||||
const auto set = util::collect<std::set<int>>(range);
|
||||
auto test_assert_no_fail() {
|
||||
util::assert_ne("asdf"sv, "nsdf"sv);
|
||||
util::assert_eq(1, 1);
|
||||
util::assert_eq(1 == 1, true);
|
||||
util::assert_eq(0, false);
|
||||
}
|
||||
|
||||
auto test_panic() { util::panic("asdf {}", 42); }
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
printf("Hello, Alloy!\n");
|
||||
|
||||
test_iterator_t();
|
||||
test_enumerate_view();
|
||||
test_collect();
|
||||
test_generated_view();
|
||||
test_first();
|
||||
test_assert_no_fail();
|
||||
|
||||
util::print("hello {}\n", "world");
|
||||
|
||||
util::assert_ne("asdf"sv, "nsdf"sv);
|
||||
util::panic("asdf {}", 42);
|
||||
return 1;
|
||||
}
|
Loading…
Reference in a new issue