Fix Build.builder.feature() for Java bindings (#9517)

The "const char*" used for the string literal parameter of the `feature`
method becomes invalid once it passes outside the Java binding scope,
leading to invalid data access. This fix ensures the string is safely
stored.

Add support for heterogeneous lookup in associative containers that
use CString keys. Add conversion operators for std::string_view and
raw string literals to CString.
This commit is contained in:
Sungun Park
2025-12-15 13:04:36 -08:00
committed by GitHub
parent a3708b2616
commit 05f24516dd
6 changed files with 223 additions and 31 deletions

View File

@@ -22,6 +22,7 @@
#include <climits>
#include <utility>
#include <type_traits>
#include <unordered_set>
using namespace utils;
@@ -242,7 +243,7 @@ TEST(CString, Concatenation) {
}
}
TEST(CString, Comparison) {
TEST(CString, ComparisonCString) {
CString s1("abc");
CString s2("abc");
CString s3("def");
@@ -272,6 +273,106 @@ TEST(CString, Comparison) {
EXPECT_TRUE(s1 > s4);
}
TEST(CString, ComparisonStringView) {
const CString CS1("abc");
const CString CS2("abc");
const CString CS3("def");
const CString CS4("ab");
const std::string_view sv1("abc");
const std::string_view sv2("abc");
const std::string_view sv3("def");
const std::string_view sv4("ab");
EXPECT_TRUE(CS1 == sv2);
EXPECT_TRUE(sv2 == CS1);
EXPECT_FALSE(CS1 == sv3);
EXPECT_FALSE(sv3 == CS1);
EXPECT_TRUE(CS1 != sv3);
EXPECT_TRUE(sv3 != CS1);
EXPECT_FALSE(CS1 != sv2);
EXPECT_FALSE(sv2 != CS1);
EXPECT_TRUE(CS1 < sv3);
EXPECT_TRUE(sv1 < CS3);
EXPECT_FALSE(CS3 < sv1);
EXPECT_FALSE(sv3 < CS1);
EXPECT_TRUE(CS3 > sv1);
EXPECT_TRUE(sv3 > CS1);
EXPECT_FALSE(CS1 > sv3);
EXPECT_FALSE(sv1 > CS3);
EXPECT_TRUE(CS1 <= sv2);
EXPECT_TRUE(sv1 <= CS2);
EXPECT_TRUE(CS1 <= sv3);
EXPECT_TRUE(sv1 <= CS3);
EXPECT_FALSE(CS3 <= sv1);
EXPECT_FALSE(sv3 <= CS1);
EXPECT_TRUE(CS2 >= sv1);
EXPECT_TRUE(sv2 >= CS1);
EXPECT_TRUE(CS3 >= sv1);
EXPECT_TRUE(sv3 >= CS1);
EXPECT_FALSE(CS1 >= sv3);
EXPECT_FALSE(sv1 >= CS3);
EXPECT_TRUE(CS4 < sv1);
EXPECT_TRUE(sv4 < CS1);
EXPECT_TRUE(CS1 > sv4);
EXPECT_TRUE(sv1 > CS4);
}
TEST(CString, ComparisonStringLiteral) {
const CString CS1("abc");
const CString CS2("abc");
const CString CS3("def");
const CString CS4("ab");
const char* sv1("abc");
const char* sv2("abc");
const char* sv3("def");
const char* sv4("ab");
EXPECT_TRUE(CS1 == sv2);
EXPECT_TRUE(sv2 == CS1);
EXPECT_FALSE(CS1 == sv3);
EXPECT_FALSE(sv3 == CS1);
EXPECT_TRUE(CS1 != sv3);
EXPECT_TRUE(sv3 != CS1);
EXPECT_FALSE(CS1 != sv2);
EXPECT_FALSE(sv2 != CS1);
EXPECT_TRUE(CS1 < sv3);
EXPECT_TRUE(sv1 < CS3);
EXPECT_FALSE(CS3 < sv1);
EXPECT_FALSE(sv3 < CS1);
EXPECT_TRUE(CS3 > sv1);
EXPECT_TRUE(sv3 > CS1);
EXPECT_FALSE(CS1 > sv3);
EXPECT_FALSE(sv1 > CS3);
EXPECT_TRUE(CS1 <= sv2);
EXPECT_TRUE(sv1 <= CS2);
EXPECT_TRUE(CS1 <= sv3);
EXPECT_TRUE(sv1 <= CS3);
EXPECT_FALSE(CS3 <= sv1);
EXPECT_FALSE(sv3 <= CS1);
EXPECT_TRUE(CS2 >= sv1);
EXPECT_TRUE(sv2 >= CS1);
EXPECT_TRUE(CS3 >= sv1);
EXPECT_TRUE(sv3 >= CS1);
EXPECT_FALSE(CS1 >= sv3);
EXPECT_FALSE(sv1 >= CS3);
EXPECT_TRUE(CS4 < sv1);
EXPECT_TRUE(sv4 < CS1);
EXPECT_TRUE(CS1 > sv4);
EXPECT_TRUE(sv1 > CS4);
}
TEST(CString, ElementAccess) {
CString str("01234");
const CString cstr("const");
@@ -595,6 +696,31 @@ TEST(CString, ToString) {
EXPECT_STREQ("-3.140000", to_string(-3.14f).c_str());
}
TEST(CString, HeterogeneousLookupForContainer) {
std::unordered_set<CString> us;
const char* world("world");
const std::string_view filament("filament");
const CString unittest("unittest");
EXPECT_TRUE(us.insert("hello").second);
EXPECT_TRUE(us.insert(CString(world)).second); // or emplace(world)
EXPECT_TRUE(us.insert(CString(filament)).second); // or emplace(filament)
EXPECT_TRUE(us.insert(unittest).second);
auto it = us.find("hello");
EXPECT_NE(it, us.end());
it = us.find(world);
EXPECT_NE(it, us.end());
it = us.find(filament);
EXPECT_NE(it, us.end());
it = us.find(unittest);
EXPECT_NE(it, us.end());
it = us.find("invalid key");
EXPECT_EQ(it, us.end());
}
TEST(FixedSizeString, EmptyString) {
{
FixedSizeString<32> str;