summaryrefslogtreecommitdiffstats
path: root/src/lib/util/optional.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/optional.h')
-rw-r--r--src/lib/util/optional.h201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/lib/util/optional.h b/src/lib/util/optional.h
new file mode 100644
index 0000000..16d5dc0
--- /dev/null
+++ b/src/lib/util/optional.h
@@ -0,0 +1,201 @@
+// Copyright (C) 2014-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef OPTIONAL_H
+#define OPTIONAL_H
+
+#include <exceptions/exceptions.h>
+#include <ostream>
+#include <string>
+
+namespace isc {
+namespace util {
+
+/// @brief A template representing an optional value.
+///
+/// This template class encapsulates an optional value. The default implementation
+/// encapsulates numeric values, but additional specializations are defined
+/// as necessary to support other types od data.
+///
+/// This class includes a boolean flag which indicates if the encapsulated
+/// value is specified or unspecified. For example, a configuration parser
+/// for the DHCP server may use this class to represent a value of the
+/// configuration parameter which may appear in the configuration file, but
+/// is not mandatory. The value of the @c Optional may be initialized to
+/// "unspecified" initially. When the configuration parser finds that the
+/// particular parameter exists in the configuration file, the default value
+/// can be overridden and the value may be marked as "specified". If the
+/// parameter is not found, the value remains "unspecified" and the appropriate
+/// actions may be taken, e.g. the default value may be used.
+///
+/// @tparam Type of the encapsulated value.
+template<typename T>
+class Optional {
+public:
+
+ /// @brief Type of the encapsulated value.
+ typedef T ValueType;
+
+ /// @brief Assigns a new value value and marks it "specified".
+ ///
+ /// @tparam A Type of the value to be assigned. Typically this is @c T, but
+ /// may also be a type that can be cast to @c T.
+ /// @param other new actual value.
+ template<typename A>
+ Optional<T>& operator=(A other) {
+ default_ = other;
+ unspecified_ = false;
+ return (*this);
+ }
+
+ /// @brief Type cast operator.
+ ///
+ /// This operator converts the optional value to the actual value being
+ /// encapsulated.
+ ///
+ /// @return Encapsulated value.
+ operator T() const {
+ return (default_);
+ }
+
+ /// @brief Equality operator.
+ ///
+ /// @param other value to be compared.
+ bool operator==(const T& other) const {
+ return (default_ == other);
+ }
+
+ /// @brief Inequality operator.
+ ///
+ /// @param other value to be compared.
+ bool operator!=(const T& other) const {
+ return (default_ != other);
+ }
+
+ /// @brief Default constructor.
+ ///
+ /// Sets the encapsulated value to 0 and marks it as "unspecified".
+ ///
+ /// The caller must ensure that the constructor of the class @c T
+ /// creates a valid object when invoked with 0 as an argument.
+ /// For example, a @c std::string(0) compiles but will crash at
+ /// runtime as 0 is not a valid pointer for the
+ /// @c std::string(const char*) constructor. Therefore, the
+ /// specialization of the @c Optional template for @c std::string
+ /// is provided below. It uses @c std::string default constructor.
+ ///
+ /// For any other type used with this template which doesn't come
+ /// with an appropriate constructor, the caller must create a
+ /// template specialization similar to the one provided for
+ /// @c std::string below.
+ Optional()
+ : default_(T(0)), unspecified_(true) {
+ }
+
+ /// @brief Constructor
+ ///
+ /// Sets an explicit value and marks it as "specified".
+ ///
+ /// @tparam A Type of the value to be assigned. Typically this is @c T, but
+ /// may also be a type that can be cast to @c T.
+ /// @param value value to be assigned.
+ /// @param unspecified initial state. Default is "unspecified".
+ template<typename A>
+ Optional(A value, const bool unspecified = false)
+ : default_(value), unspecified_(unspecified) {
+ }
+
+ /// @brief Retrieves the encapsulated value.
+ ///
+ /// @return the encapsulated value
+ T get() const {
+ return (default_);
+ }
+
+ /// @brief Retrieves the encapsulated value if specified, or the given value
+ /// otherwise.
+ ///
+ /// @param or_value the value it defaults to, if unspecified
+ ///
+ /// @return the encapsulated value or the default value
+ T valueOr(T const& or_value) const {
+ if (unspecified_) {
+ return or_value;
+ }
+ return default_;
+ }
+
+ /// @brief Modifies the flag that indicates whether the value is specified
+ /// or unspecified.
+ ///
+ /// @param unspecified new value of the flag. If it is @c true, the
+ /// value is marked as unspecified, otherwise it is marked as specified.
+ void unspecified(bool unspecified) {
+ unspecified_ = unspecified;
+ }
+
+ /// @brief Checks if the value has been specified or unspecified.
+ ///
+ /// @return true if the value hasn't been specified, false otherwise.
+ bool unspecified() const {
+ return (unspecified_);
+ }
+
+ /// @brief Checks if the encapsulated value is empty.
+ ///
+ /// This method can be overloaded in the template specializations that
+ /// are dedicated to strings, vectors etc.
+ ///
+ /// @throw isc::InvalidOperation.
+ bool empty() const {
+ isc_throw(isc::InvalidOperation, "call to empty() not supported");
+ }
+
+protected:
+ T default_; ///< Encapsulated value.
+ bool unspecified_; ///< Flag which indicates if the value is specified.
+};
+
+/// @brief Specialization of the default @c Optional constructor for
+/// strings.
+///
+/// It calls default string object constructor.
+template<>
+inline Optional<std::string>::Optional()
+ : default_(), unspecified_(true) {
+}
+
+/// @brief Specialization of the @c Optional::empty method for strings.
+///
+/// @return true if the value is empty, false otherwise.
+template<>
+inline bool Optional<std::string>::empty() const {
+ return (default_.empty());
+}
+
+/// @brief Inserts an optional value to a stream.
+///
+/// This function overloads the global operator<< to behave as in
+/// @c ostream::operator<< but applied to @c Optional objects.
+///
+/// @param os A @c std::ostream object to which the value is inserted.
+/// @param optional_value An @c Optional object to be inserted into
+/// a stream.
+/// @tparam Type of the value encapsulated by the @c Optional object.
+///
+/// @return A reference to the stream after insertion.
+template<typename T>
+std::ostream&
+operator<<(std::ostream& os, const Optional<T>& optional_value) {
+ os << optional_value.get();
+ return (os);
+}
+
+
+} // end of namespace isc::util
+} // end of namespace isc
+
+#endif // OPTIONAL_VALUE_H