Skip to content

Commit 6ac59d2

Browse files
committed
Add the OptionalReference class
1 parent 4dfbe89 commit 6ac59d2

7 files changed

Lines changed: 249 additions & 2 deletions

File tree

docs/web/release-notes-3.2.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ For more details, see <https://github.com/thelfer/MFrontGenericInterfaceSupport/
201201

202202
For more details, see <https://github.com/thelfer/MFrontGenericInterfaceSupport/issues/196>
203203

204+
## Issue 158: Model implicite for LICOS software
205+
206+
For more details, see <https://github.com/thelfer/MFrontGenericInterfaceSupport/issues/158>
207+
204208
# Acknowledgements
205209

206210
The authors are grateful to the many contributors to the `TFEL/MFront`

include/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mgis_header(MGIS ThreadPool.ixx)
1717
mgis_header(MGIS ThreadedTaskResult.hxx)
1818
mgis_header(MGIS ThreadedTaskResult.ixx)
1919
mgis_header(MGIS/Utilities Markdown.hxx)
20+
mgis_header(MGIS/Utilities OptionalReference.hxx)
2021
mgis_header(MGIS LibrariesManager.hxx)
2122
mgis_header(MGIS/MaterialProperty OutputStatus.hxx)
2223
mgis_header(MGIS/MaterialProperty OutOfBoundsPolicy.hxx)
@@ -45,7 +46,6 @@ mgis_header(MGIS/Behaviour BehaviourIntegrationFailureAnalyser.hxx)
4546
mgis_header(MGIS/Behaviour FiniteStrainSupport.hxx)
4647
mgis_header(MGIS/Model Model.hxx)
4748

48-
4949
if(MGIS_HAVE_TFEL)
5050
mgis_header(MGIS Database.hxx)
5151
endif(MGIS_HAVE_TFEL)

include/MGIS/AbstractErrorHandler.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "MGIS/Config.hxx"
1212
#include "MGIS/InvalidResult.hxx"
13+
#include "MGIS/Utilities/OptionalReference.hxx"
1314

1415
// source_location seems badly supported by the current compilers (2022):
1516
// - with some compilers, this header is missing

include/MGIS/Contract.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "MGIS/Config.hxx"
1313
#include "MGIS/InvalidResult.hxx"
1414
#include "MGIS/AbstractErrorHandler.hxx"
15+
#include "MGIS/Utilities/OptionalReference.hxx"
1516

