1/*******************************************************************************
2* Copyright 2021 Intel Corporation
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*******************************************************************************/
16
17#ifndef COMMON_OPTIONAL_HPP
18#define COMMON_OPTIONAL_HPP
19
20#include <cassert>
21#include <memory>
22#include <new>
23#include <type_traits>
24
25namespace dnnl {
26namespace impl {
27namespace utils {
28
29// This is a simple version of the std::optional class
30// When C++17 will be supported it is highly recommended
31// to remove this class and start using std::optional instead.
32
33struct nullopt_t {
34 nullopt_t() = default;
35};
36static constexpr nullopt_t nullopt {};
37
38template <typename T>
39class optional_t;
40
41template <typename T>
42struct is_optional_t : public std::false_type {};
43template <typename T>
44struct is_optional_t<optional_t<T>> : public std::true_type {};
45
46template <class T>
47class optional_t {
48public:
49 static_assert(!std::is_lvalue_reference<T>::value, "");
50 static_assert(!std::is_rvalue_reference<T>::value, "");
51 static_assert(!std::is_const<T>::value, "");
52 static_assert(!std::is_volatile<T>::value, "");
53 static_assert(!is_optional_t<T>::value, "");
54
55 optional_t(const nullopt_t nullopt) : has_value_(false), dummy {} {}
56 optional_t(T object) : has_value_(true), value_(object) {}
57 optional_t(const optional_t &other)
58 : has_value_(other.has_value_), dummy {} {
59 if (has_value_) new (std::addressof(value_)) T(other.value_);
60 }
61 optional_t(optional_t<T> &&other) noexcept
62 : has_value_(other.has_value_), dummy {} {
63 if (has_value_) new (std::addressof(value_)) T(std::move(other.value_));
64 }
65 ~optional_t() {
66 if (has_value_) value_.~T();
67 }
68
69 optional_t &operator=(const nullopt_t nullopt) {
70 if (has_value_) value_.~T();
71 has_value_ = false;
72 }
73 optional_t &operator=(const optional_t &other) {
74 if (this == &other) return *this;
75 if (has_value_) value_.~T();
76 has_value_ = other.has_value_;
77 if (has_value_) value_ = other.value_;
78 return *this;
79 }
80 optional_t &operator=(optional_t &&other) {
81 if (this == &other) return *this;
82 if (has_value_) value_.~T();
83 has_value_ = other.has_value_;
84 if (has_value_) value_ = std::move(other.value_);
85 return *this;
86 }
87
88 const T *operator->() const {
89 assert(has_value_);
90 return &value_;
91 }
92 T *operator->() {
93 assert(has_value_);
94 return &value_;
95 }
96 const T &operator*() const {
97 assert(has_value_);
98 return value_;
99 }
100 T &operator*() {
101 assert(has_value_);
102 return value_;
103 }
104 operator bool() const { return has_value_; }
105
106 T value_or(T &&returned_value) {
107 return has_value_ ? value_ : returned_value;
108 }
109 T value_or(T &&returned_value) const {
110 return has_value_ ? value_ : returned_value;
111 }
112 const T &value() const {
113 assert(has_value_);
114 return value_;
115 }
116 T &value() {
117 assert(has_value_);
118 return value_;
119 }
120 bool has_value() const { return has_value_; }
121 void reset() {
122 if (has_value_) value_.~T();
123 has_value_ = false;
124 }
125
126private:
127 bool has_value_;
128
129 union {
130 char dummy;
131 T value_;
132 };
133};
134
135} // namespace utils
136} // namespace impl
137} // namespace dnnl
138
139#endif
140