Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Function.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_Function_h_
5#define _Stroika_Foundation_Execution_Function_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10#include <functional>
11#include <memory>
12
13#include "Stroika/Foundation/Common/Common.h"
14
15/**
16 * \file
17 *
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 *
20 * TODO
21 * @todo Instead of using shared_ptr<> - we could have an INT counter (except for special case of null where we use
22 * 0). That might be cheaper, and preserve the same semantics.
23 *
24 * @todo Better understand, and fix qFoundation_Execution_Function_OperatorForwardNeedsRefBug, and eliminate it
25 *
26 * @todo Consider if this should be copy-by-value (use SharedByValue instead of shared_ptr) so it more closely
27 * mimics copy behavior of std::function?
28 */
29
31 class String;
32}
33
34// Function's own definitions - here and in Function.inl - name it: only uses outside them should warn it is deprecated
35DISABLE_COMPILER_MSC_WARNING_START (4996);
36DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
37DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
38
40
41 // SB in .inl file except to support qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
42 namespace Private_ {
43 inline atomic<uint32_t> sFunctionObjectNextPtrID_{1};
44 }
45
46 /**
47 * IDEA is be SAME AS std::function<> but allow for operator<, a usable operator== etc...,
48 * which is an unfortunate omission from the c++ standard.
49 *
50 * This should be convertible to a normal std::function<>, and fairly if not totally interoperable.
51 *
52 * @aliases This template could have been called Callback<> - as that's principally what its used for.
53 * Callbacks you need to be able to create, and then later remove (by value) - and this class
54 * lets you create an object (callback/Function) - which can then be added to a Mapping (or Set)
55 * and then later removed by value.
56 *
57 * \deprecated Since Stroika v3.0d25 - use std::function; and for callbacks to remove later, Execution::CallbackRegistry, which
58 * removes by the ID its Add returns. Removing by a Function works only with the Function added, or a copy of it -
59 * and a lambda, converted implicitly, is a new one, so 'the same' lambda removes nothing (@see CallbackRegistry).
60 *
61 * \note This was implemented using a shared_ptr<function<...>> instead of a directly aggregated function object
62 * until Stroika v2.1d8.
63 *
64 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
65 * static_assert (totally_ordered<Function<...>);
66 */
67 template <typename FUNCTION_SIGNATURE>
68 class [[deprecated ("Since Stroika v3.0d25 - use std::function; for callbacks to remove later, Execution::CallbackRegistry")]] Function {
69 public:
70 using STDFUNCTION = function<FUNCTION_SIGNATURE>;
71
72 public:
73 /**
74 */
75 using result_type = typename STDFUNCTION::result_type;
76
77 public:
78 /**
79 * \note Implementation note:
80 * Reason for the not derived_from<> restriction on CTOR/1(CTOR_FUNC_SIG&&) is to prevent compiler from
81 * instantiating that constructor template for argument subclasses of this Function type, and having those take precedence over the
82 * default X(const X&) CTOR.
83 *
84 * And also careful not to apply to non-functions.
85 *
86 * \note Constructor with nullptr or a null function object - will produce a UNIQUE function value (according to operator==).
87 * ANY other function object - each time you call the constructor - you will get a different (according to operator==) Function
88 * object. See https://github.com/SophistSolutions/Stroika/issues/1092 (STK-960) for some of the reasoning behind this.
89 */
90 Function () = default;
91 Function (nullptr_t);
92 Function (const Function&) = default;
93 Function (Function&&) = default;
94#if qCompilerAndStdLib_template_Requires_constraint_not_treated_constexpr_Buggy
95 template <typename CTOR_FUNC_SIG, enable_if_t<is_convertible_v<remove_cvref_t<CTOR_FUNC_SIG>, function<FUNCTION_SIGNATURE>> and
96 not derived_from<remove_cvref_t<CTOR_FUNC_SIG>, Function<FUNCTION_SIGNATURE>>>* = nullptr>
97 Function (CTOR_FUNC_SIG&& f);
98#else
99 template <typename CTOR_FUNC_SIG>
100 requires (is_convertible_v<remove_cvref_t<CTOR_FUNC_SIG>, function<FUNCTION_SIGNATURE>> and
101 not derived_from<remove_cvref_t<CTOR_FUNC_SIG>, Function<FUNCTION_SIGNATURE>>)
102 Function (CTOR_FUNC_SIG&& f)
103#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
104 : fFun_{forward<CTOR_FUNC_SIG> (f)}
105 , fOrdering_{fFun_ == nullptr ? OrderingType_{} : ++Private_::sFunctionObjectNextPtrID_}
106 {
107 Assert ((fOrdering_ == OrderingType_{}) == (fFun_ == nullptr));
108 }
109#endif
110#endif
111 ;
112
113 public:
114 /**
115 */
116 nonvirtual Function& operator= (Function&&) = default;
117 nonvirtual Function& operator= (const Function&) = default;
118
119 public:
120 /**
121 */
122 nonvirtual operator STDFUNCTION () const;
123
124 public:
125 /**
126 */
127 template <typename... Args>
128 nonvirtual result_type operator() (Args... args) const;
129
130 public:
131 struct ThreeWayComparer;
132
133 public:
134 /**
135 */
136 nonvirtual strong_ordering operator<=> (const Function& rhs) const;
137
138 public:
139 /**
140 */
141 nonvirtual bool operator== (const Function& rhs) const;
142
143 public:
144 /**
145 * @see Characters::ToString ();
146 */
147 nonvirtual Characters::String ToString () const;
148
149 private:
150 STDFUNCTION fFun_;
151
152 private:
153 /*
154 * Before Stroika 2.1.11, we used f.template target<remove_cvref_t<CTOR_FUNC_SIG>> ()
155 * as OrderingType_. But this caused problems on g++-10 release builds (at least inside WTF). Not sure
156 * exactly how this happened, but sometimes different lambdas produced the same address. And the docs
157 * for std::function<> suggest this is possible.
158 *
159 * So just avoid altogether. Simply store a separate number ID.
160 */
161 using OrderingType_ = uint32_t;
162 OrderingType_ fOrdering_{}; // captured early when we have the right type info, so we can safely compare, and print
163 };
164
165}
166
167/*
168 ********************************************************************************
169 ***************************** Implementation Details ***************************
170 ********************************************************************************
171 */
172#include "Function.inl"
173
174DISABLE_COMPILER_MSC_WARNING_END (4996);
175DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
176DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
177
178#endif /*_Stroika_Foundation_Execution_Function_h_*/
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})