/src/assimp/code/AssetLib/MDL/HalfLife/UniqueNameGenerator.cpp
Line | Count | Source |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2025, assimp team |
7 | | |
8 | | All rights reserved. |
9 | | |
10 | | Redistribution and use of this software in source and binary forms, |
11 | | with or without modification, are permitted provided that the following |
12 | | conditions are met: |
13 | | |
14 | | * Redistributions of source code must retain the above |
15 | | copyright notice, this list of conditions and the |
16 | | following disclaimer. |
17 | | |
18 | | * Redistributions in binary form must reproduce the above |
19 | | copyright notice, this list of conditions and the |
20 | | following disclaimer in the documentation and/or other |
21 | | materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the assimp team, nor the names of its |
24 | | contributors may be used to endorse or promote products |
25 | | derived from this software without specific prior |
26 | | written permission of the assimp team. |
27 | | |
28 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | | --------------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file UniqueNameGenerator.cpp |
43 | | * @brief Implementation for the unique name generator. |
44 | | */ |
45 | | |
46 | | #include "UniqueNameGenerator.h" |
47 | | #include <algorithm> |
48 | | #include <list> |
49 | | #include <map> |
50 | | #include <numeric> |
51 | | |
52 | | namespace Assimp { |
53 | | namespace MDL { |
54 | | namespace HalfLife { |
55 | | |
56 | | UniqueNameGenerator::UniqueNameGenerator() : |
57 | 0 | template_name_("unnamed"), |
58 | 0 | separator_("_") { |
59 | 0 | } |
60 | | |
61 | | UniqueNameGenerator::UniqueNameGenerator(const char *template_name) : |
62 | 0 | template_name_(template_name), |
63 | 0 | separator_("_") { |
64 | 0 | } |
65 | | |
66 | | UniqueNameGenerator::UniqueNameGenerator(const char *template_name, const char *separator) : |
67 | 0 | template_name_(template_name), |
68 | 0 | separator_(separator) { |
69 | 0 | } |
70 | | |
71 | 0 | UniqueNameGenerator::~UniqueNameGenerator() = default; |
72 | | |
73 | 0 | void UniqueNameGenerator::make_unique(std::vector<std::string> &names) { |
74 | 0 | struct DuplicateInfo { |
75 | 0 | DuplicateInfo() : |
76 | 0 | indices(), |
77 | 0 | next_id(0) { |
78 | 0 | } |
79 | |
|
80 | 0 | std::list<size_t> indices; |
81 | 0 | size_t next_id; |
82 | 0 | }; |
83 | |
|
84 | 0 | std::vector<size_t> empty_names_indices; |
85 | 0 | std::vector<size_t> template_name_duplicates; |
86 | 0 | std::map<std::string, DuplicateInfo> names_to_duplicates; |
87 | |
|
88 | 0 | const std::string template_name_with_separator(template_name_ + separator_); |
89 | |
|
90 | 0 | auto format_name = [&](const std::string &base_name, size_t id) -> std::string { |
91 | 0 | return base_name + separator_ + std::to_string(id); |
92 | 0 | }; |
93 | |
|
94 | 0 | auto generate_unique_name = [&](const std::string &base_name) -> std::string { |
95 | 0 | auto *duplicate_info = &names_to_duplicates[base_name]; |
96 | |
|
97 | 0 | std::string new_name; |
98 | |
|
99 | 0 | bool found_identical_name; |
100 | 0 | bool tried_with_base_name_only = false; |
101 | 0 | do { |
102 | | // Assume that no identical name exists. |
103 | 0 | found_identical_name = false; |
104 | |
|
105 | 0 | if (!tried_with_base_name_only) { |
106 | | // First try with only the base name. |
107 | 0 | new_name = base_name; |
108 | 0 | } else { |
109 | | // Create the name expected to be unique. |
110 | 0 | new_name = format_name(base_name, duplicate_info->next_id); |
111 | 0 | } |
112 | | |
113 | | // Check in the list of duplicates for an identical name. |
114 | 0 | for (size_t i = 0; |
115 | 0 | i < names.size() && |
116 | 0 | !found_identical_name; |
117 | 0 | ++i) { |
118 | 0 | if (new_name == names[i]) |
119 | 0 | found_identical_name = true; |
120 | 0 | } |
121 | |
|
122 | 0 | if (tried_with_base_name_only) |
123 | 0 | ++duplicate_info->next_id; |
124 | |
|
125 | 0 | tried_with_base_name_only = true; |
126 | |
|
127 | 0 | } while (found_identical_name); |
128 | |
|
129 | 0 | return new_name; |
130 | 0 | }; |
131 | |
|
132 | 0 | for (size_t i = 0; i < names.size(); ++i) { |
133 | | // Check for empty names. |
134 | 0 | if (names[i].find_first_not_of(' ') == std::string::npos) { |
135 | 0 | empty_names_indices.push_back(i); |
136 | 0 | continue; |
137 | 0 | } |
138 | | |
139 | | /* Check for potential duplicate. |
140 | | a) Either if this name is the same as the template name or |
141 | | b) <template name><separator> is found at the beginning. */ |
142 | 0 | if (names[i] == template_name_ || |
143 | 0 | names[i].substr(0, template_name_with_separator.length()) == template_name_with_separator) |
144 | 0 | template_name_duplicates.push_back(i); |
145 | | |
146 | | // Map each unique name to it's duplicate. |
147 | 0 | if (names_to_duplicates.count(names[i]) == 0) |
148 | 0 | names_to_duplicates.insert({ names[i], DuplicateInfo()}); |
149 | 0 | else |
150 | 0 | names_to_duplicates[names[i]].indices.push_back(i); |
151 | 0 | } |
152 | | |
153 | | // Make every non-empty name unique. |
154 | 0 | for (auto it = names_to_duplicates.begin(); |
155 | 0 | it != names_to_duplicates.end(); ++it) { |
156 | 0 | for (auto it2 = it->second.indices.begin(); |
157 | 0 | it2 != it->second.indices.end(); |
158 | 0 | ++it2) |
159 | 0 | names[*it2] = generate_unique_name(it->first); |
160 | 0 | } |
161 | | |
162 | | // Generate a unique name for every empty string. |
163 | 0 | if (template_name_duplicates.size()) { |
164 | | // At least one string ressembles to <template name>. |
165 | 0 | for (auto it = empty_names_indices.begin(); |
166 | 0 | it != empty_names_indices.end(); ++it) |
167 | 0 | names[*it] = generate_unique_name(template_name_); |
168 | 0 | } else { |
169 | | // No string alike <template name> exists. |
170 | 0 | size_t i = 0; |
171 | 0 | for (auto it = empty_names_indices.begin(); |
172 | 0 | it != empty_names_indices.end(); ++it, ++i) |
173 | 0 | names[*it] = format_name(template_name_, i); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | } // namespace HalfLife |
178 | | } // namespace MDL |
179 | | } // namespace Assimp |