Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Optional.h File Reference
#include "Stroika/Foundation/StroikaPreComp.h"
#include <mutex>
#include <optional>
#include <shared_mutex>
#include "Stroika/Foundation/Common/Common.h"
#include "Stroika/Foundation/Common/Compare.h"
#include "Stroika/Foundation/Common/Concepts.h"
#include "Stroika/Foundation/Common/Empty.h"
#include "Stroika/Foundation/Containers/Adapters/Adder.h"
#include "Stroika/Foundation/Debug/AssertExternallySynchronizedMutex.h"
#include "Stroika/Foundation/Execution/NullMutex.h"
#include "Stroika/Foundation/Memory/BlockAllocated.h"
#include "Stroika/Foundation/Memory/Common.h"
#include "Optional.inl"

Go to the source code of this file.

Namespaces

namespace  Stroika::Foundation
 

Functions

template<typename T , convertible_to< T > CONVERTIBLE_TO_T, convertible_to< function< T(T, T)> > OP = plus<T>>
void Stroika::Foundation::Memory::AccumulateIf (optional< T > *lhsOptionalValue, const optional< CONVERTIBLE_TO_T > &rhsOptionalValue, const OP &op=OP{})
 AccumulateIf () add in the rhs argument value to lhs optional, but if both were missing leave 'lhs' as still missing, and if only RHS available, assign it to the left.
 
template<typename T , typename CONVERTABLE_TO_TYPE >
void Stroika::Foundation::Memory::CopyToIf (CONVERTABLE_TO_TYPE *to, const optional< T > &copyFromIfHasValue)
 
template<Private_::INullCoalescable OT>
const OT & Stroika::Foundation::Memory::NullCoalesce (const OT &l, const OT &r)
 return one of l, or r, with first preference for which is engaged, and second preference for left-to-right.
 
template<typename T >
constexpr const T & Stroika::Foundation::Memory::ValueOf (const optional< T > &t)
 Same as *t, but Requires that 't' is engaged.
 
template<typename OUT_T , Common::explicitly_convertible_to< OUT_T > IN_T>
optional< OUT_T > Stroika::Foundation::Memory::OptionallyCopy (const optional< IN_T > &in)
 if you can copy an IN_T to an OUT_T, you should be able to copy an optional<IN_T> to an optional<OUT_T>
 
template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::And_Then (const optional< T > &o, F &&f)
 
template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::Or_Else (const optional< T > &o, F &&f)
 
template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::Transform (const optional< T > &o, F &&f)
 
template<typename RHS_CONVERTIBLE_TO_OPTIONAL_OF_T , constructible_from< RHS_CONVERTIBLE_TO_OPTIONAL_OF_T > T = RHS_CONVERTIBLE_TO_OPTIONAL_OF_T>
constexpr optional< T > Stroika::Foundation::Memory::OptionalFromNullable (const RHS_CONVERTIBLE_TO_OPTIONAL_OF_T *from)
 
template<typename T >
optional< T > Stroika::Foundation::Memory::operator+ (const optional< T > &lhs, const optional< T > &rhs)
 
template<typename T >
optional< T > Stroika::Foundation::Memory::operator- (const optional< T > &lhs, const optional< T > &rhs)
 
template<typename T >
optional< T > Stroika::Foundation::Memory::operator* (const optional< T > &lhs, const optional< T > &rhs)
 
template<typename T >
optional< T > Stroika::Foundation::Memory::operator/ (const optional< T > &lhs, const optional< T > &rhs)
 

Detailed Description

Note
Code-Status: Beta

TODO:

NOTE TO SUGGEST TO C++ standards - 
    Things I miss most about my Optional versus std::optional
        >   Value () - what they call value_or - should take T{} as default argument. About 25% of teh time
            that's what I want, and its much more clear/terse.

        >   Accumulate method, and operator +=, operator-= etc overloads calling Accumulate(). Much simpler
            and more elegant code with those methods.

Definition in file Optional.h.

Function Documentation

◆ AccumulateIf()

template<typename T , convertible_to< T > CONVERTIBLE_TO_T, convertible_to< function< T(T, T)> > OP = plus<T>>
void Stroika::Foundation::Memory::AccumulateIf ( optional< T > *  lhsOptionalValue,
const optional< CONVERTIBLE_TO_T > &  rhsOptionalValue,
const OP &  op = OP{} 
)