1617
namespace mgis {
1718

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*!
2+
* \file MFEMMGIS/Utilities/OptionalReference.hxx
3+
* \brief This header declares the OptionalReference class
4+
* \author Thomas Helfer
5+
* \date 19/02/2026
6+
*/
7+
8+
#ifndef LIB_MGIS_UTILITIES_OPTIONALREFERENCE_HXX
9+
#define LIB_MGIS_UTILITIES_OPTIONALREFERENCE_HXX
10+
11+
#include <memory>
12+
#include <cstddef>
13+
#include <utility>
14+
#include <cassert>
15+
#include <type_traits>
16+
#include "MGIS/Config.hxx"
17+
#include "MGIS/InvalidResult.hxx"
18+
19+
namespace mgis {
20+
21+
/*!
22+
* \brief a class that may contain a reference to a class
23+
*
24+
* \note this class was introduced by of the lack of optional
25+
* references befor to C++-26.
26+
* \note the design of the class is loosely modeled by the
27+
* std::experimental::observer_ptr proposal
28+
*/
29+
template <typename ValueType>
30+
struct [[nodiscard]] OptionalReference {
31+
//
32+
using element_type = ValueType;
33+
using pointer = ValueType*;
34+
using reference = ValueType&;
35+
//
36+
constexpr OptionalReference() noexcept : ptr(nullptr) {}
37+
38+
constexpr OptionalReference(std::nullptr_t) noexcept : ptr(nullptr) {}
39+
40+
constexpr OptionalReference(pointer p) noexcept : ptr(p) {}
41+
42+
template <typename ValueType2>
43+
requires(std::is_convertible<ValueType2*, ValueType*>::value) //
44+
constexpr OptionalReference(
45+
OptionalReference<ValueType2> other) noexcept
46+
: ptr(other.get()) {}
47+
48+
template <typename ValueType2>
49+
requires(std::is_convertible<ValueType2*, ValueType*>::value) //
50+
constexpr OptionalReference(
51+
std::unique_ptr<ValueType2> const& other) noexcept
52+
: ptr(other.get()) {}
53+
54+
template <typename ValueType2>
55+
requires(std::is_convertible<ValueType2*, ValueType*>::value) //
56+
constexpr OptionalReference(
57+
std::shared_ptr<ValueType2> const& other) noexcept
58+
: ptr(other.get()) {}
59+
60+
[[nodiscard]] constexpr pointer get() const noexcept { return this->ptr; }
61+
62+
[[nodiscard]] constexpr reference operator*() const {
63+
assert(ptr != nullptr);
64+
return *ptr;
65+
}
66+
67+
constexpr pointer operator->() const noexcept { return this->ptr; }
68+
69+
[[nodiscard]] constexpr operator bool() const noexcept {
70+
return this->ptr != nullptr;
71+
}
72+
73+
constexpr operator pointer() const noexcept { return this->ptr; }
74+
75+
constexpr pointer release() noexcept {
76+
pointer p(ptr);
77+
this->reset();
78+
return p;
79+
}
80+
81+
constexpr void reset(pointer p = nullptr) noexcept { this->ptr = p; }
82+
83+
constexpr void swap(OptionalReference& other) noexcept {
84+
std::swap(ptr, other.ptr);
85+
}
86+
87+
private:
88+
pointer ptr;
89+
};
90+
91+
template <typename ValueType>
92+
void swap(OptionalReference<ValueType>& p1,
93+
OptionalReference<ValueType>& p2) noexcept {
94+
p1.swap(p2);
95+
}
96+
97+
template <typename ValueType>
98+
[[nodiscard]] constexpr OptionalReference<ValueType> make_optional_reference(
99+
ValueType& p) noexcept {
100+
return OptionalReference<ValueType>(&p);
101+
}
102+
103+
template <typename ValueType>
104+
[[nodiscard]] constexpr OptionalReference<ValueType> make_optional_reference(
105+
ValueType* p) noexcept {
106+
return OptionalReference<ValueType>(p);
107+
}
108+
109+
template <typename ValueType1, typename ValueType2>
110+
[[nodiscard]] constexpr bool operator==(OptionalReference<ValueType1> p1,
111+
OptionalReference<ValueType2> p2) {
112+
return p1.get() == p2.get();
113+
}
114+
115+
template <typename ValueType1, typename ValueType2>
116+
[[nodiscard]] constexpr bool operator!=(OptionalReference<ValueType1> p1,
117+
OptionalReference<ValueType2> p2) {
118+
return !(p1 == p2);
119+
}
120+
121+
template <typename ValueType>
122+
[[nodiscard]] constexpr bool operator==(OptionalReference<ValueType> p,
123+
std::nullptr_t) noexcept {
124+
return !p;
125+
}
126+
127+
template <typename ValueType>
128+
[[nodiscard]] constexpr bool operator==(
129+
std::nullptr_t, OptionalReference<ValueType> p) noexcept {
130+
return !p;
131+
}
132+
133+
template <typename ValueType>
134+
[[nodiscard]] constexpr bool operator!=(OptionalReference<ValueType> p,
135+
std::nullptr_t) noexcept {
136+
return static_cast<bool>(p);
137+
}
138+
139+
template <typename ValueType>
140+
[[nodiscard]] constexpr bool operator!=(
141+
std::nullptr_t, OptionalReference<ValueType> p) noexcept {
142+
return static_cast<bool>(p);
143+
}
144+
145+
template <typename ValueType>
146+
[[nodiscard]] constexpr bool isInvalid(
147+
const OptionalReference<ValueType>& p) noexcept {
148+
return p == nullptr;
149+
} // end of isInvalid
150+
151+
} // end of namespace mgis
152+
153+
namespace std {
154+
155+
template <typename ValueType>
156+
struct hash<::mgis::OptionalReference<ValueType>> {
157+
[[nodiscard]] size_t operator()(
158+
::mgis::OptionalReference<ValueType> p) const noexcept {
159+
return hash<ValueType*>()(p.get());
160+
}
161+
};
162+
163+
} // namespace std
164+
165+
namespace mgis::internal {
166+
167+
//! \brief partial specialisation for optional references
168+
template <typename ValueType>
169+
struct InvalidValueTraits<mgis::OptionalReference<ValueType>> {
170+
static constexpr bool isSpecialized = true;
171+
static mgis::OptionalReference<ValueType> getValue() noexcept {
172+
return {};
173+
}
174+
};
175+
176+
} // end of namespace mgis::internal
177+
178+
#endif /* LIB_MGIS_UTILITIES_OPTIONALREFERENCE_HXX */

tests/CMakeLists.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ mfront_behaviours_check_library(BehaviourTest
3030
mfront_behaviours_check_library(ModelTest
3131
ode_rk54)
3232

33-
#
3433

34+
#
3535
add_executable(IntegrationFailureDebugTest
3636
EXCLUDE_FROM_ALL
3737
IntegrationFailureDebugTest.cxx)
@@ -461,6 +461,19 @@ if(enable-mgis-function)
461461

462462
if(MGIS_HAVE_TFEL)
463463

464+
add_executable(OptionalReferenceTest
465+
EXCLUDE_FROM_ALL
466+
OptionalReferenceTest.cxx)
467+
target_link_libraries(OptionalReferenceTest
468+
PRIVATE MFrontGenericInterface tfel::TFELTests)
469+
add_test(NAME OptionalReferenceTest
470+
COMMAND OptionalReferenceTest "$<TARGET_FILE:BehaviourTest>")
471+
add_dependencies(check OptionalReferenceTest)
472+
if((CMAKE_HOST_WIN32) AND (NOT MSYS))
473+
set_property(TEST OptionalReferenceTest
474+
PROPERTY ENVIRONMENT "PATH=$<TARGET_FILE_DIR:MFrontGenericInterface>\;${MGIS_PATH_STRING}")
475+
endif((CMAKE_HOST_WIN32) AND (NOT MSYS))
476+
464477
add_executable(SharedSpaceTest
465478
EXCLUDE_FROM_ALL
466479
SharedSpaceTest.cxx)

tests/OptionalReferenceTest.cxx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*!
2+
* \file tests/OptionalReferenceTest.cxx
3+
* \brief This file contains unit test of the `OptionalReference` class
4+
* \author Thomas Helfer
5+
* \date 20/02/2026
6+
*/
7+
8+
#ifdef NDEBUG
9+
#undef NDEBUG
10+
#endif
11+
12+
#include <cmath>
13+
#include <memory>
14+
#include <cstdlib>
15+
#include <iostream>
16+
#include "TFEL/Tests/TestCase.hxx"
17+
#include "TFEL/Tests/TestProxy.hxx"
18+
#include "TFEL/Tests/TestManager.hxx"
19+
#include "MGIS/Utilities/OptionalReference.hxx"
20+
21+
struct OptionalReferenceTest final : public tfel::tests::TestCase {
22+
OptionalReferenceTest()
23+
: tfel::tests::TestCase("MGIS/Utilities", "OptionalReferenceTests") {
24+
} // end of OptionalReferenceTest
25+
tfel::tests::TestResult execute() override {
26+
this->test1();
27+
return this->result;
28+
}
29+
30+
private:
31+
void test1() {
32+
using namespace mgis;
33+
auto p = OptionalReference<int>{};
34+
TFEL_TESTS_CHECK_EQUAL(p, nullptr);
35+
TFEL_TESTS_CHECK_EQUAL(p.get(), nullptr);
36+
int a;
37+
p = OptionalReference<int>{&a};
38+
TFEL_TESTS_CHECK_EQUAL(p.get(), &a);
39+
} // end of test1
40+
};
41+
42+
TFEL_TESTS_GENERATE_PROXY(OptionalReferenceTest, "OptionalReferenceTest");
43+
44+
/* coverity [UNCAUGHT_EXCEPT]*/
45+
int main() {
46+
auto& m = tfel::tests::TestManager::getTestManager();
47+
m.addTestOutput(std::cout);
48+
m.addXMLTestOutput("OptionalReferenceTest.xml");
49+
return m.execute().success() ? EXIT_SUCCESS : EXIT_FAILURE;
50+
}

0 commit comments

Comments
 (0)