packio
args_specs.h
Go to the documentation of this file.
1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 
5 #ifndef PACKIO_ARGS_SPECS_H
6 #define PACKIO_ARGS_SPECS_H
7 
10 
11 #include <optional>
12 #include <stdexcept>
13 #include <string>
14 
15 #include "arg.h"
16 #include "handler.h"
17 #include "internal/utils.h"
18 
19 namespace packio {
20 namespace internal {
21 
22 template <typename DefaultType>
23 class arg_spec {
24 public:
25  explicit arg_spec(std::string name) : name_(std::move(name)) {}
26  explicit arg_spec(const arg& arg) : name_(arg.name()) {}
27  explicit arg_spec(arg::with_value<DefaultType> arg)
28  : name_(std::move(arg.name)), default_value_(std::move(arg.value))
29  {
30  }
31 
32  const std::string& name() const { return name_; }
33  const std::optional<DefaultType>& default_value() const
34  {
35  return default_value_;
36  }
37 
38 private:
39  std::string name_;
40  std::optional<DefaultType> default_value_;
41 };
42 
43 template <typename F>
44 using arg_specs_tuple_for_sync_procedure_t =
45  map_tuple_t<arg_spec, decay_tuple_t<typename func_traits<F>::args_type>>;
46 
47 template <typename F>
48 using arg_specs_tuple_for_async_procedure_t =
49  left_shift_tuple_t<arg_specs_tuple_for_sync_procedure_t<F>>;
50 
51 template <typename, bool>
52 struct arg_specs_tuple_for;
53 
54 template <typename F>
55 struct arg_specs_tuple_for<F, true> {
56  using type = arg_specs_tuple_for_async_procedure_t<F>;
57 };
58 
59 template <typename F>
60 struct arg_specs_tuple_for<F, false> {
61  using type = arg_specs_tuple_for_sync_procedure_t<F>;
62 };
63 
64 template <typename F>
65 using arg_specs_tuple_for_t =
66  typename arg_specs_tuple_for<F, is_async_procedure_v<F>>::type;
67 
68 template <typename T>
69 struct args_specs_maker;
70 
71 template <typename... Specs>
72 struct args_specs_maker<std::tuple<Specs...>> {
73  template <typename... Args>
74  static std::tuple<Specs...> make(Args&&... args)
75  {
76  if constexpr (sizeof...(Args) == 0) {
77  // default arg specs are arguments called "0", "1", ... and no default value
78  return iota(std::make_index_sequence<sizeof...(Specs)>());
79  }
80  else {
81  static_assert(
82  sizeof...(Args) == sizeof...(Specs),
83  "arguments specification must either match the number of "
84  "arguments or be empty");
85  return {Specs{std::forward<Args>(args)}...};
86  }
87  }
88 
89  template <std::size_t... Idxs>
90  static std::tuple<Specs...> iota(std::index_sequence<Idxs...>)
91  {
92  return {Specs{std::to_string(Idxs)}...};
93  }
94 };
95 
103  bool allow_extra_arguments = false;
104 
105  constexpr args_specs_options operator|(const args_specs_options& other)
106  {
107  auto ret = *this;
108  ret.allow_extra_arguments |= other.allow_extra_arguments;
109  return ret;
110  }
111 };
112 
113 template <typename SpecsTuple>
114 class args_specs {
115 public:
116  args_specs() : args_specs(args_specs_options{}){};
117 
118  template <
119  typename T,
120  typename... Args,
121  typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, args_specs_options>>>
122  args_specs(T&& arg0, Args&&... args)
123  : args_specs(
124  args_specs_options{},
125  std::forward<T>(arg0),
126  std::forward<Args>(args)...)
127  {
128  }
129 
130  template <typename... Args>
131  args_specs(args_specs_options opts, Args&&... args)
132  : specs_{args_specs_maker<SpecsTuple>::make(std::forward<Args>(args)...)},
133  opts_{std::move(opts)}
134  {
135  }
136 
137  constexpr const args_specs_options& options() const { return opts_; }
138 
139  template <std::size_t I>
140  constexpr decltype(auto) get() const
141  {
142  return std::get<I>(specs_);
143  }
144 
145  static constexpr std::size_t size()
146  {
147  return std::tuple_size_v<SpecsTuple>;
148  }
149 
150 private:
151  SpecsTuple specs_;
152  args_specs_options opts_{};
153 };
154 } // internal
155 
170 template <typename Procedure>
172  // Using the real implementation as the base class reduces
173  // the number of templates instanciation
174  : public internal::args_specs<internal::arg_specs_tuple_for_t<Procedure>> {
175 public:
176  using base = internal::args_specs<internal::arg_specs_tuple_for_t<Procedure>>;
177  using base::base;
178 };
179 
182 
183 } // packio
184 
185 #endif // PACKIO_ARGS_SPECS_H
Class arg.
Procedure arguments specifications.
Definition: args_specs.h:174
Class completion_handler.
The packio namespace.
Definition: arg.h:14
constexpr auto allow_extra_arguments
Option to allo extra arguments, ignoring them.
Definition: args_specs.h:181
Options available for the argument specifications.
Definition: args_specs.h:102