Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/string/node_path.cpp
9903 views
1
/**************************************************************************/
2
/* node_path.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "node_path.h"
32
33
#include "core/variant/variant.h"
34
35
void NodePath::_update_hash_cache() const {
36
uint32_t h = data->absolute ? 1 : 0;
37
int pc = data->path.size();
38
const StringName *sn = data->path.ptr();
39
for (int i = 0; i < pc; i++) {
40
h = h ^ sn[i].hash();
41
}
42
int spc = data->subpath.size();
43
const StringName *ssn = data->subpath.ptr();
44
for (int i = 0; i < spc; i++) {
45
h = h ^ ssn[i].hash();
46
}
47
48
data->hash_cache_valid = true;
49
data->hash_cache = h;
50
}
51
52
void NodePath::prepend_period() {
53
if (data->path.size() && data->path[0].operator String() != ".") {
54
data->path.insert(0, ".");
55
data->hash_cache_valid = false;
56
}
57
}
58
59
bool NodePath::is_absolute() const {
60
if (!data) {
61
return false;
62
}
63
64
return data->absolute;
65
}
66
67
int NodePath::get_name_count() const {
68
if (!data) {
69
return 0;
70
}
71
72
return data->path.size();
73
}
74
75
StringName NodePath::get_name(int p_idx) const {
76
ERR_FAIL_NULL_V(data, StringName());
77
ERR_FAIL_INDEX_V(p_idx, data->path.size(), StringName());
78
return data->path[p_idx];
79
}
80
81
int NodePath::get_subname_count() const {
82
if (!data) {
83
return 0;
84
}
85
86
return data->subpath.size();
87
}
88
89
StringName NodePath::get_subname(int p_idx) const {
90
ERR_FAIL_NULL_V(data, StringName());
91
ERR_FAIL_INDEX_V(p_idx, data->subpath.size(), StringName());
92
return data->subpath[p_idx];
93
}
94
95
int NodePath::get_total_name_count() const {
96
if (!data) {
97
return 0;
98
}
99
100
return data->path.size() + data->subpath.size();
101
}
102
103
void NodePath::unref() {
104
if (data && data->refcount.unref()) {
105
memdelete(data);
106
}
107
data = nullptr;
108
}
109
110
bool NodePath::operator==(const NodePath &p_path) const {
111
if (data == p_path.data) {
112
return true;
113
}
114
115
if (!data || !p_path.data) {
116
return false;
117
}
118
119
if (data->absolute != p_path.data->absolute) {
120
return false;
121
}
122
123
int path_size = data->path.size();
124
125
if (path_size != p_path.data->path.size()) {
126
return false;
127
}
128
129
int subpath_size = data->subpath.size();
130
131
if (subpath_size != p_path.data->subpath.size()) {
132
return false;
133
}
134
135
const StringName *l_path_ptr = data->path.ptr();
136
const StringName *r_path_ptr = p_path.data->path.ptr();
137
138
for (int i = 0; i < path_size; i++) {
139
if (l_path_ptr[i] != r_path_ptr[i]) {
140
return false;
141
}
142
}
143
144
const StringName *l_subpath_ptr = data->subpath.ptr();
145
const StringName *r_subpath_ptr = p_path.data->subpath.ptr();
146
147
for (int i = 0; i < subpath_size; i++) {
148
if (l_subpath_ptr[i] != r_subpath_ptr[i]) {
149
return false;
150
}
151
}
152
153
return true;
154
}
155
156
bool NodePath::operator!=(const NodePath &p_path) const {
157
return (!(*this == p_path));
158
}
159
160
void NodePath::operator=(const NodePath &p_path) {
161
if (this == &p_path) {
162
return;
163
}
164
165
unref();
166
167
if (p_path.data && p_path.data->refcount.ref()) {
168
data = p_path.data;
169
}
170
}
171
172
NodePath::operator String() const {
173
if (!data) {
174
return String();
175
}
176
177
String ret;
178
if (data->absolute) {
179
ret = "/";
180
}
181
182
for (int i = 0; i < data->path.size(); i++) {
183
if (i > 0) {
184
ret += "/";
185
}
186
ret += data->path[i].operator String();
187
}
188
189
for (int i = 0; i < data->subpath.size(); i++) {
190
ret += ":" + data->subpath[i].operator String();
191
}
192
193
return ret;
194
}
195
196
Vector<StringName> NodePath::get_names() const {
197
if (data) {
198
return data->path;
199
}
200
return Vector<StringName>();
201
}
202
203
Vector<StringName> NodePath::get_subnames() const {
204
if (data) {
205
return data->subpath;
206
}
207
return Vector<StringName>();
208
}
209
210
StringName NodePath::get_concatenated_names() const {
211
ERR_FAIL_NULL_V(data, StringName());
212
213
if (!data->concatenated_path) {
214
int pc = data->path.size();
215
String concatenated;
216
const StringName *sn = data->path.ptr();
217
for (int i = 0; i < pc; i++) {
218
if (i > 0) {
219
concatenated += "/";
220
}
221
concatenated += sn[i].operator String();
222
}
223
data->concatenated_path = concatenated;
224
}
225
return data->concatenated_path;
226
}
227
228
StringName NodePath::get_concatenated_subnames() const {
229
ERR_FAIL_NULL_V(data, StringName());
230
231
if (!data->concatenated_subpath) {
232
int spc = data->subpath.size();
233
String concatenated;
234
const StringName *ssn = data->subpath.ptr();
235
for (int i = 0; i < spc; i++) {
236
if (i > 0) {
237
concatenated += ":";
238
}
239
concatenated += ssn[i].operator String();
240
}
241
data->concatenated_subpath = concatenated;
242
}
243
return data->concatenated_subpath;
244
}
245
246
NodePath NodePath::slice(int p_begin, int p_end) const {
247
const int name_count = get_name_count();
248
const int total_count = get_total_name_count();
249
250
int begin = CLAMP(p_begin, -total_count, total_count);
251
if (begin < 0) {
252
begin += total_count;
253
}
254
int end = CLAMP(p_end, -total_count, total_count);
255
if (end < 0) {
256
end += total_count;
257
}
258
const int sub_begin = MAX(begin - name_count, 0);
259
const int sub_end = MAX(end - name_count, 0);
260
261
const Vector<StringName> names = get_names().slice(begin, end);
262
const Vector<StringName> sub_names = get_subnames().slice(sub_begin, sub_end);
263
const bool absolute = is_absolute() && (begin == 0);
264
return NodePath(names, sub_names, absolute);
265
}
266
267
NodePath NodePath::rel_path_to(const NodePath &p_np) const {
268
ERR_FAIL_COND_V(!is_absolute(), NodePath());
269
ERR_FAIL_COND_V(!p_np.is_absolute(), NodePath());
270
271
Vector<StringName> src_dirs = get_names();
272
Vector<StringName> dst_dirs = p_np.get_names();
273
274
//find common parent
275
int common_parent = 0;
276
277
while (true) {
278
if (src_dirs.size() == common_parent) {
279
break;
280
}
281
if (dst_dirs.size() == common_parent) {
282
break;
283
}
284
if (src_dirs[common_parent] != dst_dirs[common_parent]) {
285
break;
286
}
287
common_parent++;
288
}
289
290
common_parent--;
291
292
Vector<StringName> relpath;
293
relpath.resize(src_dirs.size() + dst_dirs.size() + 1);
294
295
StringName *relpath_ptr = relpath.ptrw();
296
297
int path_size = 0;
298
StringName back_str("..");
299
for (int i = common_parent + 1; i < src_dirs.size(); i++) {
300
relpath_ptr[path_size++] = back_str;
301
}
302
303
for (int i = common_parent + 1; i < dst_dirs.size(); i++) {
304
relpath_ptr[path_size++] = dst_dirs[i];
305
}
306
307
if (path_size == 0) {
308
relpath_ptr[path_size++] = ".";
309
}
310
311
relpath.resize(path_size);
312
313
return NodePath(relpath, p_np.get_subnames(), false);
314
}
315
316
NodePath NodePath::get_as_property_path() const {
317
if (!data || !data->path.size()) {
318
return *this;
319
} else {
320
Vector<StringName> new_path = data->subpath;
321
322
String initial_subname = data->path[0];
323
324
for (int i = 1; i < data->path.size(); i++) {
325
initial_subname += "/" + data->path[i];
326
}
327
new_path.insert(0, initial_subname);
328
329
return NodePath(Vector<StringName>(), new_path, false);
330
}
331
}
332
333
bool NodePath::is_empty() const {
334
return !data;
335
}
336
337
void NodePath::simplify() {
338
if (!data) {
339
return;
340
}
341
for (int i = 0; i < data->path.size(); i++) {
342
if (data->path.size() == 1) {
343
break;
344
}
345
if (data->path[i].operator String() == ".") {
346
data->path.remove_at(i);
347
i--;
348
} else if (i > 0 && data->path[i].operator String() == ".." && data->path[i - 1].operator String() != "." && data->path[i - 1].operator String() != "..") {
349
//remove both
350
data->path.remove_at(i - 1);
351
data->path.remove_at(i - 1);
352
i -= 2;
353
if (data->path.is_empty()) {
354
data->path.push_back(".");
355
break;
356
}
357
}
358
}
359
data->hash_cache_valid = false;
360
}
361
362
NodePath NodePath::simplified() const {
363
NodePath np = *this;
364
np.simplify();
365
return np;
366
}
367
368
NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
369
if (p_path.is_empty() && !p_absolute) {
370
return;
371
}
372
373
data = memnew(Data);
374
data->refcount.init();
375
data->absolute = p_absolute;
376
data->path = p_path;
377
data->hash_cache_valid = false;
378
}
379
380
NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) {
381
if (p_path.is_empty() && p_subpath.is_empty() && !p_absolute) {
382
return;
383
}
384
385
data = memnew(Data);
386
data->refcount.init();
387
data->absolute = p_absolute;
388
data->path = p_path;
389
data->subpath = p_subpath;
390
data->hash_cache_valid = false;
391
}
392
393
NodePath::NodePath(const NodePath &p_path) {
394
if (p_path.data && p_path.data->refcount.ref()) {
395
data = p_path.data;
396
}
397
}
398
399
NodePath::NodePath(const String &p_path) {
400
if (p_path.length() == 0) {
401
return;
402
}
403
404
String path = p_path;
405
Vector<StringName> subpath;
406
407
bool absolute = (path[0] == '/');
408
bool last_is_slash = true;
409
int slices = 0;
410
int subpath_pos = path.find_char(':');
411
412
if (subpath_pos != -1) {
413
int from = subpath_pos + 1;
414
415
for (int i = from; i <= path.length(); i++) {
416
if (path[i] == ':' || path[i] == 0) {
417
String str = path.substr(from, i - from);
418
if (str.is_empty()) {
419
if (path[i] == 0) {
420
continue; // Allow end-of-path :
421
}
422
423
ERR_FAIL_MSG(vformat("Invalid NodePath '%s'.", p_path));
424
}
425
subpath.push_back(str);
426
427
from = i + 1;
428
}
429
}
430
431
path = path.substr(0, subpath_pos);
432
}
433
434
for (int i = (int)absolute; i < path.length(); i++) {
435
if (path[i] == '/') {
436
last_is_slash = true;
437
} else {
438
if (last_is_slash) {
439
slices++;
440
}
441
442
last_is_slash = false;
443
}
444
}
445
446
if (slices == 0 && !absolute && !subpath.size()) {
447
return;
448
}
449
450
data = memnew(Data);
451
data->refcount.init();
452
data->absolute = absolute;
453
data->subpath = subpath;
454
data->hash_cache_valid = false;
455
456
if (slices == 0) {
457
return;
458
}
459
data->path.resize(slices);
460
last_is_slash = true;
461
int from = (int)absolute;
462
int slice = 0;
463
464
for (int i = (int)absolute; i < path.length() + 1; i++) {
465
if (path[i] == '/' || path[i] == 0) {
466
if (!last_is_slash) {
467
String name = path.substr(from, i - from);
468
ERR_FAIL_INDEX(slice, data->path.size());
469
data->path.write[slice++] = name;
470
}
471
from = i + 1;
472
last_is_slash = true;
473
} else {
474
last_is_slash = false;
475
}
476
}
477
}
478
479
NodePath::~NodePath() {
480
unref();
481
}
482
483