1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one |
3 | * or more contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. The ASF licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | |
20 | /*! |
21 | * \file tvm/runtime/container/optional.h |
22 | * \brief Runtime Optional container types. |
23 | */ |
24 | #ifndef TVM_RUNTIME_CONTAINER_OPTIONAL_H_ |
25 | #define TVM_RUNTIME_CONTAINER_OPTIONAL_H_ |
26 | |
27 | #include <utility> |
28 | |
29 | #include "./base.h" |
30 | |
31 | namespace tvm { |
32 | namespace runtime { |
33 | |
34 | /*! \brief Helper to represent nullptr for optional. */ |
35 | struct NullOptType {}; |
36 | |
37 | /*! |
38 | * \brief Optional container that to represent to a Nullable variant of T. |
39 | * \tparam T The original ObjectRef. |
40 | * |
41 | * \code |
42 | * |
43 | * Optional<String> opt0 = nullptr; |
44 | * Optional<String> opt1 = String("xyz"); |
45 | * ICHECK(opt0 == nullptr); |
46 | * ICHECK(opt1 == "xyz"); |
47 | * |
48 | * \endcode |
49 | */ |
50 | template <typename T> |
51 | class Optional : public ObjectRef { |
52 | public: |
53 | using ContainerType = typename T::ContainerType; |
54 | static_assert(std::is_base_of<ObjectRef, T>::value, "Optional is only defined for ObjectRef." ); |
55 | // default constructors. |
56 | Optional() = default; |
57 | Optional(const Optional<T>&) = default; |
58 | Optional(Optional<T>&&) = default; |
59 | Optional<T>& operator=(const Optional<T>&) = default; |
60 | Optional<T>& operator=(Optional<T>&&) = default; |
61 | /*! |
62 | * \brief Construct from an ObjectPtr |
63 | * whose type already matches the ContainerType. |
64 | * \param ptr |
65 | */ |
66 | explicit Optional(ObjectPtr<Object> ptr) : ObjectRef(ptr) {} |
67 | /*! \brief Nullopt handling */ |
68 | Optional(NullOptType) {} // NOLINT(*) |
69 | // nullptr handling. |
70 | // disallow implicit conversion as 0 can be implicitly converted to nullptr_t |
71 | explicit Optional(std::nullptr_t) {} |
72 | Optional<T>& operator=(std::nullptr_t) { |
73 | data_ = nullptr; |
74 | return *this; |
75 | } |
76 | // normal value handling. |
77 | Optional(T other) // NOLINT(*) |
78 | : ObjectRef(std::move(other)) {} |
79 | Optional<T>& operator=(T other) { |
80 | ObjectRef::operator=(std::move(other)); |
81 | return *this; |
82 | } |
83 | // delete the int constructor |
84 | // since Optional<Integer>(0) is ambiguious |
85 | // 0 can be implicitly casted to nullptr_t |
86 | explicit Optional(int val) = delete; |
87 | Optional<T>& operator=(int val) = delete; |
88 | /*! |
89 | * \return A not-null container value in the optional. |
90 | * \note This function performs not-null checking. |
91 | */ |
92 | T value() const { |
93 | ICHECK(data_ != nullptr); |
94 | return T(data_); |
95 | } |
96 | /*! |
97 | * \return The internal object pointer with container type of T. |
98 | * \note This function do not perform not-null checking. |
99 | */ |
100 | const ContainerType* get() const { return static_cast<ContainerType*>(data_.get()); } |
101 | /*! |
102 | * \return The contained value if the Optional is not null |
103 | * otherwise return the default_value. |
104 | */ |
105 | T value_or(T default_value) const { return data_ != nullptr ? T(data_) : default_value; } |
106 | |
107 | /*! \return Whether the container is not nullptr.*/ |
108 | explicit operator bool() const { return *this != nullptr; } |
109 | // operator overloadings |
110 | bool operator==(std::nullptr_t) const { return data_ == nullptr; } |
111 | bool operator!=(std::nullptr_t) const { return data_ != nullptr; } |
112 | auto operator==(const Optional<T>& other) const { |
113 | // support case where sub-class returns a symbolic ref type. |
114 | using RetType = decltype(value() == other.value()); |
115 | if (same_as(other)) return RetType(true); |
116 | if (*this != nullptr && other != nullptr) { |
117 | return value() == other.value(); |
118 | } else { |
119 | // one of them is nullptr. |
120 | return RetType(false); |
121 | } |
122 | } |
123 | auto operator!=(const Optional<T>& other) const { |
124 | // support case where sub-class returns a symbolic ref type. |
125 | using RetType = decltype(value() != other.value()); |
126 | if (same_as(other)) return RetType(false); |
127 | if (*this != nullptr && other != nullptr) { |
128 | return value() != other.value(); |
129 | } else { |
130 | // one of them is nullptr. |
131 | return RetType(true); |
132 | } |
133 | } |
134 | auto operator==(const T& other) const { |
135 | using RetType = decltype(value() == other); |
136 | if (same_as(other)) return RetType(true); |
137 | if (*this != nullptr) return value() == other; |
138 | return RetType(false); |
139 | } |
140 | auto operator!=(const T& other) const { return !(*this == other); } |
141 | template <typename U> |
142 | auto operator==(const U& other) const { |
143 | using RetType = decltype(value() == other); |
144 | if (*this == nullptr) return RetType(false); |
145 | return value() == other; |
146 | } |
147 | template <typename U> |
148 | auto operator!=(const U& other) const { |
149 | using RetType = decltype(value() != other); |
150 | if (*this == nullptr) return RetType(true); |
151 | return value() != other; |
152 | } |
153 | static constexpr bool _type_is_nullable = true; |
154 | }; |
155 | |
156 | } // namespace runtime |
157 | |
158 | // expose the functions to the root namespace. |
159 | using runtime::Optional; |
160 | constexpr runtime::NullOptType NullOpt{}; |
161 | } // namespace tvm |
162 | |
163 | #endif // TVM_RUNTIME_CONTAINER_OPTIONAL_H_ |
164 | |