File: id.hpp

package info (click to toggle)
sight 25.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 42,180 kB
  • sloc: cpp: 289,476; xml: 17,257; ansic: 9,878; python: 1,379; sh: 144; makefile: 33
file content (210 lines) | stat: -rw-r--r-- 6,591 bytes parent folder | download | duplicates (2)
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/************************************************************************
 *
 * Copyright (C) 2009-2024 IRCAD France
 * Copyright (C) 2012-2019 IHU Strasbourg
 *
 * This file is part of Sight.
 *
 * Sight is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Sight is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Sight. If not, see <https://www.gnu.org/licenses/>.
 *
 ***********************************************************************/

#pragma once

#include <sight/core/config.hpp>

#include "base.hpp"

#include "mt/types.hpp"

#include "string.hpp"

#include <cstdint>
#include <string>
#include <unordered_map>

namespace sight::core
{

class object;

/**
 * @brief   Defines ID for core::object. It is used to associate ID with object.
 */
class SIGHT_CORE_CLASS_API id
{
public:

    SIGHT_DECLARE_CLASS(id);

    using type = std::string;

    enum class policy
    {
        empty = 1, ///< return an empty id if no one set
        generate,  ///< generate a new id if necessary
        must_exist ///< throw an exception if object has not id.
    };

    SIGHT_CORE_API virtual ~id();

    /**
     * Test if the given id exist (i.e recorded in fwID dictionary)
     * @param[in] _id : the id to test.
     * @return true iff the given id is recorded in fwID dictionary.
     * @note This method is thread-safe.
     */
    SIGHT_CORE_API static bool exist(type _id);

    /**
     * @brief Retrieve the object attached to the given id. Return a null sptr if no correspondence exist.
     * @note This method is thread-safe.
     */
    SIGHT_CORE_API static SPTR(object) get_object(type _request_id);

    template<typename T, typename ... Args>
    static SPTR(object) get_object(const T& _first, const Args & ... _args);

    /**
     * @brief Concatenate things with the separator `s_separator`.
     * This is an utility function to be used where an id is constructed from multiple parts.
     * @note This method uses variadic template as argument to concatenate.
     */
    template<typename T, typename ... Args>
    static std::string join(const T& _first, const Args& ... _args);

protected:

    inline static constexpr auto s_separator = '-';

    /**
     * @brief   Constructor : does nothing.
     */
    id() = default; // cannot be instantiated

    // API to expose in core::object
    /**
     * @brief Return true if the object has an id set.
     * @note This method is thread-safe.
     */
    SIGHT_CORE_API bool has_id() const;

    /**
     * @brief Returns the id of the object. If it is not set and the policy value is
     * \li EMPTY then an empty id is returned
     * \li GENERATE (default) then a new ID will be generated (and recorded) using the pattern "CLASSNAME-NUM". NUM is
     * always increasing
     * \li MUST_EXIST then an exception Failed is raised
     * @note We consider an object be constant whatever if its id is generated.
     * @note This method is thread-safe.
     */
    SIGHT_CORE_API type get_id(policy _policy = policy::generate) const;

    /**
     * @brief Returns the base ID of the object which is the last sub-string when separator is used in ID.
     * For example, if the ID is "config_name-1-my_service", the base ID is "my_service".
     * @note if there is no separator, the "full" ID is returned.
     */
    SIGHT_CORE_API type base_id(policy _policy = policy::generate) const;

    /**
     * @brief Set an ID for the object.
     * @warning Cannot set an empty or existing ID.
     * @note This method is thread-safe.
     */
    SIGHT_CORE_API virtual void set_id(type _new_id);

    /**
     * @brief Set an ID for the object by joining all arguments into a string.
     * @note arguments are separated with `s_separator`.
     */
    template<typename T, typename ... Args>
    void set_id(const T& _first, const Args& ... _args);

    /**
     * @brief Release the id for the object.
     * @note This method is thread-safe
     */
    SIGHT_CORE_API void reset_id();

private:

    /**
     * @brief Will generate a new ID using the pattern "CLASSNAME-NUM". NUM is always increasing.
     * @note This method is NOT thread-safe.
     */
    type generate() const;

    /**
     * @brief Remove ID from the dictionary.
     * @note This method is NOT thread-safe.
     */
    static void remove_id_from_dictionary(type _id);

    /**
     * @brief return true if the  _id is found in the dictionary.
     * @note This method is NOT thread-safe.
     */
    static bool is_id_found(type _id);

    /**
     * @brief Add newID in the dictionary (newID must not exist in fwID).
     * @note This method is NOT thread-safe
     */
    void add_id_in_dictionary(type _new_id) const;

    /// The ID associated with the object. It is mutable, as it may be modified with a call to get_id(GENERATE).
    mutable type m_id;

    using dictionary          = std::unordered_map<type, std::weak_ptr<object> >;
    using categorized_counter = std::unordered_map<std::string, std::uint32_t>;

    static dictionary s_dictionary;
    static categorized_counter s_categorized_counter;

    /// Mutex used to lock dictionary access
    static core::mt::read_write_mutex s_dictionary_mutex;

    /// Mutex used by generate() to lock m_CategorizedCounter changes.
    static core::mt::mutex s_mutex_counter;

    /// Mutex used to lock m_id access
    mutable core::mt::read_write_mutex m_id_mutex;
};

//------------------------------------------------------------------------------

template<typename T, typename ... Args>
SPTR(object) id::get_object(const T& _first, const Args & ... _args)
{
    return get_object(join(_first, _args ...));
}

//------------------------------------------------------------------------------

template<typename T, typename ... Args>
std::string id::join(const T& _first, const Args& ... _args)
{
    return string::join(s_separator, _first, _args ...);
}

//------------------------------------------------------------------------------

template<typename T, typename ... Args>
void id::set_id(const T& _first, const Args& ... _args)
{
    set_id(join(_first, _args ...));
}

} // namespace sight::core