Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Property.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_Property_h_
5#define _Stroika_Foundation_Common_Property_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <concepts>
10#include <forward_list>
11#include <functional>
12#include <mutex>
13#include <optional>
14
15#include "Stroika/Foundation/Common/Common.h"
17#include "Stroika/Foundation/Execution/LazyInitialized.h" // tmp for deprecation impl
18
19/**
20 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
21 *
22 * Notes:
23 * I've long thought about doing something like this, but only recently got frustrated with
24 * the ugliness of tons of getters and setters. So I googled for solutions, and was surprised
25 * there was so little traction behind adding this feature to C++ (from C#).
26 *
27 * These links give a few hints about discussions of adding this feature to c++:
28 * * http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/2004/n1615.pdf
29 * * https://stackoverflow.com/questions/40559828/c-properties-with-setter-and-getter
30 * * https://www.reddit.com/r/cpp/comments/61m9r1/what_do_you_think_about_properties_in_the_c/
31 *
32 * TODO:
33 * @todo Consider redoing so type of Getter/Setter embedded into the class, so it can
34 * be saved RAW, and not converted to a function pointer. Trickier to do construction,
35 * but probably possible with template guides. But only bother if there is a clear
36 * performance benefit, because this is simpler.
37 *
38 */
39
41
42 /**
43 * There are two good ways to access the address of the outer object from the property.
44 * One is clearly and straight-forwardly portable safe C++, and the other is more efficient
45 * and generally safe. Users of this class can choose on their own which style to use.
46 * But this #define provides a configurable choice between the two approaches if you use it - and Stroika does internally -
47 * between those approaches so you can change it through configuration.
48 * To use this automatically use qStroika_Foundation_Common_Property_EmbedThisInProperties, and qStroika_Foundation_Common_Property_OuterObjPtr
49 * as below in the example documentation for Property constructor
50 *
51 * \see For more information on this topic, see
52 * https://stackoverflow.com/questions/65940393/c-why-the-restriction-on-offsetof-for-non-standard-layout-objects-or-how-t?noredirect=1#comment116600269_65940393
53 *
54 * \see http://stroika-bugs.sophists.com/browse/STK-939 - probably LOSE This define and REQUIRE its always zero, so can COPY properties safely.
55 */
56#ifndef qStroika_Foundation_Common_Property_EmbedThisInProperties
57#if qCompilerAndStdLib_function_dependency_too_complex_Buggy
58#define qStroika_Foundation_Common_Property_EmbedThisInProperties 1
59#else
60#define qStroika_Foundation_Common_Property_EmbedThisInProperties 0
61#endif
62#endif
63
64#if qStroika_Foundation_Common_Property_EmbedThisInProperties
65 /**
66 * @see qStroika_Foundation_Common_Property_EmbedThisInProperties
67 */
68#define qStroika_Foundation_Common_Property_ExtraCaptureStuff this
69 /**
70 * @see qStroika_Foundation_Common_Property_EmbedThisInProperties
71 */
72#define qStroika_Foundation_Common_Property_OuterObjPtr(property, propertyPtrToMember) this
73#else
74 /**
75 * @see qStroika_Foundation_Common_Property_EmbedThisInProperties
76 */
77#define qStroika_Foundation_Common_Property_ExtraCaptureStuff
78 /**
79 * @see qStroika_Foundation_Common_Property_EmbedThisInProperties
80 */
81#define qStroika_Foundation_Common_Property_OuterObjPtr(property, propertyPtrToMember) \
82 Memory::GetObjectOwningField (property, propertyPtrToMember)
83#endif
84
85 struct PropertyCommon {
86 /**
87 * read-only Properties (or the read method of a normal Property) can be used to 'simulate' read-write access (by having it return a mutable reference)
88 * This flag tells is that is going on, so we can make our accessor methods non-const in that case.
89 *
90 * \note This is SUBTLE but important for 'constness' to work properly.
91 * if we use
92 * struct OwningObject {
93 * ReadOnlyProperty<FOO&> p;
94 * then we want code:
95 * OwningObject& o = ...;
96 * const OwningObject& co = o;
97 * o.p().constOrNonConstMethod(); // OK
98 * co.p().constMethod (); // OK
99 * co.p().nonConstMethod (); // should fail to compile
100 *
101 * kIsMutableType, plus appropriate requires on the various accessor methods are designed to accomplish that.
102 */
103 template <typename TT>
104 static constexpr bool kIsMutableType = not is_const_v<remove_reference_t<TT>> and is_reference_v<TT>;
105
106 enum class PropertyChangedEventResultType {
107 eSilentlyCutOffProcessing,
108 eContinueProcessing,
109 };
110 };
111
112 template <typename T>
113 concept IPropertyMutatable = PropertyCommon::kIsMutableType<T>;
114
115 /**
116 * Implement C#-like syntax for read-only properties (syntactically like data members but backed by a getter function)
117 * \note Typically not used - use Property
118 * \note ANYHOW - see @Property for design overview
119 *
120 * \note We allow T to be of REFERENCE type for ReadOnlyProperties. Not sure its a good idea to be
121 * returning a const T& from a property, but it works/is allowed (for now).
122 *
123 * Note - unlike with functions - you cannot overload properties, making one return const T& and one return T&
124 *
125 * \note \em Thread-Safety <a href="Thread-Safety.md">SAME AS T/GETTER - all methods have exactly the thread safety of the underlying GETTER</a>
126 */
127 template <typename T>
129 public:
130 /**
131 */
132 using value_type = T;
133
134 public:
135 /**
136 * ReadOnlyProperty are NOT movable, nor copy constructible: the data doesn't logically exist in the property itself,
137 * but in its relationship to some parent object; if it were copied, it might be copied TO some place that didn't
138 * have an appropriate enclosing object.
139 */
140 ReadOnlyProperty () = delete;
141 ReadOnlyProperty (const ReadOnlyProperty&) = delete;
143 template <qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (invocable<const ReadOnlyProperty<T>*>) G>
144 constexpr ReadOnlyProperty (G getter)
145 qCompilerAndStdLib_RequiresNotMatchXXXDefined_2_BWA (requires (convertible_to<invoke_result_t<G, const ReadOnlyProperty<T>*>, T>));
146
147 public:
148 nonvirtual ReadOnlyProperty& operator= (const ReadOnlyProperty&) = delete;
149 nonvirtual ReadOnlyProperty& operator= (const ReadOnlyProperty&&) = delete;
150
151 public:
152 /**
153 * Returns the value of the given property T (by calling the underlying 'getter' for the property.
154 * This is a non-const method if PropertyCommon::kIsMutableType<T>, and otherwise a const method.
155 */
156 nonvirtual T Get () const
157 requires (not IPropertyMutatable<T>);
158 nonvirtual T Get ()
159 requires (IPropertyMutatable<T>);
160
161 public:
162 /**
163 * A ReadOnlyProperty can be automatically converted to its underlying base type.
164 * Due to how conversion operators work, this won't always be helpful (like with overloading
165 * or multiple levels of conversions, for example with optional<int> compare with int property).
166 * But when it works (80% of the time) - its helpful.
167 *
168 * When it doesn't work, simply throw in '()' - to use the 'operator()' call, or call Get()
169 * if you prefer that syntax.
170 *
171 * This is a non-const method if PropertyCommon::kIsMutableType<T>, and otherwise a const method.
172 */
173 nonvirtual operator const T () const
174 requires (not IPropertyMutatable<T>);
175 nonvirtual operator T ()
176 requires (IPropertyMutatable<T>);
177
178 public:
179 /**
180 * This works 100% of the time. Just use the function syntax, and you get back a copy of the desired
181 * underlying type.
182 *
183 * \par Example Usage
184 * \code
185 * namespace PredefinedInternetMediaType { const inline Common::VirtualConstant<InternetMediaType> kPNG...
186 *
187 * bool checkIsImage1 = PredefinedInternetMediaType::kPNG().IsA (InternetMediaTypes::Wildcards::kImage);
188 * \endcode
189 *
190 * This is a non-const method if PropertyCommon::kIsMutableType<T>, and otherwise a const method.
191 */
192 nonvirtual const T operator() () const
193 requires (not IPropertyMutatable<T>);
194 nonvirtual T operator() ()
195 requires (IPropertyMutatable<T>);
196
197 private:
198 const function<T (const ReadOnlyProperty*)> fGetter_;
199 };
200
201 /**
202 * Implement C#-like syntax for write-only properties (syntactically like data members but backed by a setter function)
203 * \note Typically not used - use Property
204 * \note ANYHOW - see @Property for design overview
205 *
206 * \note \em Thread-Safety <a href="Thread-Safety.md">SAME AS T/SETTER - all methods have exactly the thread safety of the underlying SETTER</a>
207 */
208 template <typename T>
210 public:
211 /**
212 */
213 using value_type = T;
214
215 public:
216 /**
217 * WriteOnlyProperty are NOT movable, nor copy constructible: the data doesn't logically exist in the property itself,
218 * but in its relationship to some parent object; if it were copied, it might be copied TO some place that didn't
219 * have an appropriate enclosing object.
220 */
221 WriteOnlyProperty () = delete;
222 WriteOnlyProperty (const WriteOnlyProperty&) = delete;
224
225 template <qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (invocable<WriteOnlyProperty<T>*, T>) S>
226 constexpr WriteOnlyProperty (S setter);
227
228 public:
229 /**
230 * You can assign a value of the underlying type, but we do NOT support operator=(WriteOnlyProperty) because
231 * we cannot generically read from a write-only property to copy its value.
232 */
233 nonvirtual WriteOnlyProperty& operator= (ArgByValueType<T> value);
234 nonvirtual WriteOnlyProperty& operator= (const WriteOnlyProperty&) = delete;
235 nonvirtual WriteOnlyProperty& operator= (const WriteOnlyProperty&&) = delete;
236
237 public:
238 /**
239 * Alternate syntax for setting the property value.
240 */
241 nonvirtual void Set (ArgByValueType<T> value);
242
243 public:
244 /**
245 * Alternate syntax for setting the property value.
246 */
247 nonvirtual void operator() (ArgByValueType<T> value);
248
249 private:
250 const function<void (WriteOnlyProperty*, ArgByValueType<T>)> fSetter_;
251 };
252
253 /**
254 * Implement C#-like syntax for properties (syntactically like data members but backed by a getter and a setter function).
255 *
256 * Properties are NOT movable, nor copy constructible: the data doesn't logically exist in the property itself,
257 * but in its relationship to some parent object; if it were copied, it might be copied TO some place that didn't
258 * have an appropriate enclosing object.
259 *
260 * But, properties are ASSIGNABLE TO, because here we retain our getter/setter, and just treat assignment as copying the value.
261 *
262 * \note This has implications for classes that use Property objects: they will not be able to use X(const X&) = default;
263 * nor X(X&&) = default; Classes with properties can be copy constructed/move constructed, but just not automatically
264 * (memberwise). It wouldn't make sense to do memberwise because typically the property just 'knows how to find the data'
265 * stored elsewhere in the owning object.
266 *
267 * \note Though this looks syntactically much like using a direct data member, it will likely have some performance overhead
268 * due to forcing the use of a std::function wrapping a lambda for each access to the underlying object of type T.
269 *
270 * \note see base class ReadOnlyProperty and WriteOnlyProperty for details on APIs to read/write the underlying data.
271 *
272 * \note New Stroika NAMING CONVENTION introduced for instance variables of type Property<...>, which is to prepend a 'p'. This
273 * convention is to emphasize that these names DONT work QUITE like fields, but only somewhat like fields.
274 *
275 * \par Example Usage
276 * \code
277 * struct Headers {
278 * public:
279 * Headers ();
280 * Headers (const Headers& src);
281 * Headers (Headers&& src);
282 * nonvirtual Headers& operator= (const Headers& rhs) = default; // properties are assignable, so this is OK
283 * nonvirtual Headers& operator = (Headers&& rhs);
284 *
285 * Property<unsigned int> contentLength1; // all 3 refer to the private fContentLength_ field
286 * Property<unsigned int> contentLength2;
287 * Property<unsigned int> contentLength3;
288 *
289 * private:
290 * unsigned int fContentLength_{0};
291 * };
292 * Headers::Headers ()
293 * // Can implement getter/setters with this capture (wastes a bit of space)
294 * : contentLength1{
295 * [this] ([[maybe_unused]] const auto* property) {
296 * return fContentLength_;
297 * },
298 * [this] ([[maybe_unused]] auto* property, const auto& contentLength) {
299 * fContentLength_ = contentLength;
300 * }}
301 * // Can implement getter/setters with Memory::GetObjectOwningField - to save space, but counts on exact
302 * // storage layout and not totally legal with non- is_standard_layout<> - see Memory::GetObjectOwningField
303 * , contentLength2{
304 * [] (const auto* property) {
305 * const Headers* headerObj = Memory::GetObjectOwningField (property, &Headers::contentLength2);
306 * return headerObj->fContentLength_;
307 * },
308 * [] (auto* property, auto contentLength) {
309 * Headers* headerObj = Memory::GetObjectOwningField (property, &Headers::contentLength2);
310 * headerObj->fContentLength_ = contentLength;
311 * }}
312 * // Use stroika #define to decide which strategy to use
313 * , contentLength3{
314 * [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]const auto* property) {
315 * const Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentLength3);
316 * return thisObj->fContentLength_;
317 * },
318 * [qStroika_Foundation_Common_Property_ExtraCaptureStuff] ([[maybe_unused]]auto* property, auto contentLength) {
319 * Headers* thisObj = qStroika_Foundation_Common_Property_OuterObjPtr (property, &Headers::contentLength3);
320 * thisObj->fContentLength_ = contentLength;
321 * }}
322 * {
323 * }
324 * Headers::Headers (const Headers& src)
325 * : Headers{} // do default initialization of properties
326 * {
327 * // NOTE - cannot INITIALIZE properties with src.Properties values since they are not copy constructible
328 * // but they are assignable, so do that
329 * contentLength1 = src.contentLength1;
330 * contentLength2 = src.contentLength2;
331 * // COULD EITHER initialize fContentLength_ or contentLength1/contentLength2 - but no need to do both
332 * }
333 * Headers::Headers (Headers&& src)
334 * : Headers{} // do default initialization of properties
335 * {
336 * // NOTE - cannot MOVE properties with src.Properties values since they are not copy constructible
337 * // but they are assignable, so do that
338 * contentLength1 = src.contentLength1;
339 * contentLength2 = src.contentLength2;
340 * // COULD EITHER initialize fContentLength_ or contentLength1/contentLength2 - but no need to do both
341 * }
342 * Headers& Headers::operator= (Headers&& rhs)
343 * {
344 * // Could copy either properties or underlying field - no matter which
345 * fContentLength_ = rhs.fContentLength_;
346 * return *this;
347 * }
348 * //....
349 *
350 * Headers h;
351 * Assert (h.contentLength1 == 0);
352 * h.contentLength1 = 2;
353 * Assert (h.contentLength2 == 2);
354 * h.contentLength2 = 4;
355 * Assert (h.contentLength1 == 4);
356 * Headers h2 = h;
357 * Assert (h2.contentLength1 == 4);
358 * h.contentLength2 = 5;
359 * Assert (h.contentLength1 == 5);
360 * Assert (h2.contentLength1 == 4);
361 *
362 * \endcode
363 *
364 * Another important scenario, is where you have a complex, and want to update it. Properties only allow for
365 * getters and setters, not updaters. The simple solution to this is to have the Property return a REFERENCE to the
366 * object in question.
367 *
368 * \par Example Usage (EXTENDING the Header example above)
369 * \code
370 * // HTTP 'Response' object
371 * class Response {
372 * public:
373 * Response () = delete;
374 * Response (const Response&) = delete;
375 * Response (Response&& src);
376 * Response (const IO::Network::Socket::Ptr& s, const Streams::OutputStream::Ptr<byte>& outStream, const optional<InternetMediaType>& ct = nullopt);
377 * ~Response () = default;
378 * nonvirtual Response& operator= (const Response&) = delete;
379 * public:
380 * Common::ReadOnlyProperty<const IO::Network::HTTP::Headers&> headers;
381 * public:
382 * Common::Property<IO::Network::HTTP::Headers&> rwHeaders;
383 * ...
384 * // then the ABOVE checks/assignments become
385 * Response& r = get_from_somewhere();
386 * Assert (r.headers().contentLength1 == 0);
387 * r.rwHeaders().contentLength1 = 2;
388 * Assert (r.headers().contentLength2 == 2);
389 * h.contentLength2 = 4;
390 * Assert (r.headers().contentLength1 == 4);
391 * Headers h2 = r.headers;
392 * Assert (h2.contentLength1 == 4);
393 * r.rwHeaders().contentLength2 = 5;
394 * Assert (r.headers().contentLength1 == 5);
395 * Assert (h2.contentLength1 == 4);
396 * \endcode
397 *
398 * \note when using Properties, its often helpful to combine (for thread safety checking) with
399 * Debug::AssertExternallySynchronizedMutex and SetAssertExternallySynchronizedMutexContext ()
400 *
401 * \see See the example usage (above outlined) in Frameworks/WebServer/Request.h, Message.h, Response.h, and Foundation/IO/Network/HTTP/Headers
402 *
403 * \note \em Thread-Safety <a href="Thread-Safety.md">SAME AS T/GETTER/SETTER - all methods have exactly the thread safety of the underlying GETTER/SETTER</a>
404 */
405 template <typename T>
406 class Property : public ReadOnlyProperty<T>, public WriteOnlyProperty<remove_cvref_t<T>> {
407 public:
408 /**
409 * \brief base_value_type is T the type declared, and decayed_value_type is similar, but with the references etc removed (so can be set/stored)
410 */
412 using decayed_value_type = remove_cvref_t<T>;
413
414 public:
415 /**
416 * Properties are NOT movable, nor copy constructible: the data doesn't logically exist in the property itself,
417 * but in its relationship to some parent object; if it were copied, it might be copied TO some place that didn't
418 * have an appropriate enclosing object.
419 */
420 Property () = delete;
421 Property (const Property&) = delete;
422 Property (Property&&) = delete;
423 template <invocable<const ReadOnlyProperty<T>*> G, invocable<WriteOnlyProperty<remove_cvref_t<T>>*, remove_cvref_t<T>> S>
424 Property (G getter, S setter)
425 requires (convertible_to<invoke_result_t<G, const ReadOnlyProperty<T>*>, T>);
426
427 public:
428 /**
429 */
430 nonvirtual Property& operator= (ArgByValueType<decayed_value_type> value);
431 nonvirtual Property& operator= (const Property& value);
432 nonvirtual Property& operator= (const Property&&) = delete;
433
434 public:
435 template <typename TT>
436 nonvirtual bool operator== (const TT& rhs) const;
437
438 public:
439 using ReadOnlyProperty<T>::operator();
440 using ReadOnlyProperty<T>::Get;
441
442 public:
443 using WriteOnlyProperty<decayed_value_type>::Set;
444 using WriteOnlyProperty<decayed_value_type>::operator();
445 };
446
447 template <typename T>
448 using ConstantProperty [[deprecated ("Since Stroika v3.0d16 use Execution::LazyInitialized")]] = Execution::LazyInitialized<T>;
449
450 /**
451 * \brief ExtendableProperty is a Property which has callbacks associated with it, to be notified when it is accessed or updated
452 *
453 * These callbacks which you can attach to an ExtendableProperty effectively allow OVERRIDING the property
454 * because you can suppress update or handle it differently yourself.
455 *
456 * Use Cases:
457 * - HTTP Response
458 * - IO::Network::HTTP::Response base class
459 * - Frameworks::WebServer::Response subclass
460 * in Response::rwHeader() property, I want to (in subclass) ASSERT that state is in-progress (or some such)
461 *
462 * VIABLE APPROACHES:
463 * - Implement 'events' so when a property changes a hook gets called (possibly even before/after hooks, with before hooks
464 * possibly aborting change)
465 * - Provide some method for REPLACING the GETTER/SETTER hooks
466 * - Simply 'hide' the member in the subclass (so 2 properties with the same name)
467 *
468 * The third approach sucks cuz waste of space, and inconsistent behavior if you access property through ptr
469 * to base class.
470 *
471 * 'Events' approach nice in that it is more generally useful (listeners could be largely unrelated - external - like vtable methods
472 * vs 'function' ptr objects). But its COSTLY when not used (must maintain a list of callbacks, or worse two). Can mitigate cost
473 * as mentioned above, by only having subclass of Property (PropertyWithEvents) that supports events.
474 *
475 * REPLACING the GETTER/SETTER seems quite viable, except that it appears to really kill modularity. No way (I can think of) within
476 * c++ to capture any kind of public/private thing. Anybody would be replacing GETTERS or SETTERS (if anybody can) (cannot use
477 * protected cuz not subclassing, and forcing extra subclassing would be awkward).
478 *
479 * \note since properties and therefore ExtendableProperty cannot be copied, its natural to note that their 'event handlers' also
480 * are not generally copied.
481 *
482 * Though its up to any object which uses properties, its generally presumed and recommended that of you copy objects
483 * O1 (of type O, with ExtendableProperty P) to object O2, then the event handlers watching properties P (from O1)
484 * will NOT be copied to object O2 (to its property P).
485 *
486 * \note @todo - it we use a std::forward_list in the interest of being very cheap when not used (often), but this class is a PITA, if we need to
487 * control the order of additions (like append) - which is a PITA with forward_list. Consider alternatives.
488 *
489 */
490 template <typename T>
491 class ExtendableProperty : public Property<T> {
492 public:
493 using typename Property<T>::decayed_value_type;
494 using typename Property<T>::base_value_type;
495
496 public:
497 /**
498 */
499 ExtendableProperty () = delete;
500 ExtendableProperty (const ExtendableProperty&) = delete;
502 template <qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (invocable<const ExtendableProperty<T>*>) G,
503 qCompilerAndStdLib_RequiresNotMatchXXXDefined_1_BWA (invocable<ExtendableProperty<T>*, remove_cvref_t<T>>) S>
504 ExtendableProperty (G getter, S setter)
505 qCompilerAndStdLib_RequiresNotMatchXXXDefined_2_BWA (requires (convertible_to<invoke_result_t<G, const ExtendableProperty<T>*>, T>));
506
507 public:
508 /**
509 */
510 nonvirtual ExtendableProperty& operator= (ArgByValueType<T> value);
511 nonvirtual ExtendableProperty& operator= (const ExtendableProperty& value);
512 nonvirtual ExtendableProperty& operator= (const ExtendableProperty&&) = delete;
513
514 public:
515 /**
516 */
517 struct PropertyChangedEvent {
518 decayed_value_type fPreviousValue;
519 decayed_value_type fNewValue;
520 };
521
522 public:
523 /**
524 * if return result is false, this silently cuts-off processing. EventHandlers can also
525 * throw also can be used to prevent further processing, but then calling code will see that as an error.
526 * So event handler ordering matters.
527 * If any event propertyChangedHandlers present, they are handled in-order, with the underlying SETTER being the final 'eventhandler'
528 *
529 * TODO
530 * @todo be CAREFUL about copying these propertyChangedHandlers (what they reference) - maybe they should take parent obj ptr param*? or propery*?
531 *
532 * \note These handlers can get called even when no change has actually occurred (no compare != of new/Prev value) - in order to avoid
533 * building in a dependency in this code on using types that are comparable.
534 *
535 * This means you may find you need to do such comparisons yourself in callbacks before doing much to 'process' the change.
536 */
537 using PropertyChangedEventHandler = function<PropertyCommon::PropertyChangedEventResultType (const PropertyChangedEvent&)>;
538
539 public:
540 /**
541 * Note - that assigning/coping reference values and using them with optional works poorly, so when T is a reference type,
542 * the PropertyReadEventHandler just takes and returns a pointer to T instead to avoid this unpleasantness.
543 *
544 * #if 0
545 * This must return optional<base_value_type> because base_value_type is what is returned by the Get() function.
546 * But C++ doesn't allow optional<reference type>. So - for reference types, PropertyReadEventHandler returns a pointer.
547 *
548 * @todo - must copy constness of that pointer from constness of base_value_type (or address of it... so ignore for now)
549 * #endif
550 */
551 using PropertyReadEventHandlerArgAndReturnValue_ = conditional_t<is_reference_v<base_value_type>, decayed_value_type*, base_value_type>;
552
553 public:
554 /**
555 * this gets handed the original base value (stored), but then each handler gets a crack at overriding the
556 * value.
557 */
559
560 public:
561 /**
562 * Use forward_list instead of Sequence<> to avoid a dependency on Stroika containers in a potentially low level component
563 */
566
567 public:
568 /**
569 * Use forward_list instead of Sequence<> to avoid a dependency on Stroika containers in a potentially low level component
570 */
572 Property<forward_list<PropertyChangedEventHandler>&> rwPropertyChangedHandlers;
573
574 private:
575 forward_list<PropertyReadEventHandler> fPropertyReadHandlers_;
576 forward_list<PropertyChangedEventHandler> fPropertyChangedHandlers_;
577 };
578
579}
580
581/*
582 ********************************************************************************
583 ***************************** Implementation Details ***************************
584 ********************************************************************************
585 */
586#include "Property.inl"
587
588#endif /*_Stroika_Foundation_Common_Property_h_*/
ExtendableProperty is a Property which has callbacks associated with it, to be notified when it is ac...
Definition Property.h:491
conditional_t< is_reference_v< base_value_type >, decayed_value_type *, base_value_type > PropertyReadEventHandlerArgAndReturnValue_
Definition Property.h:551
function< PropertyCommon::PropertyChangedEventResultType(const PropertyChangedEvent &)> PropertyChangedEventHandler
Definition Property.h:537
function< PropertyReadEventHandlerArgAndReturnValue_(const PropertyReadEventHandlerArgAndReturnValue_ &)> PropertyReadEventHandler
Definition Property.h:558
ReadOnlyProperty< const std::forward_list< PropertyReadEventHandler > & > propertyReadHandlers
Definition Property.h:564
ReadOnlyProperty< const std::forward_list< PropertyChangedEventHandler > & > propertyChangedHandlers
Definition Property.h:571
T base_value_type
base_value_type is T the type declared, and decayed_value_type is similar, but with the references et...
Definition Property.h:411
nonvirtual const T operator()() const
Definition Property.inl:48
value-object, where the value construction is delayed until first needed (can be handy to avoid c++ i...
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32