AccumulateIf () add in the rhs argument value to lhs optional, but if both were missing leave 'lhs' as still missing, and if only RHS available, assign it to the left.

Example Usage
optional<int> accumulator;
optional<int> SomeFunctionToGetOptionalValue();
if (accumulator or (tmp = SomeFunctionToGetOptionalValue())) {
accumulator = accumulator.Value () + tmp;
}
VERSUS
AccumulateIf (&accumulator, SomeFunctionToGetOptionalValue ());
Example Usage
optional<Sequence<InternetAddress>>> addresses;
Memory::AccumulateIf (&addresses, IO::Network::InternetAddress{connection.GET ().GetDataTextInputStream ().ReadAll ().Trim ()});

Notes:

Precondition
lhsOptionalValue != nullptr (for optional* first argument)
Note
Overloads that take optional* first argument accumulate in place and return nothing, while overloads taking optional<T> as the first augment return the computed result. overloads taking optional<CONTAINER> or optional<CONTAINER>* dont take an op as argument, but assume the operation is 'Add' to the container
ITS CONFUSING direction of if-test for this versus CopyToIf
typical OP arguments would be: std::plus{} the default std::minus{} std::multiplies{} std::divides{}

Definition at line 28 of file Optional.inl.

◆ CopyToIf()

template<typename T , typename CONVERTABLE_TO_TYPE >
void Stroika::Foundation::Memory::CopyToIf ( CONVERTABLE_TO_TYPE *  to,
const optional< T > &  copyFromIfHasValue 
)

Assign (overwriting) the value held by this optional (first argument) if one is present with destination (second) argument if engaged. Assigns from right to left.

The point of this to to facilitate a common idiom, where you want to maintain an existing value unless you get an update. This function is ANALAGOUS to if (o.has_value()) { destArgVal = *o; }

but can be done in a single line.

Example Usage
int curValue = 3;
Memory::CopyToIf (&curValue, someMap.Lookup (KEY_VALUE)); // curValue will be 3, or overwritten by whatever value MAY have been in someMap
Example Usage
optional<int> curValue = getSomeValue ();
optional<long> oVal = someMap.Lookup (KEY_VALUE);
Memory::CopyToIf (&curValue, oVal); // curValue retains its value from before CopyToIf if oVal was missing
See also
Value

Definition at line 110 of file Optional.inl.

◆ NullCoalesce()

template<Private_::INullCoalescable OT>
const OT & Stroika::Foundation::Memory::NullCoalesce ( const OT &  l,
const OT &  r 
)

return one of l, or r, with first preference for which is engaged, and second preference for left-to-right.

So Equivalent to (depending on overload) static_cast<bool> (l)? l : r; or static_cast<bool> (l)? *l : r;

This is similar to/inspired by C# ?? operator (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator)

Note
This is handy because there is no default argument for std::optional<>::value_or () - there should be (like this).
a bit like value_or, but RHS arg can be optional or T, and depending returns optional or T and this takes default value
See also
Value ()
Example Usage
optional<uint64_t> workingOrResidentSetSize = NullCoalesce (thisProcess.fWorkingSetSize, thisProcess.fResidentMemorySize);
uint64_t useMemUsageSz = NullCoalesce (workingOrResidentSetSize, 1024);
uint64_t useMemUsageSz2 = NullCoalesce (workingOrResidentSetSize);
Note
NullCoalesce overloads returns a const T& internal pointer: that means the caller MAY need to be careful to finish using the result of the function before the end of the full expression calling NullCoalesce ().

Definition at line 134 of file Optional.inl.

◆ ValueOf()

template<typename T >
constexpr const T & Stroika::Foundation::Memory::ValueOf ( const optional< T > &  t)
constexpr

Same as *t, but Requires that 't' is engaged.

Note
operator* for optional returns a const T& internal pointer, and so does this. That means the caller MAY need to be careful to finish using the result of the function before the end of the full expression calling ValueOf (). But again, this is the same as if they used *v, which is the obvious alternative.

Definition at line 156 of file Optional.inl.

◆ OptionallyCopy()

template<typename OUT_T , Common::explicitly_convertible_to< OUT_T > IN_T>
optional< OUT_T > Stroika::Foundation::Memory::OptionallyCopy ( const optional< IN_T > &  in)

