1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright (C) 2013-2024 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 OPTION_SPACE_CONTAINER_H
#define OPTION_SPACE_CONTAINER_H

#include <exceptions/exceptions.h>
#include <list><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace dhcp {

/// @brief A tag for accessing DHCP options and definitions by id.
struct OptionIdIndexTag { };

/// @brief Simple container for option spaces holding various items.
///
/// This helper class is used to store items of various types
/// that are grouped by option space names. Each option space is
/// mapped to a container that holds items which specifically can
/// be OptionDefinition objects or Subnet::OptionDescriptor structures.
///
/// @tparam ContainerType of the container holding items within
/// option space.
/// @tparam ItemType type of the item being held by the container.
/// @tparam Selector a string (for option spaces) or uint32_t (for vendor options)
template<typename ContainerType, typename ItemType, typename Selector>
class OptionSpaceContainer {
public:

    /// Pointer to the container.
    typedef boost::shared_ptr<ContainerType> ItemsContainerPtr;

    /// @brief Indicates the container is empty
    ///
    /// @return true when the container is empty
    bool empty() const {
        return (option_space_map_.empty());
    }

    /// @brief Adds a new item to the option_space.
    ///
    /// @param item reference to the item being added.
    /// @param option_space name or vendor-id of the option space
    void addItem(const ItemType& item, const Selector& option_space) {
        ItemsContainerPtr items = getItems(option_space);
        // Assume that the push_back() can't fail even when the
        // ContainerType is a multi index container, i.e., assume
        // there is no unique index which can raise a conflict.
        static_cast<void>(items->push_back(item));
        option_space_map_[option_space] = items;
    }

    /// @brief Get all items for the particular option space.
    ///
    /// @warning when there are no items for the specified option
    /// space an empty container is created and returned. However
    /// this container is not added to the list of option spaces.
    ///
    /// @param option_space name or vendor-id of the option space.
    ///
    /// @return pointer to the container holding items.
    ItemsContainerPtr getItems(const Selector& option_space) const {
        const typename OptionSpaceMap::const_iterator& items =
            option_space_map_.find(option_space);
        if (items == option_space_map_.end()) {
            return (ItemsContainerPtr(new ContainerType()));
        }
        return (items->second);
    }

    /// @brief Get a list of existing option spaces.
    ///
    /// @return a list of option spaces.
    ///
    /// @todo This function is likely to be removed once
    /// we create a structure of OptionSpaces defined
    /// through the configuration manager.
    std::list<Selector> getOptionSpaceNames() const {
        std::list<Selector> names;
        for (typename OptionSpaceMap::const_iterator space =
                 option_space_map_.begin();
             space != option_space_map_.end(); ++space) {
            names.push_back(space->first);
        }
        return (names);
    }

    /// @brief Remove all items from the container.
    void clearItems() {
        option_space_map_.clear();
    }

    /// @brief Remove all options or option definitions with a given
    /// database identifier.
    ///
    /// Note that there are cases when there will be multiple options
    /// or option definitions having the same id (typically id of 0).
    /// When configuration backend is in use it sets the unique ids
    /// from the database. In cases when the configuration backend is
    /// not used, the ids default to 0. Passing the id of 0 would
    /// result in deleting all options or option definitions that were
    /// not added via the database.
    ///
    /// @param id Identifier of the items to be deleted.
    ///
    /// @return Number of deleted options or option definitions.
    uint64_t deleteItems(const uint64_t id) {
        uint64_t num_deleted = 0;
        for (auto const& space : option_space_map_) {
            auto container = space.second;
            auto& index = container->template get<OptionIdIndexTag>();
            num_deleted += index.erase(id);
        }

        return (num_deleted);
    }

    /// @brief Check if two containers are equal.
    ///
    /// This method checks if option space container contains exactly
    /// the same selectors and that there are exactly the same items
    /// added for each selector. The order of items doesn't matter.
    ///
    /// @param other Other container to compare to.
    ///
    /// @return true if containers are equal, false otherwise.
    bool equals(const OptionSpaceContainer& other) const {
        for (typename OptionSpaceMap::const_iterator it =
                 option_space_map_.begin(); it != option_space_map_.end();
             ++it) {

            typename OptionSpaceMap::const_iterator other_it =
                other.option_space_map_.find(it->first);
            if (other_it == other.option_space_map_.end()) {
                return (false);
            }

            // If containers have different sizes it is an indication that
            // they are unequal.
            if (it->second->size() != other_it->second->size()) {
                return (false);
            }

            // If they have the same sizes, we have to compare each element.
            for (typename ContainerType::const_iterator items_it =
                     it->second->begin();
                 items_it != it->second->end(); ++items_it) {

                bool match_found = false;
                for (typename ContainerType::const_iterator other_items_it =
                         other_it->second->begin();
                     other_items_it != other_it->second->end();
                     ++other_items_it) {
                    if (items_it->equals(*other_items_it)) {
                        match_found = true;
                        break;
                    }
                }

                if (!match_found) {
                    return (false);
                }
            }
        }
        return (true);
    }

private:

    /// A map holding container (option space name or vendor-id is the key).
    typedef std::map<Selector, ItemsContainerPtr> OptionSpaceMap;
    OptionSpaceMap option_space_map_;
};


} // end of isc::dhcp namespace
} // end of isc namespace

#endif // OPTION_SPACE_CONTAINER_H