1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef DART_COMMON_NAMEMANAGER_HPP_
34 #define DART_COMMON_NAMEMANAGER_HPP_
35 
36 #include <map>
37 #include <string>
38 
39 namespace dart {
40 namespace common {
41 
42 /// \brief class NameManager
43 ///
44 /// Typical usage:
45 /// \code{.cpp}
46 /// using namespace dart;
47 ///
48 /// NameManager<BodyNode*> nameMgr;
49 ///
50 /// BodyNode* bodyNode = new BodyNode();
51 /// std::string name = "Link";
52 ///
53 /// if (!nameMgr.hasName(name))
54 ///   nameMgr.addName(name, bodyNode);  // "Link"
55 /// else
56 ///   name = nameMgr.issueNewNameAndAdd(name, bodyNode);  // "Link1"
57 ///
58 /// bodyNode->setName(name);
59 /// \endcode
60 template <typename T>
61 class NameManager
62 {
63 public:
64   /// Constructor
65   NameManager(
66       const std::string& _managerName = "default",
67       const std::string& _defaultName = "default");
68 
69   /// Destructor
70   virtual ~NameManager() = default;
71 
72   /// Set a new pattern for name generation.
73   ///
74   /// Use %s to indicate the base name and use %d to indicate where the number
75   /// belongs. The pattern must contain both a %s and a %d.
76   ///
77   /// Examples:
78   /// "%s(%d)" : name -> name(1) -> name(2)
79   /// "%d-%s" : name -> 1-name -> 2-name
80   ///
81   /// returns false if the pattern was invalid (i.e. did not contain b
82   /// oth %s and %d)
83   bool setPattern(const std::string& _newPattern);
84 
85   /// Issue new unique combined name of given base name and number suffix
86   std::string issueNewName(const std::string& _name) const;
87 
88   /// Call issueNewName() and add the result to the map
89   std::string issueNewNameAndAdd(const std::string& _name, const T& _obj);
90 
91   /// Add an object to the map
92   bool addName(const std::string& _name, const T& _obj);
93 
94   /// Remove an object from the Manager based on its name
95   bool removeName(const std::string& _name);
96 
97   /// Remove an object from the Manager based on reverse lookup
98   bool removeObject(const T& _obj);
99 
100   /// Remove _name using the forward lookup and _obj using the reverse lookup.
101   /// This will allow you to add _obj under the name _name without any conflicts
102   void removeEntries(const std::string& _name, const T& _obj);
103 
104   /// Clear all the objects
105   void clear();
106 
107   /// Return true if the name is contained
108   bool hasName(const std::string& _name) const;
109 
110   /// Return true if the object is contained
111   bool hasObject(const T& _obj) const;
112 
113   /// Get the number of the objects currently stored by the NameManager
114   std::size_t getCount() const;
115 
116   /// Get object by given name
117   /// \param[in] _name
118   ///   Name of the requested object
119   /// \return
120   ///   The object if it exists, or nullptr if it does not exist
121   T getObject(const std::string& _name) const;
122 
123   /// Use a reverse lookup to get the name that the manager has _obj listed
124   /// under. Returns an empty string if it is not in the list.
125   std::string getName(const T& _obj) const;
126 
127   /// Change the name of a currently held object. This will do nothing if the
128   /// object is already using _newName or if the object is not held by this
129   /// NameManager.
130   ///
131   /// If the object is held, its new name is returned (which might
132   /// be different than _newName if there was a duplicate naming conflict). If
133   /// the object is not held, an empty string will be returned.
134   std::string changeObjectName(const T& _obj, const std::string& _newName);
135 
136   /// Set the name that will be provided to objects passed in with an empty
137   /// string for a name
138   void setDefaultName(const std::string& _defaultName);
139 
140   /// Get the name that will be provided to objects passed in with an empty
141   /// string for a name
142   const std::string& getDefaultName() const;
143 
144   /// Set the name of this NameManager so that it can be printed in error
145   /// reports
146   void setManagerName(const std::string& _managerName);
147 
148   /// Get the name of this NameManager
149   const std::string& getManagerName() const;
150 
151 protected:
152   /// Name of this NameManager. This is used to report errors.
153   std::string mManagerName;
154 
155   /// Map of objects that have been added to the NameManager
156   std::map<std::string, T> mMap;
157 
158   /// Reverse map of objects that have been added to the NameManager
159   std::map<T, std::string> mReverseMap;
160 
161   /// String which will be used as a name for any object which is passed in with
162   /// an empty string name
163   std::string mDefaultName;
164 
165   /// Internal variable used to arrange the text when resolving duplicate names
166   bool mNameBeforeNumber;
167 
168   /// The chunk of text that gets prepended to a duplicate name
169   std::string mPrefix;
170 
171   /// The chunk of text that comes between a duplicate name and its duplication
172   /// number
173   std::string mInfix;
174 
175   /// The chunk of text that gets appended to a duplicate name
176   std::string mAffix;
177 };
178 
179 } // namespace common
180 } // namespace dart
181 
182 #include "dart/common/detail/NameManager.hpp"
183 
184 #endif // DART_COMMON_NAMEMANAGER_HPP_
185