• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DNKpp / Simple-Utility / 6497034454

12 Oct 2023 02:27PM UTC coverage: 86.872% (-12.8%) from 99.712%
6497034454

Pull #71

github

web-flow
Merge 967744a15 into e4166ac5d
Pull Request #71: graph namespace

281 of 281 new or added lines in 17 files covered. (100.0%)

622 of 716 relevant lines covered (86.87%)

154.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/include/Simple-Utility/nullables/base.hpp
1
//          Copyright Dominic Koepke 2019 - 2023.
2
// Distributed under the Boost Software License, Version 1.0.
3
//    (See accompanying file LICENSE_1_0.txt or copy at
4
//          https://www.boost.org/LICENSE_1_0.txt)
5

6
#ifndef SL_UTILITY_NULLABLES_BASE_HPP
7
#define SL_UTILITY_NULLABLES_BASE_HPP
8

9
#pragma once
10

11
#include "Simple-Utility/Config.hpp"
12
#include "Simple-Utility/concepts/operators.hpp"
13
#include "Simple-Utility/concepts/stl_extensions.hpp"
14

15
#include <cstddef>
16
#include <functional>
17
#include <type_traits>
18

19
namespace sl::nullables
20
{
21
        /**
22
         * \defgroup GROUP_NULLABLES nullables
23
         *
24
         * \brief This library offers some simple algorithms for convenient working with \ref sl::nullables::nullable "nullable" types.
25
         * \details
26
         * ## General
27
         * The algorithms may be chained in arbitrary combination and deepness, as long as it makes sense to the compiler. Such a
28
         * chain may involve multiple different \ref sl::nullables::nullable "nullable" types. Of this library explicitly supported types are:
29
         * - \ref sl::unique_handle ("Simple-Utility/unique_handle.hpp" header must be included)
30
         * - [std::optional](https://en.cppreference.com/w/cpp/utility/optional) ("Simple-Utility/nullables/std_optional.hpp" header must be included)
31
         * - [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) ("Simple-Utility/nullables/std_pointers.hpp" header must be included)
32
         * - [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr) ("Simple-Utility/nullables/std_pointers.hpp" header must be included)
33
         * - and ``raw pointers``
34
         *
35
         * The general idea is making the handling with types e.g. ``std::optional`` less verbose and more enjoyable. The syntax is inspired by
36
         * the ``std::ranges`` library and [this proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html).
37
         * If you would like to learn more about an algorithm, just visit the specific sub-page:
38
         *        - \ref sl::nullables::or_else "or_else"
39
         *        - \ref sl::nullables::and_then "and_then"
40
         *        - \ref sl::nullables::value_or "value_or"
41
         *        - \ref sl::nullables::fwd_value "fwd_value"
42
         *
43
         *        ### Quick algorithm example
44
         *        This example demonstrates that \ref sl::nullables::and_then "and_then" and \ref sl::nullables::or_else "or_else" algorithms can
45
         *        be chained in arbitrarily length. \ref sl::nullables::value_or "value_or" and \ref sl::nullables::fwd_value "fwd_value" on the
46
         *        other side act as a terminator (as they usually do not return a \ref sl::nullables::nullable "nullable" objects).
47
         * \snippet algorithm.cpp algorithm chain
48
         *
49
         * This can be quite useful, but the library can even better than this. All nullable algorithms are designed to work properly with the functional
50
         * part of this library, thus the above example can be adjusted like this:
51
         * \snippet algorithm.cpp algorithm chain functional
52
         *
53
         * At last I would like to quickly present a naive comparison between the usual stl style and the style this library offers.
54
         * In this example I utilize a adapter, which already supports iterator adapting out of the box.
55
         * \snippet adapter.cpp adapter comparison
56
         *
57
         * ## Using custom types
58
         * Well, that depends which interface your type offers. If it's already dereferencable via ``operator *`` and it has an explicit ``null``-object,
59
         * which it can equality compared to, than you are in a good position.
60
         *
61
         * ### There exists a dedicated type or constexpr null object
62
         * Just specialize \ref sl::nullables::traits "nullable traits". If your type then doesn't offer a ``operator *`` access or it
63
         * doesn't follow the semantics, you can hook the ``unwrap`` customization point and simply create an overload in the types namespace.
64
         *
65
         * ### No dedicated type or constexpr null object exists
66
         * If your type doesn't have a dedicated null object or it is simply not constexpr constructible, you can wrap your type and a null object into
67
         * \ref sl::nullables::adapter "adapter" object. Depending how your type behaves with the null object, this adapter will be either a ``input_nullable``
68
         * or even a ``nullable``.
69
         *
70
         * If your type doesn't offer a ``operator *`` access or it doesn't follow the semantics, you can hook the ``unwrap_adapted`` customization point and
71
         * simply create an overload in the types namespace.
72
         *
73
         * @{
74
         */
75

76
        /**
77
         * \defgroup GROUP_NULLABLES_CUSTOMIZATION_POINTS customization points
78
         *
79
         * \brief Contains several customization points, which users may hook for their custom types.
80
         * \details Nullables namespace are designed to work out of the box with types satisfying the corresponding concepts, but sometimes custom types
81
         * can not be tweaked freely. This is when the pre-defined customization points begin to shine, as users may simply put overloads in the types namespace
82
         * and let the ADL do the work finding it.
83
         */
84

85
        /**
86
         * \defgroup GROUP_NULLABLES_TRAITS traits
87
         *
88
         * \brief These traits are used by the \ref GROUP_NULLABLES_ALGORITHMS "algorithms" and my be specialized by users for their custom types.
89
         * @{
90
         */
91

92
        /**
93
         * \brief The main trait, which may be specialized from.
94
         * \tparam T The type to query
95
         */
96
        template <class T>
97
        struct traits;
98

99
        /**
100
         * \brief Convenience alias retrieving the value type of a \ref sl::nullables::nullable "nullable" type
101
         * \tparam T The type to query
102
         */
103
        template <class T>
104
        using value_t = typename traits<std::remove_cvref_t<T>>::value_type;
105

106
        /**
107
         * \brief Convenience constant retrieving the null object of a \ref sl::nullables::nullable "nullable" type
108
         * \tparam T  The type to query
109
         */
110
        template <class T>
111
        constexpr static auto null_v{traits<std::remove_cvref_t<T>>::null};
112

113
        /**
114
         * \brief Specialization for raw pointers
115
         * \tparam T Pointer type
116
         */
117
        template <class T>
118
                requires std::is_pointer_v<T>
119
        struct traits<T>
120
        {
121
                using value_type = std::remove_pointer_t<T>;
122
                static constexpr std::nullptr_t null{nullptr};
123
        };
124

125
        /** @} */
126

127
        namespace detail
128
        {
129
                template <class TNullable>
130
                        requires concepts::dereferencable_r<TNullable, value_t<TNullable>>
131
                [[nodiscard]]
132
                constexpr decltype(auto) unwrap(
132✔
133
                        TNullable&& na
134
                )
135
                        noexcept
136
                {
137
                        return *std::forward<TNullable>(na);
132✔
138
                }
139

140
                struct unwrap_fn
141
                {
142
                        template <class TNullable>
143
                                requires requires { { unwrap(std::declval<TNullable>()) } -> std::convertible_to<value_t<TNullable>>; }
144
                        [[nodiscard]]
145
                        constexpr decltype(auto) operator()(TNullable&& na) const noexcept
×
146
                        {
147
                                return unwrap(std::forward<TNullable>(na));
×
148
                        }
149
                };
150
        }
151

152
        /**
153
         * \brief Retrieves the value of the given \ref sl::nullables::input_nullable "input_nullable".
154
         * \ingroup GROUP_NULLABLES_CUSTOMIZATION_POINTS
155
         * \details This function is only called if the given \ref sl::nullables::input_nullable "input_nullable" compares unequal to its ``null``-object,
156
         * thus it will never access an invalid \ref sl::nullables::input_nullable "input_nullable" and therefore any additional checks in custom
157
         * overloads will be unnecessary overhead, which can be avoided.
158
         * \note Custom overloads should never throw.
159
         */
160
        inline constexpr detail::unwrap_fn unwrap{};
161

162
        /**
163
         * \brief Checks whether a type is an \ref sl::nullables::input_nullable "input_nullable".
164
         * \details A type is considered as \ref sl::nullables::input_nullable "input_nullable" if:
165
         *                - ``nullable_traits`` is found which exposes the ``value_type`` and ``null``-object,
166
         *                - it satisfies the \ref sl::concepts::weakly_equality_comparable_with "weakly_equality_comparable_with" concept with its ``null``-object,
167
         * \tparam T Type to check
168
         */
169
        template <class T>
170
        concept input_nullable = requires
171
                                                        {
172
                                                                typename value_t<T>;
173
                                                                null_v<T>;
174
                                                        }
175
                                                        && concepts::weakly_equality_comparable_with<T, decltype(null_v<T>)>;
176

177
        /**
178
         * \brief Checks whether a type is \ref sl::nullables::nullable "nullable".
179
         * \details A type is considered as \ref sl::nullables::nullable "nullable" if:
180
         *                - it satisfies the \ref sl::nullables::input_nullable "input_nullable" concept
181
         *                - it is initializable by its ``null``-object and
182
         *                - it is assignable by its ``null``-object.
183
         * \tparam T Type to check
184
         */
185
        template <class T>
186
        concept nullable = input_nullable<T>
187
                                                && concepts::initializes<decltype(null_v<T>), std::remove_cvref_t<T>>
188
                                                && std::is_assignable_v<std::remove_cvref_t<T>&, decltype(null_v<T>)>;
189
}
190

