libkazv
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 
22 namespace 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
constexpr auto anyCursor(Cursor &&first, Cursors &&...cursors)
Definition: cursorutil.hpp:209
constexpr auto allCursors(Cursor &&first, Cursors &&...cursors)
Definition: cursorutil.hpp:196
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