libkazv
Loading...
Searching...
No Matches
cursorutil.hpp
Go to the documentation of this file.
1/*
2 * This file is part of libkazv.
3 * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
4 * SPDX-License-Identifier: AGPL-3.0-or-later
5 */
6
7#pragma once
8#include "libkazv-config.hpp"
9
10#include <iterator>
11#include <boost/hana/type.hpp>
12
13#include <lager/constant.hpp>
14#include <lager/reader.hpp>
15#include <lager/lenses/optional.hpp>
16
17#include <zug/into.hpp>
18#include <zug/tuplify.hpp>
19#include <zug/transducer/each.hpp>
20#include <zug/run.hpp>
21
22namespace Kazv
23{
24 namespace detail
25 {
26 constexpr auto hasPushBack = boost::hana::is_valid(
27 [](auto t) -> decltype(
28 (void)
29 std::declval<typename decltype(t)::type>().push_back(std::declval<typename decltype(t)::type::value_type>())) { });
30
31 constexpr auto hasInsert = boost::hana::is_valid(
32 [](auto t) -> decltype(
33 (void)
34 std::declval<typename decltype(t)::type>().insert(std::declval<typename decltype(t)::type::value_type>())) { });
35
36 struct ImmerPushBackOrInsertT
37 {
38 template<class Container, class ...InputRanges>
39 auto operator()(Container container, InputRanges &&...ins) {
40 using ContT = std::decay_t<Container>;
41 if constexpr (hasPushBack(boost::hana::type_c<ContT>)) {
42 return std::move(container)
43 .push_back(zug::tuplify(std::forward<InputRanges>(ins)...));
44 } else {
45 static_assert(hasInsert(boost::hana::type_c<ContT>),
46 "Container must have either push_back() or insert() method");
47 return std::move(container)
48 .insert(zug::tuplify(std::forward<InputRanges>(ins)...));
49 }
50 }
51 };
52
53 inline ImmerPushBackOrInsertT immerPushBackOrInsert{};
54
55 struct IntoImmerT
56 {
57 // We check for both transient_type and persistent_type
58 // because for some containers, transient_type is not
59 // implemented.
60 constexpr static auto hasTransientType = boost::hana::is_valid(
61 [](auto t) -> boost::hana::type<typename decltype(t)::type::transient_type::persistent_type> {});
62
63 template<class Container, class Func, class ...InputRanges>
64 auto operator()(Container &&m, Func &&transducer, InputRanges &&...ins) const {
65 using ContainerT = std::decay_t<Container>;
66 if constexpr (hasTransientType(boost::hana::type_c<ContainerT>)) {
67 using TransientT = typename ContainerT::transient_type;
68 return zug::into(
69 std::forward<TransientT>(m.transient()),
70 std::forward<Func>(transducer),
71 std::forward<InputRanges>(ins)...)
72 .persistent();
73 } else {
74 ContainerT c;
75 zug::run(
76 std::forward<Func>(transducer)
77 | zug::each(
78 [&](auto ...ins) {
79 c = immerPushBackOrInsert(std::move(c), std::move(ins)...);
80 }),
81 std::forward<InputRanges>(ins)...);
82 return c;
83 }
84 }
85
86 };
87 }
88 inline detail::IntoImmerT intoImmer{};
89
90 namespace detail
91 {
92 inline auto looksLikeImmer = boost::hana::is_valid(
93 [](auto t) -> boost::hana::type<typename decltype(t)::type::transient_type> { });
94 struct ContainerMapT
95 {
96 template<class ResultContainer, class Func>
97 auto operator()(ResultContainer c, Func transducer) {
98 return zug::map(
99 [=](auto m) {
100 using ContT = std::decay_t<ResultContainer>;
101 if constexpr (looksLikeImmer(boost::hana::type_c<ContT>)) {
102 return intoImmer(c, transducer, m);
103 } else {
104 return zug::into(c, transducer, m);
105 }
106 });
107 }
108 };
109 }
110
111 inline detail::ContainerMapT containerMap{};
112
113 namespace CursorOp
114 {
115 template<class Cursor>
116 inline auto operator~(Cursor &&c)
117 {
118 return std::forward<Cursor>(c).make();
119 }
120
121 template<class Cursor>
122 inline auto operator+(Cursor &&c)
123 {
124 return (~std::forward<Cursor>(c)).get();
125 }
126 }
127
128 inline constexpr auto eventContent =
129 zug::map([](auto &&event) {
130 return std::forward<decltype(event)>(event).content();
131 });
132
133 namespace detail
134 {
135 constexpr auto isJsonWrap = boost::hana::is_valid(
136 [](auto t) -> decltype((void) std::declval<typename decltype(t)::type>().get()) { });
137 }
138
139 template<class T, class V>
140 constexpr auto jsonAtOr(T &&key, V &&defaultValue)
141 {
142 return
143 zug::map([key=std::forward<T>(key), def=std::forward<V>(defaultValue)](auto &&j) -> std::decay_t<V> {
144 using JsonT = decltype(j);
145 using ValueT = std::decay_t<V>;
146 try {
147 if constexpr (detail::isJsonWrap(boost::hana::type_c<std::decay_t<JsonT>>)) {
148 return j.get().contains(key)
149 ? std::forward<JsonT>(j).get().at(key).template get<ValueT>()
150 : def;
151 } else {
152 return j.contains(key)
153 ? std::forward<JsonT>(j).at(key).template get<ValueT>()
154 : def;
155 }
156 } catch (const std::exception &) {
157 return def;
158 }
159 });
160 }
161
162 namespace detail
163 {
164 struct AllTrueT
165 {
166 template<class B1, class ...Bs>
167 constexpr auto operator()(B1 &&b1, Bs &&...bs) const {
168 return std::forward<B1>(b1)
169 && operator()(std::forward<Bs>(bs)...);
170 }
171
172 constexpr auto operator()() const {
173 return true;
174 }
175 };
176
177 constexpr AllTrueT allTrue{};
178
179 struct AnyTrueT
180 {
181 template<class B1, class ...Bs>
182 constexpr auto operator()(B1 &&b1, Bs &&...bs) const {
183 return std::forward<B1>(b1)
184 || operator()(std::forward<Bs>(bs)...);
185 }
186
187 constexpr auto operator()() const {
188 return false;
189 }
190 };
191
192 constexpr AnyTrueT anyTrue{};
193 }
194
195 template<class Cursor, class ...Cursors>
196 constexpr auto allCursors(Cursor &&first, Cursors &&...cursors)
197 {
198 return lager::with(std::forward<Cursor>(first),
199 std::forward<Cursors>(cursors)...)
200 .map(detail::allTrue);
201 }
202
203 inline auto allCursors()
204 {
205 return lager::make_constant(detail::allTrue());
206 }
207
208 template<class Cursor, class ...Cursors>
209 constexpr auto anyCursor(Cursor &&first, Cursors &&...cursors)
210 {
211 return lager::with(std::forward<Cursor>(first),
212 std::forward<Cursors>(cursors)...)
213 .map(detail::anyTrue);
214 }
215
216 inline auto anyCursor()
217 {
218 return lager::make_constant(detail::anyTrue());
219 }
220}
auto operator~(Cursor &&c)
Definition cursorutil.hpp:116
auto operator+(Cursor &&c)
Definition cursorutil.hpp:122
ImmerPushBackOrInsertT immerPushBackOrInsert
Definition cursorutil.hpp:53
constexpr auto hasPushBack
Definition cursorutil.hpp:26
constexpr AllTrueT allTrue
Definition cursorutil.hpp:177
constexpr auto hasInsert
Definition cursorutil.hpp:31
constexpr AnyTrueT anyTrue
Definition cursorutil.hpp:192
auto looksLikeImmer
Definition cursorutil.hpp:92
constexpr auto isJsonWrap
Definition cursorutil.hpp:135
Definition location.hpp:10
constexpr auto eventContent
Definition cursorutil.hpp:128
auto allCursors()
Definition cursorutil.hpp:203
auto anyCursor()
Definition cursorutil.hpp:216
constexpr auto jsonAtOr(T &&key, V &&defaultValue)
Definition cursorutil.hpp:140
detail::IntoImmerT intoImmer
Definition cursorutil.hpp:88
detail::ContainerMapT containerMap
Definition cursorutil.hpp:111