]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#487,!242] Adjusted OptionalValue to Triplet and renamed to Optional.
authorMarcin Siodelski <marcin@isc.org>
Mon, 25 Feb 2019 11:35:44 +0000 (12:35 +0100)
committerMarcin Siodelski <marcin@isc.org>
Thu, 28 Feb 2019 13:38:18 +0000 (08:38 -0500)
src/bin/dhcp4/tests/dhcp4_client.cc
src/bin/dhcp4/tests/dhcp4_client.h
src/bin/dhcp4/tests/dora_unittest.cc
src/lib/dhcp/iface_mgr.cc
src/lib/dhcp/iface_mgr.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/parsers/option_data_parser.cc
src/lib/dhcpsrv/parsers/option_data_parser.h
src/lib/util/optional_value.h
src/lib/util/tests/optional_value_unittest.cc

index 19565308a4f864ea4b8cde9443cca92a10686135..d02e82df73c7adb72da698549594cbbc47d0c1ed 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
@@ -42,7 +42,7 @@ Dhcp4Client::Configuration::reset() {
 
 Dhcp4Client::Dhcp4Client(const Dhcp4Client::State& state) :
     config_(),
-    ciaddr_(IOAddress("0.0.0.0")),
+    ciaddr_(),
     curr_transid_(0),
     dest_addr_("255.255.255.255"),
     hwaddr_(generateHWAddr()),
@@ -60,7 +60,7 @@ Dhcp4Client::Dhcp4Client(const Dhcp4Client::State& state) :
 Dhcp4Client::Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv> srv,
                          const Dhcp4Client::State& state) :
     config_(),
-    ciaddr_(IOAddress("0.0.0.0")),
+    ciaddr_(),
     curr_transid_(0),
     dest_addr_("255.255.255.255"),
     fqdn_(),
@@ -259,8 +259,8 @@ Dhcp4Client::doDiscover(const boost::shared_ptr<IOAddress>& requested_addr) {
         addRequestedAddress(*requested_addr);
     }
     // Override the default ciaddr if specified by a test.