191
namespace sl::nullables::detail
192
{
193
        struct algorithm_tag
194
        {
195
        };
196
}
197

198
namespace sl::nullables
199
{
200
        /**
201
         * \defgroup GROUP_NULLABLES_ALGORITHMS algorithms
202
         *
203
         * \brief Contains nullable algorithm related symbols.
204
         * \details There already exists several pre-defined algorithms, but users may easily write their own algorithm within a few lines.
205
         * \snippet nullables/base.cpp algorithm custom
206
         * @{
207
         */
208

209
        /**
210
         * \brief The core algorithm helper, which executes the held operation when used as the right-hand-side of ``operator |`` expressions,
211
         * when the left-hand-side is a valid ``nullable`` type.
212
         * \tparam Operation The function type.
213
         */
214
        template <concepts::unqualified Operation>
215
        class Algorithm
216
        {
217
        public:
218
                [[nodiscard]]
219
                explicit Algorithm(Operation operation) noexcept(std::is_nothrow_move_constructible_v<Operation>)
386✔
220
                        : m_Operation{std::move(operation)}
386✔
221
                {
222
                }
386✔
223

224
                template <input_nullable Nullable>
225
                        requires std::regular_invocable<Operation, Nullable>
226
                                        && std::is_void_v<std::invoke_result_t<Operation, Nullable>>
227
                friend constexpr auto operator |(
68✔
228
                        Nullable&& input,
229
                        const Algorithm& algorithm
230
                ) noexcept(std::is_nothrow_invocable_v<Operation, Nullable>)
231
                {
232
                        return std::invoke(algorithm.m_Operation, std::forward<Nullable>(input));
68✔
233
                }
234

235
                template <input_nullable Nullable>
236
                        requires std::regular_invocable<Operation, Nullable>
237
                [[nodiscard]]
238
                friend constexpr auto operator |(
159✔
239
                        Nullable&& input,
240
                        const Algorithm& algorithm
241
                ) noexcept(std::is_nothrow_invocable_v<Operation, Nullable>)
242
                {
243
                        return std::invoke(algorithm.m_Operation, std::forward<Nullable>(input));
159✔
244
                }
245

246
        private:
247
                SL_UTILITY_NO_UNIQUE_ADDRESS
248
                Operation m_Operation{};
249
        };
250

251
        /** @} */
252

253
        /** @} */
254
}
255

256
namespace sl::nullables::detail
257
{
258
        template <class T>
259
        using dereference_result_t = decltype(nullables::unwrap(std::declval<T>()));
260
}
261

262
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc