BLI: Add std::string variant of BLI_uniquename_cb
Allows to ensure unique name for cases when name is a dynamically sized string. Pull Request: https://projects.blender.org/blender/blender/pulls/114052
This commit is contained in:
committed by
Sergey Sharybin
parent
7ba92a2a2f
commit
7afa5aaa59
@@ -9,8 +9,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "BLI_compiler_attrs.h"
|
#include "BLI_compiler_attrs.h"
|
||||||
|
#include "BLI_function_ref.hh"
|
||||||
|
#include "BLI_string_ref.hh"
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
struct ListBase;
|
struct ListBase;
|
||||||
@@ -153,6 +156,18 @@ void BLI_uniquename_cb(UniquenameCheckCallback unique_check,
|
|||||||
char delim,
|
char delim,
|
||||||
char *name,
|
char *name,
|
||||||
size_t name_maxncpy) ATTR_NONNULL(1, 3, 5);
|
size_t name_maxncpy) ATTR_NONNULL(1, 3, 5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures name is unique (according to criteria specified by caller in unique_check callback),
|
||||||
|
* incrementing its numeric suffix as necessary.
|
||||||
|
*
|
||||||
|
* \param unique_check: Return true if name is not unique
|
||||||
|
* \param delim: Delimits numeric suffix in name
|
||||||
|
* \param name: Name to be ensured unique
|
||||||
|
*/
|
||||||
|
std::string BLI_uniquename_cb(blender::FunctionRef<bool(blender::StringRef)> unique_check,
|
||||||
|
char delim,
|
||||||
|
blender::StringRef name);
|
||||||
/**
|
/**
|
||||||
* Ensures that the specified block has a unique name within the containing list,
|
* Ensures that the specified block has a unique name within the containing list,
|
||||||
* incrementing its numeric suffix as necessary.
|
* incrementing its numeric suffix as necessary.
|
||||||
|
|||||||
@@ -550,6 +550,7 @@ if(WITH_GTESTS)
|
|||||||
tests/BLI_string_search_test.cc
|
tests/BLI_string_search_test.cc
|
||||||
tests/BLI_string_test.cc
|
tests/BLI_string_test.cc
|
||||||
tests/BLI_string_utf8_test.cc
|
tests/BLI_string_utf8_test.cc
|
||||||
|
tests/BLI_string_utils_test.cc
|
||||||
tests/BLI_task_graph_test.cc
|
tests/BLI_task_graph_test.cc
|
||||||
tests/BLI_task_test.cc
|
tests/BLI_task_test.cc
|
||||||
tests/BLI_tempfile_test.cc
|
tests/BLI_tempfile_test.cc
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
|
|
||||||
|
#include "BLI_array.hh"
|
||||||
#include "BLI_string.h"
|
#include "BLI_string.h"
|
||||||
#include "BLI_string_utf8.h"
|
#include "BLI_string_utf8.h"
|
||||||
#include "BLI_string_utils.hh"
|
#include "BLI_string_utils.hh"
|
||||||
@@ -424,6 +427,38 @@ void BLI_uniquename_cb(UniquenameCheckCallback unique_check,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string BLI_uniquename_cb(blender::FunctionRef<bool(blender::StringRef)> unique_check,
|
||||||
|
const char delim,
|
||||||
|
const blender::StringRef name)
|
||||||
|
{
|
||||||
|
std::string new_name = name;
|
||||||
|
|
||||||
|
if (!unique_check(new_name)) {
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int number;
|
||||||
|
blender::Array<char> left_buffer(new_name.size() + 1);
|
||||||
|
const size_t len = BLI_string_split_name_number(
|
||||||
|
new_name.c_str(), delim, left_buffer.data(), &number);
|
||||||
|
|
||||||
|
const std::string left = left_buffer.data();
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::array<char, 16> num_str;
|
||||||
|
BLI_snprintf(num_str.data(), num_str.size(), "%c%03d", delim, ++number);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
new_name = num_str.data();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_name = left + num_str.data();
|
||||||
|
}
|
||||||
|
} while (unique_check(new_name));
|
||||||
|
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic function to set a unique name. It is only designed to be used in situations
|
* Generic function to set a unique name. It is only designed to be used in situations
|
||||||
* where the name is part of the struct.
|
* where the name is part of the struct.
|
||||||
|
|||||||
81
source/blender/blenlib/tests/BLI_string_utils_test.cc
Normal file
81
source/blender/blenlib/tests/BLI_string_utils_test.cc
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 */
|
||||||
|
|
||||||
|
#include "BLI_string_utils.hh"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
|
namespace blender {
|
||||||
|
|
||||||
|
static bool unique_check_func(void *arg, const char *name)
|
||||||
|
{
|
||||||
|
const Vector<std::string> *current_names = static_cast<const Vector<std::string> *>(arg);
|
||||||
|
return current_names->contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BLI_string_utils, BLI_uniquename_cb)
|
||||||
|
{
|
||||||
|
const Vector<std::string> current_names{"Foo", "Bar", "Bar.003", "Baz.001", "Big.999"};
|
||||||
|
|
||||||
|
/* C version. */
|
||||||
|
{
|
||||||
|
void *arg = const_cast<void *>(static_cast<const void *>(¤t_names));
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Default Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "Baz";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "Foo";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Foo.001");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "Baz.001";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Baz.002");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "Bar.003";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Bar.004");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char name[64] = "Big.999";
|
||||||
|
BLI_uniquename_cb(unique_check_func, arg, "Default Name", '.', name, sizeof(name));
|
||||||
|
EXPECT_STREQ(name, "Big.1000");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C++ version. */
|
||||||
|
{
|
||||||
|
const auto unique_check = [&](const blender::StringRef name) -> bool {
|
||||||
|
return current_names.contains(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', ""), "");
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', "Baz"), "Baz");
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', "Foo"), "Foo.001");
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', "Baz.001"), "Baz.002");
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', "Bar.003"), "Bar.004");
|
||||||
|
EXPECT_EQ(BLI_uniquename_cb(unique_check, '.', "Big.999"), "Big.1000");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender
|
||||||
Reference in New Issue
Block a user