-    if (ciaddr_.isSpecified()) {
-        context_.query_->setCiaddr(ciaddr_.get());
+    if (!ciaddr_.unspecified()) {
+        context_.query_->setCiaddr(ciaddr_);
     }
     appendExtraOptions();
     appendClasses();
@@ -364,8 +364,8 @@ Dhcp4Client::doRequest() {
     context_.query_ = createMsg(DHCPREQUEST);
 
     // Override the default ciaddr if specified by a test.
-    if (ciaddr_.isSpecified()) {
-        context_.query_->setCiaddr(ciaddr_.get());
+    if (!ciaddr_.unspecified()) {
+        context_.query_->setCiaddr(ciaddr_);
     } else if ((state_ == SELECTING) || (state_ == INIT_REBOOT)) {
         context_.query_->setCiaddr(IOAddress("0.0.0.0"));
     } else {
index d86491f1fe3bd75bad93a2f5d89e683f3137b9e7..5201176bcf88753683789c1dc04a563a1e038070 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
@@ -371,7 +371,7 @@ public:
     /// If this value is "unspecified" the default values will be used
     /// by the client. If this value is specified, it will override ciaddr
     /// in the client's messages.
-    isc::util::OptionalValue<asiolink::IOAddress> ciaddr_;
+    isc::util::Optional<asiolink::IOAddress> ciaddr_;
 
     /// @brief Adds extra option (an option the client will always send)
     ///
index 7ae1424c97cb248c9c9ed385817a791de294f85a..e74f473dd0f8524c26cd3ace7b15a715a48a6f2e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
@@ -1040,7 +1040,7 @@ TEST_F(DORATest, ciaddr) {
     // Configure DHCP server.
     configure(DORA_CONFIGS[0], *client.getServer());
     // Force ciaddr of Discover message to be non-zero.
-    client.ciaddr_.specify(IOAddress("10.0.0.50"));
+    client.ciaddr_ = IOAddress("10.0.0.50");
     // Obtain a lease from the server using the 4-way exchange.
     ASSERT_NO_THROW(client.doDiscover(boost::shared_ptr<
                                       IOAddress>(new IOAddress("10.0.0.50"))));
@@ -1076,7 +1076,7 @@ TEST_F(DORATest, ciaddr) {
     // Replace the address held by the client. The client will request
     // the assignment of this address but the server has a different
     // address for this client.
-    client.ciaddr_.specify(IOAddress("192.168.0.30"));
+    client.ciaddr_ = IOAddress("192.168.0.30");
     ASSERT_NO_THROW(client.doRequest());
     // The client is sending invalid ciaddr so the server should send a NAK.
     resp = client.getContext().response_;
index a4dc8ad636aedef349986f8c2c061dff1d4a1390..50c041e20e7e96544db03eef1f6768f51bcf233f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2019 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
@@ -213,7 +213,7 @@ void Iface::addUnicast(const isc::asiolink::IOAddress& addr) {
                       << " already defined on the " << name_ << " interface.");
         }
     }
-    unicasts_.push_back(OptionalValue<IOAddress>(addr, true));
+    unicasts_.push_back(Optional<IOAddress>(addr));
 }
 
 bool
@@ -244,7 +244,7 @@ Iface::hasAddress(const isc::asiolink::IOAddress& address) const {
 
 void
 Iface::addAddress(const isc::asiolink::IOAddress& addr) {
-    addrs_.push_back(Address(addr, OptionalValueState(true)));
+    addrs_.push_back(Address(addr));
 }
 
 void
@@ -252,7 +252,7 @@ Iface::setActive(const IOAddress& address, const bool active) {
     for (AddressCollection::iterator addr_it = addrs_.begin();
          addr_it != addrs_.end(); ++addr_it) {
         if (address == addr_it->get()) {
-            addr_it->specify(OptionalValueState(active));
+            addr_it->unspecified(!active);
             return;
         }
     }
@@ -264,7 +264,7 @@ void
 Iface::setActive(const bool active) {
     for (AddressCollection::iterator addr_it = addrs_.begin();
          addr_it != addrs_.end(); ++addr_it) {
-        addr_it->specify(OptionalValueState(active));
+        addr_it->unspecified(!active);
     }
 }
 
@@ -272,7 +272,7 @@ unsigned int
 Iface::countActive4() const {
     uint16_t count = 0;
     BOOST_FOREACH(Address addr, addrs_) {
-        if (addr.get().isV4() && addr.isSpecified()) {
+        if (!addr.unspecified() && addr.get().isV4()) {
             ++count;
         }
     }
@@ -526,7 +526,7 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
 
         BOOST_FOREACH(Iface::Address addr, iface->getAddresses()) {
             // Skip non-IPv4 addresses and those that weren't selected..
-            if (!addr.get().isV4() || !addr.isSpecified()) {
+            if (addr.unspecified() || !addr.get().isV4()) {
                 continue;
             }
 
index e771ce2764706970310bdb21613e3c04c69f9c56..229bb5fd0a171c847ec6a1439813b3b72a295314 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2019 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
@@ -118,7 +118,7 @@ public:
     static const unsigned int MAX_MAC_LEN = 20;
 
     /// @brief Address type.
-    typedef util::OptionalValue<asiolink::IOAddress> Address;
+    typedef util::Optional<asiolink::IOAddress> Address;
 
     /// Type that defines list of addresses
     typedef std::list<Address> AddressCollection;
@@ -227,7 +227,7 @@ public:
 
     /// @brief Returns all addresses available on an interface.
     ///
-    /// The returned addresses are encapsulated in the @c util::OptionalValue
+    /// The returned addresses are encapsulated in the @c util::Optional
     /// class to be able to selectively flag some of the addresses as active
     /// (when optional value is specified) or inactive (when optional value
     /// is specified). If the address is marked as active, the
index 75e2d17e1818ca6bdfe7d019f186a5d03f356ebe..8bb59e099e44010b92f53a5542e5e8dc6ee94f00 100644 (file)
@@ -1758,7 +1758,7 @@ public:
     std::vector<MYSQL_BIND>
     createBindForSend(const OptionDescriptor& opt_desc,
                       const std::string& opt_space,
-                      const OptionalValue<SubnetID>& subnet_id,
+                      const Optional<SubnetID>& subnet_id,
                       const HostID& host_id) {
 
         // Hold pointer to the option to make sure it remains valid until
@@ -1850,7 +1850,7 @@ public:
             bind_[7].length = &client_class_len_;
 
             // dhcp4_subnet_id: INT UNSIGNED NULL
-            if (subnet_id.isSpecified()) {
+            if (!subnet_id.unspecified()) {
                 subnet_id_ = subnet_id;
                 bind_[8].buffer_type = MYSQL_TYPE_LONG;
                 bind_[8].buffer = reinterpret_cast<char*>(subnet_id_);
@@ -2029,7 +2029,7 @@ public:
     void addOption(const MySqlHostDataSourceImpl::StatementIndex& stindex,
                    const OptionDescriptor& opt_desc,
                    const std::string& opt_space,
-                   const OptionalValue<SubnetID>& subnet_id,
+                   const Optional<SubnetID>& subnet_id,
                    const HostID& host_id);
 
     /// @brief Inserts multiple options into the database.
@@ -2624,7 +2624,7 @@ void
 MySqlHostDataSourceImpl::addOption(const StatementIndex& stindex,
                                    const OptionDescriptor& opt_desc,
                                    const std::string& opt_space,
-                                   const OptionalValue<SubnetID>& subnet_id,
+                                   const Optional<SubnetID>& subnet_id,
                                    const HostID& id) {
     std::vector<MYSQL_BIND> bind =
         host_option_exchange_->createBindForSend(opt_desc, opt_space,
@@ -2652,7 +2652,7 @@ MySqlHostDataSourceImpl::addOptions(const StatementIndex& stindex,
         if (options && !options->empty()) {
             for (OptionContainer::const_iterator opt = options->begin();
                  opt != options->end(); ++opt) {
-                addOption(stindex, *opt, *space, OptionalValue<SubnetID>(),
+                addOption(stindex, *opt, *space, Optional<SubnetID>(),
                           host_id);
             }
         }
index 97c34e097079a2b43f4911258e1888ebfafe23dc..f447a9f75777e88b7ef812f9094970b82b1e8eca 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 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
@@ -47,7 +47,7 @@ OptionDataParser::parse(isc::data::ConstElementPtr single_option) {
     return (opt);
 }
 
-OptionalValue<uint32_t>
+Optional<uint32_t>
 OptionDataParser::extractCode(ConstElementPtr parent) const {
     uint32_t code;
     try {
@@ -56,7 +56,7 @@ OptionDataParser::extractCode(ConstElementPtr parent) const {
     } catch (const std::exception&) {
         // The code parameter was not found. Return an unspecified
         // value.
-        return (OptionalValue<uint32_t>());
+        return (Optional<uint32_t>());
     }
 
     if (code == 0) {
@@ -81,17 +81,17 @@ OptionDataParser::extractCode(ConstElementPtr parent) const {
 
     }
 
-    return (OptionalValue<uint32_t>(code, OptionalValueState(true)));
+    return (Optional<uint32_t>(code));
 }
 
-OptionalValue<std::string>
+Optional<std::string>
 OptionDataParser::extractName(ConstElementPtr parent) const {
     std::string name;
     try {
         name = getString(parent, "name");
 
     } catch (...) {
-        return (OptionalValue<std::string>());
+        return (Optional<std::string>());
     }
 
     if (name.find(" ") != std::string::npos) {
@@ -100,7 +100,7 @@ OptionDataParser::extractName(ConstElementPtr parent) const {
                   << getPosition("name", parent) << ")");
     }
 
-    return (OptionalValue<std::string>(name, OptionalValueState(true)));
+    return (Optional<std::string>(name));
 }
 
 std::string
@@ -117,17 +117,17 @@ OptionDataParser::extractData(ConstElementPtr parent) const {
     return (data);
 }
 
-OptionalValue<bool>
+Optional<bool>
 OptionDataParser::extractCSVFormat(ConstElementPtr parent) const {
     bool csv_format = true;
     try {
         csv_format = getBoolean(parent, "csv-format");
 
     } catch (...) {
-        return (OptionalValue<bool>(csv_format));
+        return (Optional<bool>());
     }
 
-    return (OptionalValue<bool>(csv_format, OptionalValueState(true)));
+    return (Optional<bool>(csv_format));
 }
 
 std::string
@@ -166,17 +166,17 @@ OptionDataParser::extractSpace(ConstElementPtr parent) const {
     return (space);
 }
 
-OptionalValue<bool>
+Optional<bool>
 OptionDataParser::extractPersistent(ConstElementPtr parent) const {
     bool persist = false;
     try {
         persist = getBoolean(parent, "always-send");
 
     } catch (...) {
-        return (OptionalValue<bool>(persist));
+        return (Optional<bool>());
     }
 
-    return (OptionalValue<bool>(persist, OptionalValueState(true)));
+    return (Optional<bool>(persist));
 }
 
 template<typename SearchKey>
@@ -231,16 +231,16 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
     const Option::Universe universe = address_family_ == AF_INET ?
         Option::V4 : Option::V6;
 
-    OptionalValue<uint32_t> code_param =  extractCode(option_data);
-    OptionalValue<std::string> name_param = extractName(option_data);
-    OptionalValue<bool> csv_format_param = extractCSVFormat(option_data);
-    OptionalValue<bool> persist_param = extractPersistent(option_data);
+    Optional<uint32_t> code_param =  extractCode(option_data);
+    Optional<std::string> name_param = extractName(option_data);
+    Optional<bool> csv_format_param = extractCSVFormat(option_data);
+    Optional<bool> persist_param = extractPersistent(option_data);
     std::string data_param = extractData(option_data);
     std::string space_param = extractSpace(option_data);
     ConstElementPtr user_context = option_data->get("user-context");
 
     // Require that option code or option name is specified.
-    if (!code_param.isSpecified() && !name_param.isSpecified()) {
+    if (code_param.unspecified() && name_param.unspecified()) {
         isc_throw(DhcpConfigError, "option data configuration requires one of"
                   " 'code' or 'name' parameters to be specified"
                   << " (" << option_data->getPosition() << ")");
@@ -248,16 +248,16 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
 
     // Try to find a corresponding option definition using option code or
     // option name.
-    OptionDefinitionPtr def = code_param.isSpecified() ?
-        findOptionDefinition(space_param, code_param) :
-        findOptionDefinition(space_param, name_param);
+    OptionDefinitionPtr def = code_param.unspecified() ?
+        findOptionDefinition(space_param, name_param) :
+        findOptionDefinition(space_param, code_param);
 
     // If there is no definition, the user must not explicitly enable the
     // use of csv-format.
     if (!def) {
         // If explicitly requested that the CSV format is to be used,
         // the option definition is a must.
-        if (csv_format_param.isSpecified() && csv_format_param) {
+        if (!csv_format_param.unspecified() && csv_format_param) {
             isc_throw(DhcpConfigError, "definition for the option '"
                       << space_param << "." << name_param
                       << "' having code '" << code_param
@@ -267,7 +267,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
 
         // If there is no option definition and the option code is not specified
         // we have no means to find the option code.
-        } else if (name_param.isSpecified() && !code_param.isSpecified()) {
+        } else if (!name_param.unspecified() && code_param.unspecified()) {
             isc_throw(DhcpConfigError, "definition for the option '"
                       << space_param << "." << name_param
                       << "' does not exist ("
@@ -282,7 +282,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
 
     // If the definition is available and csv-format hasn't been explicitly
     // disabled, we will parse the data as comma separated values.
-    if (def && (!csv_format_param.isSpecified() || csv_format_param)) {
+    if (def && (csv_format_param.unspecified() || csv_format_param)) {
         // If the option data is specified as a string of comma
         // separated values then we need to split this string into
         // individual values - each value will be used to initialize
@@ -325,11 +325,11 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
                                     binary));
 
         desc.option_ = option;
-        desc.persistent_ = persist_param.isSpecified() && persist_param;
+        desc.persistent_ = !persist_param.unspecified() && persist_param;
     } else {
 
         // Option name is specified it should match the name in the definition.
-        if (name_param.isSpecified() && (def->getName() != name_param.get())) {
+        if (!name_param.unspecified() && (def->getName() != name_param.get())) {
             isc_throw(DhcpConfigError, "specified option name '"
                       << name_param << "' does not match the "
                       << "option definition: '" << space_param
@@ -341,12 +341,12 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
         // Option definition has been found so let's use it to create
         // an instance of our option.
         try {
-            bool use_csv = !csv_format_param.isSpecified() || csv_format_param;
+            bool use_csv = csv_format_param.unspecified() || csv_format_param;
             OptionPtr option = use_csv ?
                 def->optionFactory(universe, def->getCode(), data_tokens) :
                 def->optionFactory(universe, def->getCode(), binary);
             desc.option_ = option;
-            desc.persistent_ = persist_param.isSpecified() && persist_param;
+            desc.persistent_ = !persist_param.unspecified() && persist_param;
             if (use_csv) {
                 desc.formatted_value_ = data_param;
             }
index 06770dd219bd929bf137d2791501957a9cc4b845..b19406bbefc130ad9a0a8ff0838699064674cb5f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 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
@@ -107,7 +107,7 @@ private:
     ///
     /// @return Option code, possibly unspecified.
     /// @throw DhcpConfigError if option code is invalid.
-    util::OptionalValue<uint32_t>
+    util::Optional<uint32_t>
     extractCode(data::ConstElementPtr parent) const;
 
     /// @brief Retrieves parsed option name as an optional value.
@@ -116,13 +116,13 @@ private:
     ///
     /// @return Option name, possibly unspecified.
     /// @throw DhcpConfigError if option name is invalid.
-    util::OptionalValue<std::string>
+    util::Optional<std::string>
     extractName(data::ConstElementPtr parent) const;
 
     /// @brief Retrieves csv-format parameter as an optional value.
     ///
     /// @return Value of the csv-format parameter, possibly unspecified.
-    util::OptionalValue<bool> extractCSVFormat(data::ConstElementPtr parent) const;
+    util::Optional<bool> extractCSVFormat(data::ConstElementPtr parent) const;
 
     /// @brief Retrieves option data as a string.
     ///
@@ -145,7 +145,7 @@ private:
     /// @brief Retrieves persistent/always-send parameter as an optional value.
     ///
     /// @return Value of the persistent parameter, possibly unspecified.
-    util::OptionalValue<bool> extractPersistent(data::ConstElementPtr parent) const;
+    util::Optional<bool> extractPersistent(data::ConstElementPtr parent) const;
 
     /// @brief Address family: @c AF_INET or @c AF_INET6.
     uint16_t address_family_;
index 5ff5bf0de525be90958bce6f07c8d0464e777481..bda8272a03dc1650e9c704790536c116bb8a1b00 100644 (file)
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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_VALUE_H
-#define OPTIONAL_VALUE_H
+#ifndef OPTIONAL_H
+#define OPTIONAL_H
 
 #include <ostream>
+#include <string>
 
 namespace isc {
 namespace util {
 
-/// @brief Indicate if an @c OptionalValue is is specified or not.
+/// @brief A template representing an optional value.
 ///
-/// This is a simple wrapper class which holds a boolean value to indicate
-/// if the @c OptionalValue is specified or not. By using this class in the
-/// @c OptionalValue class constructor we avoid the ambiguity when the
-/// @c OptionalValue encapsulates a bool type.
-struct OptionalValueState {
-
-    /// @brief Constructor.
-    ///
-    /// @param specified A boolean value to be assigned.
-    OptionalValueState(const bool specified)
-        : specified_(specified) {
-    }
-    /// @brief A bool value encapsulated by this structure.
-    bool specified_;
-};
-
-/// @brief Simple class representing an optional value.
-///
-/// This template class encapsulates a value of any type. An additional flag
-/// held by this class indicates if the value is "specified" or "unspecified".
-/// For example, a configuration parser for DHCP server may use this class
-/// to represent the value of the configuration parameter which may appear
-/// in the configuration file, but is not mandatory. The value of the
-/// @c OptionalValue may be initialized to "unspecified" initially. When the
-/// configuration parser finds that the appropriate 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.
+/// This template class encapsulates an optional value. The default implementation
+/// encapsulates numeric values, but additional specializations are defined
+/// as neccessary to support other types od data.
 ///
-/// This is a generic class and may be used in all cases when there is a need
-/// for the additional information to be carried along with the value.
-/// Alternative approach is to use a pointer which is only initialized if the
-/// actual value needs to be specified, but this may not be feasible in all
-/// cases.
+/// 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 overriden 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 OptionalValue {
+class Optional {
 public:
 
-    /// @brief Default constructor.
+    /// @brief Assigns a new value value and marks it "specified".
     ///
-    /// Note that the type @c T must have a default constructor to use this
-    /// constructor.
-    OptionalValue()
-        : value_(T()), specified_(false) {
+    /// @param other new actual value.
+    Optional<T>& operator=(T other) {
+        default_ = other;
+        unspecified_ = false;
+        return (*this);
     }
 
-    /// @brief Constructor
-    ///
-    /// Creates optional value. The value defaults to "unspecified".
-    ///
-    /// @param value Default explicit value.
-    /// @param state Specifies bool which determines if the value is initially
-    /// specified or not (default is false).
-    explicit OptionalValue(const T& value, const OptionalValueState& state =
-                           OptionalValueState(false))
-        : value_(value), specified_(state.specified_) {
-    }
-
-    /// @brief Retrieves the actual value.
-    T get() const {
-        return (value_);
-    }
-
-    /// @brief Sets the actual value.
+    /// @brief Type cast operator.
     ///
-    /// @param value New value.
-    void set(const T& value) {
-        value_ = value;
-    }
-
-    /// @brief Sets the new value and marks it specified.
+    /// This operator converts the optional value to the actual value being
+    /// encapsulated.
     ///
-    /// @param value New actual value.
-    void specify(const T& value) {
-        set(value);
-        specify(OptionalValueState(true));
+    /// @return Encapsulated value.
+    operator T() const {
+        return (default_);
     }
 
-    /// @brief Sets the value to "specified" or "unspecified".
+    /// @brief Default constructor.
     ///
-    /// It does not alter the actual value. It only marks it "specified" or
-    /// "unspecified".
-    /// @param state determines if a value is specified or not
-    void specify(const OptionalValueState& state) {
-        specified_ = state.specified_;
+    /// Sets the encapsulated value to 0.
+    Optional()
+        : default_(T(0)), unspecified_(true) {
     }
 
-    /// @brief Checks if the value is specified or unspecified.
+    /// @brief Constructor
     ///
-    /// @return true if the value is specified, false otherwise.
-    bool isSpecified() const {
-        return (specified_);
-    }
-
-    /// @brief Specifies a new value value and marks it "specified".
+    /// Creates optional value and marks it as "specified".
     ///
-    /// @param value New actual value.
-    void operator=(const T& value) {
-        specify(value);
+    /// @param value value to be assigned.
+    explicit Optional(T value)
+        : default_(value), unspecified_(false) {
     }
 
-    /// @brief Equality operator.
-    ///
-    /// @param value Actual value to compare to.
-    ///
-    /// @return true if the value is specified and equals the argument.
-    bool operator==(const T& value) const {
-        return (specified_ && (value_ == value));
+    /// @brief Retrieves the actual value.
+    T get() const {
+        return (default_);
     }
 
-    /// @brief Inequality operator.
+    /// @brief Modifies the flag that indicates whether the value is specified
+    /// or unspecified.
     ///
-    /// @param value Actual value to compare to.
-    ///
-    /// @return true if the value is unspecified or unequal.
-    bool operator!=(const T& value) const {
-        return (!operator==(value));
+    /// @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 Type cast operator.
-    ///
-    /// This operator converts the optional value to the actual value being
-    /// encapsulated.
+    /// @brief Checks if the value has been specified or unspecified.
     ///
-    /// @return Encapsulated value.
-    operator T() const {
-        return (value_);
+    /// @return true if the value hasn't been specified, false otherwise.
+    bool unspecified() const {
+        return (unspecified_);
     }
 
-private:
-    T value_;         ///< Encapsulated value.
-    bool specified_;  ///< Flag which indicates if the value is specified.
+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 Inserts an optional value to a stream.
 ///
 /// This function overloads the global operator<< to behave as in
-/// @c ostream::operator<< but applied to @c OptionalValue objects.
+/// @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 OptionalValue object to be inserted into
+/// @param optional_value An @c Optional object to be inserted into
 /// a stream.
-/// @tparam Type of the value encapsulated by the @c OptionalValue object.
+/// @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 OptionalValue<T>& optional_value) {
+operator<<(std::ostream& os, const Optional<T>& optional_value) {
     os << optional_value.get();
     return (os);
 }
index 903cd051472508cdfcbd5c63a83ef986fa4cb8fa..fe9d39e021810292f7e10b0369295dfd69a33e16 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2019 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
@@ -12,122 +12,65 @@ namespace {
 
 using namespace isc::util;
 
-// This test checks that the constructor sets the values passed as arguments.
-TEST(OptionalValueTest, constructor) {
-    // Do not specify the second parameter. The default should be that
-    // the value is "unspecified".
-    OptionalValue<int> value1(10);
+// This test checks that the constructors work correctly.
+TEST(OptionalTest, constructor) {
+    // Explicitly set a value via constructor. The value becomes
+    // specified.
+    Optional<int> value1(10);
     EXPECT_EQ(10, value1.get());
-    EXPECT_FALSE(value1.isSpecified());
+    EXPECT_FALSE(value1.unspecified());
 
-    // Use the non-default value for second parameter.
-    OptionalValue<int> value2(2, true);
-    EXPECT_EQ(2, value2.get());
-    EXPECT_TRUE(value2.isSpecified());
+    // Do not set a value in a constructor. The value should be
+    // unspecified.
+    Optional<int> value2;
+    EXPECT_EQ(0, value2.get());
+    EXPECT_TRUE(value2.unspecified());
 }
 
-// This test checks that the OptionalValue::set and OptionalValue::specify
-// set the values as expected.
-TEST(OptionalValueTest, set) {
-    OptionalValue<int> value(10);
-    ASSERT_EQ(10, value.get());
-    ASSERT_FALSE(value.isSpecified());
-
-    // Set new value. This should not change the "specified" flag.
-    value.set(100);
-    ASSERT_EQ(100, value.get());
-    ASSERT_FALSE(value.isSpecified());
-
-    // Mark value "specified". The value itself should not change.
-    value.specify(OptionalValueState(true));
-    ASSERT_EQ(100, value.get());
-    ASSERT_TRUE(value.isSpecified());
-
-    // Once it is "specified", set the new value. It should remain specified.
-    value.set(5);
-    ASSERT_EQ(5, value.get());
-    ASSERT_TRUE(value.isSpecified());
-
-    // Mark it "unspecified". The value should remain the same.
-    value.specify(OptionalValueState(false));
-    ASSERT_EQ(5, value.get());
-    ASSERT_FALSE(value.isSpecified());
-}
+TEST(OptionalTest, constructorString) {
+    Optional<std::string> value1("foo");
+    EXPECT_EQ("foo", value1.get());
 
-// This test checks that the OptionalValue::specify functions may be used
-// to set the new value and to mark value specified.
-TEST(OptionalValueTest, specifyValue) {
-    OptionalValue<int> value(10);
-    ASSERT_EQ(10, value.get());
-    ASSERT_FALSE(value.isSpecified());
-
-    // Set the new value and mark it "specified".
-    value.specify(123);
-    ASSERT_EQ(123, value.get());
-    ASSERT_TRUE(value.isSpecified());
-
-    // Specify another value. The value should be still "specified".
-    value.specify(1000);
-    ASSERT_EQ(1000, value.get());
-    ASSERT_TRUE(value.isSpecified());
+    Optional<std::string> value2;
+    EXPECT_TRUE(value2.get().empty());
 }
 
 // This test checks if the assignment operator assigning an actual
 // value to the optional value works as expected.
-TEST(OptionalValueTest, assignValue) {
-    OptionalValue<int> value(10);
-    ASSERT_EQ(10, value.get());
-    ASSERT_FALSE(value.isSpecified());
+TEST(OptionalTest, assignValue) {
+    Optional<int> value(10);
+    EXPECT_EQ(10, value.get());
+    EXPECT_FALSE(value.unspecified());
 
-    // Set the new value and mark it "specified".
+    // Assign a new value.
     value = 111;
-    ASSERT_EQ(111, value.get());
-    ASSERT_TRUE(value.isSpecified());
+    EXPECT_EQ(111, value.get());
+    EXPECT_FALSE(value.unspecified());
 
-    // Specify another value. The value should be still "specified".
+    // Assign another value.
     value = 1000;
-    ASSERT_EQ(1000, value.get());
-    ASSERT_TRUE(value.isSpecified());
+    EXPECT_EQ(1000, value.get());
+    EXPECT_FALSE(value.unspecified());
 }
 
-// This test checks if the equality and inequality operators work
-// correctly for the optional value.
-TEST(OptionalValueTest, equalityOperators) {
-    OptionalValue<int> value(10);
-    ASSERT_EQ(10, value.get());
-    ASSERT_FALSE(value.isSpecified());
-
-    EXPECT_FALSE(value == 10);
-    EXPECT_TRUE(value != 10);
-    EXPECT_FALSE(value == 123);
-    EXPECT_TRUE(value != 123);
-
-    value.specify(OptionalValueState(true));
-
-    EXPECT_TRUE(value == 10);
-    EXPECT_FALSE(value != 10);
-    EXPECT_FALSE(value == 123);
-    EXPECT_TRUE(value != 123);
-
-    value = 123;
-    EXPECT_TRUE(value == 123);
-    EXPECT_FALSE(value != 123);
-    EXPECT_FALSE(value == 10);
-    EXPECT_TRUE(value != 10);
-
-    value.specify(OptionalValueState(false));
-
-    EXPECT_FALSE(value == 123);
-    EXPECT_TRUE(value != 123);
-    EXPECT_FALSE(value == 10);
-    EXPECT_TRUE(value != 10);
+// This test checks that it is possible to modify the flag that indicates
+// if the value is specified or unspecified.
+TEST(OptionalTest, modifyUnspecified) {
+    Optional<int> value;
+    EXPECT_TRUE(value.unspecified());
+
+    value.unspecified(false);
+    EXPECT_FALSE(value.unspecified());
+
+    value.unspecified(true);
+    EXPECT_TRUE(value.unspecified());
 }
 
 // This test checks if the type case operator returns correct value.
-TEST(OptionalValueTest, typeCastOperator) {
-    OptionalValue<int> value(-10, true);
+TEST(OptionalTest, typeCastOperator) {
+    Optional<int> value(-10);
     ASSERT_EQ(-10, value.get());
-    ASSERT_TRUE(value.isSpecified());
+    ASSERT_FALSE(value.unspecified());
 
     int actual = value;
     EXPECT_EQ(-10, actual);