if you can copy an IN_T to an OUT_T, you should be able to copy an optional<IN_T> to an optional<OUT_T>

Actually, sometimes you can. But due to C++ one-step conversion operator rule, some cases where you would want this to work it doesn't. More likely though, you need to specify some other lambda todo the conversion of T like below:

Example Usage
optional<URI> ShowAsExternalURL;
optional<String> s = OptionallyCopy<String>(ShowAsExternalURL,[](URI u) {return u.As<String>();})

Definition at line 180 of file Optional.inl.

◆ And_Then()

template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::And_Then ( const optional< T > &  o,
F &&  f 
)
constexpr

wrappers on std c++23 monadic optional support, til we can assume c++23

Definition at line 207 of file Optional.h.

◆ Or_Else()

template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::Or_Else ( const optional< T > &  o,
F &&  f 
)
constexpr

wrappers on std c++23 monadic optional support, til we can assume c++23

Definition at line 224 of file Optional.h.

◆ Transform()

template<typename T , class F >
constexpr auto Stroika::Foundation::Memory::Transform ( const optional< T > &  o,
F &&  f 
)
constexpr

wrappers on std c++23 monadic optional support, til we can assume c++23

Definition at line 241 of file Optional.h.

◆ OptionalFromNullable()

template<typename RHS_CONVERTIBLE_TO_OPTIONAL_OF_T , constructible_from< RHS_CONVERTIBLE_TO_OPTIONAL_OF_T > T = RHS_CONVERTIBLE_TO_OPTIONAL_OF_T>
constexpr optional< T > Stroika::Foundation::Memory::OptionalFromNullable ( const RHS_CONVERTIBLE_TO_OPTIONAL_OF_T *  from)
constexpr

'Constructor' taking const RHS_CONVERTIBLE_TO_OPTIONAL_OF_T* is to allow easier interoperability with code that uses null-pointers to mean 'is-missing': nullptr means missing, and if non null, dereference and copy.

Example Usage
float* d1 = nullptr;
double* d2 = nullptr;
EXPECT_TRUE (not OptionalFromNullable (d1).has_value ());
EXPECT_TRUE (not OptionalFromNullable (d2).has_value ());

Definition at line 17 of file Optional.inl.

◆ operator+()

template<typename T >
optional< T > Stroika::Foundation::Memory::operator+ ( const optional< T > &  lhs,
const optional< T > &  rhs 
)

if lhs and rhs engaged, this returns *lhs + *rhs, and otherwise nullopt

Note
this used to use AccumulateIf() before Stroika 2.1b12, but that produced confusing results. This is slightly safer, I think, and if you want the AccumulateIf () semantics, call AccumulateIf()

Definition at line 203 of file Optional.inl.

◆ operator-()

template<typename T >
optional< T > Stroika::Foundation::Memory::operator- ( const optional< T > &  lhs,
const optional< T > &  rhs 
)

if lhs and rhs engaged, this returns *lhs - *rhs, and otherwise nullopt

Note
this used to use AccumulateIf() before Stroika 2.1b12, but that produced confusing results. This is slightly safer, I think, and if you want the AccumulateIf () semantics, call AccumulateIf()

Definition at line 233 of file Optional.inl.

◆ operator*()

template<typename T >
optional< T > Stroika::Foundation::Memory::operator* ( const optional< T > &  lhs,
const optional< T > &  rhs 
)

if lhs and rhs engaged, this returns *lhs * *rhs, and otherwise nullopt

Note
this used to use AccumulateIf() before Stroika 2.1b12, but that produced confusing results. This is slightly safer, I think, and if you want the AccumulateIf () semantics, call AccumulateIf()

Definition at line 263 of file Optional.inl.

◆ operator/()

template<typename T >
optional< T > Stroika::Foundation::Memory::operator/ ( const optional< T > &  lhs,
const optional< T > &  rhs 
)

if lhs and rhs engaged, this returns *lhs / *rhs, and otherwise nullopt

Note
this used to use AccumulateIf() before Stroika 2.1b12, but that produced confusing results. This is slightly safer, I think, and if you want the AccumulateIf () semantics, call AccumulateIf()

Definition at line 293 of file Optional.inl.