Skip to content

Commit 6d23d77

Browse files
konardclaude
andcommitted
Use safe specialization for C++ functors
Replace unsafe std namespace specializations with safe template specialization syntax: - Changed from 'namespace std { template<...> struct hash<Type> {...} }' - To 'template<...> struct std::hash<Type> {...}' This addresses issue #63 by using the safer approach that avoids namespace pollution and ADL issues. Changes made in both C# and Python implementations: - CSharpToCppTransformer.cs: Updated regex to generate safe syntax - cs2cpp.py: Updated SubRule to generate safe syntax - Added test case to verify the transformation works correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 70a8bff commit 6d23d77

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,34 @@ public static void Main(string[] args)
3535
var actualResult = transformer.Transform(helloWorldCode);
3636
Assert.Equal(expectedResult, actualResult);
3737
}
38+
39+
[Fact]
40+
public void SafeHashSpecializationTest()
41+
{
42+
const string inputCode = @"
43+
namespace Platform.Ranges
44+
{
45+
template <typename T> struct Range
46+
{
47+
T Minimum;
48+
T Maximum;
49+
50+
public: override std::int32_t GetHashCode()
51+
{
52+
return {Minimum, Maximum}.GetHashCode();
53+
}
54+
};
55+
}";
56+
var transformer = new CSharpToCppTransformer();
57+
var actualResult = transformer.Transform(inputCode);
58+
59+
// Should generate safe specialization syntax
60+
Assert.Contains("template <typename T>", actualResult);
61+
Assert.Contains("struct std::hash<Platform::Ranges::Range<T>>", actualResult);
62+
63+
// Should NOT contain unsafe namespace std opening
64+
Assert.DoesNotContain("namespace std\n{", actualResult);
65+
Assert.DoesNotContain("namespace std {", actualResult);
66+
}
3867
}
3968
}

csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,8 @@ public class CSharpToCppTransformer : TextTransformer
578578
(new Regex(@"(?<classDeclarationBegin>\r?\n(?<indent>[\t ]*)template <typename (?<typeParameter>[^\n]+)> (struct|class) (?<type>[a-zA-Z0-9]+<\k<typeParameter>>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?<middle>(.|\n)*)(?<endIndent>(?<=\r?\n)\k<indent>)(?<end>};)"), "${classDeclarationBegin}/*~start~type~${type}~${typeParameter}~*/${middle}${endIndent}/*~end~type~${type}~${typeParameter}~*/${end}", 0),
579579
// Inside the scope replace:
580580
// /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/
581-
// /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template <typename T> struct hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; }
582-
(new Regex(@"(?<namespaceScopeStart>/\*~start~namespace~(?<namespace>[^~\n\*]+)~\*/)(?<betweenStartScopes>(.|\n)+)(?<typeScopeStart>/\*~start~type~(?<type>[^~\n\*]+)~(?<typeParameter>[^~\n\*]+)~\*/)(?<before>(.|\n)+?)(?<hashMethodDeclaration>\r?\n[ \t]*(?<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?<after>(.|\n)+?)(?<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?<betweenEndScopes>(.|\n)+)(?<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "namespace std" + Environment.NewLine + "{" + Environment.NewLine + " template <typename ${typeParameter}>" + Environment.NewLine + " struct hash<${namespace}::${type}>" + Environment.NewLine + " {" + Environment.NewLine + " std::size_t operator()(const ${namespace}::${type} &obj) const" + Environment.NewLine + " {" + Environment.NewLine + " /*~start~method~*/${methodBody}/*~end~method~*/" + Environment.NewLine + " }" + Environment.NewLine + " };" + Environment.NewLine + "}" + Environment.NewLine, 10),
581+
// /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template <typename T> struct std::hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } };
582+
(new Regex(@"(?<namespaceScopeStart>/\*~start~namespace~(?<namespace>[^~\n\*]+)~\*/)(?<betweenStartScopes>(.|\n)+)(?<typeScopeStart>/\*~start~type~(?<type>[^~\n\*]+)~(?<typeParameter>[^~\n\*]+)~\*/)(?<before>(.|\n)+?)(?<hashMethodDeclaration>\r?\n[ \t]*(?<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?<after>(.|\n)+?)(?<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?<betweenEndScopes>(.|\n)+)(?<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "template <typename ${typeParameter}>" + Environment.NewLine + "struct std::hash<${namespace}::${type}>" + Environment.NewLine + "{" + Environment.NewLine + " std::size_t operator()(const ${namespace}::${type} &obj) const" + Environment.NewLine + " {" + Environment.NewLine + " /*~start~method~*/${methodBody}/*~end~method~*/" + Environment.NewLine + " }" + Environment.NewLine + "};" + Environment.NewLine, 10),
583583
// Inside scope of /*~start~method~*/ replace:
584584
// /*~start~method~*/ ... Minimum ... /*~end~method~*/
585585
// /*~start~method~*/ ... obj.Minimum ... /*~end~method~*/

python/cs2cpp/cs2cpp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,8 @@ def __init__(
577577
SubRule(r"(?P<classDeclarationBegin>\r?\n(?P<indent>[\t ]*)template <typename (?P<typeParameter>[^\n]+)> (struct|class) (?P<type>[a-zA-Z0-9]+<\k<typeParameter>>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?P<middle>(.|\n)*)(?P<endIndent>(?<=\r?\n)\k<indent>)(?P<end>};)", r"\g<classDeclarationBegin>/*~start~type~\g<type>~\g<typeParameter>~*/\g<middle>\g<endIndent>/*~end~type~\g<type>~\g<typeParameter>~*/\g<end>", max_repeat=0),
578578
# Inside the scope replace:
579579
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/
580-
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template <typename T> struct hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; }
581-
SubRule(r"(?P<namespaceScopeStart>/\*~start~namespace~(?P<namespace>[^~\n\*]+)~\*/)(?P<betweenStartScopes>(.|\n)+)(?P<typeScopeStart>/\*~start~type~(?P<type>[^~\n\*]+)~(?P<typeParameter>[^~\n\*]+)~\*/)(?P<before>(.|\n)+?)(?P<hashMethodDeclaration>\r?\n[ \t]*(?P<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?P<after>(.|\n)+?)(?P<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?P<betweenEndScopes>(.|\n)+)(?P<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n", r"\g<namespaceScopeStart>\g<betweenStartScopes>\g<typeScopeStart>\g<before>\g<after>\g<typeScopeEnd>\g<betweenEndScopes>\g<namespaceScopeEnd>}\n" + "\nnamespace std\n" + "{\n" + " template <typename \g<typeParameter>>\n" + " struct hash<\g<namespace>::\g<type>>\n" + " {\n" + " std::size_t operator()(const \g<namespace>::\g<type> &obj) const\n" + " {\n" + " /*~start~method~*/\g<methodBody>/*~end~method~*/\n" + " }\n" + " };\n" + "}\n", max_repeat=10),
580+
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template <typename T> struct std::hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } };
581+
SubRule(r"(?P<namespaceScopeStart>/\*~start~namespace~(?P<namespace>[^~\n\*]+)~\*/)(?P<betweenStartScopes>(.|\n)+)(?P<typeScopeStart>/\*~start~type~(?P<type>[^~\n\*]+)~(?P<typeParameter>[^~\n\*]+)~\*/)(?P<before>(.|\n)+?)(?P<hashMethodDeclaration>\r?\n[ \t]*(?P<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?P<after>(.|\n)+?)(?P<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?P<betweenEndScopes>(.|\n)+)(?P<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n", r"\g<namespaceScopeStart>\g<betweenStartScopes>\g<typeScopeStart>\g<before>\g<after>\g<typeScopeEnd>\g<betweenEndScopes>\g<namespaceScopeEnd>}\n" + "\ntemplate <typename \g<typeParameter>>\n" + "struct std::hash<\g<namespace>::\g<type>>\n" + "{\n" + " std::size_t operator()(const \g<namespace>::\g<type> &obj) const\n" + " {\n" + " /*~start~method~*/\g<methodBody>/*~end~method~*/\n" + " }\n" + "};\n", max_repeat=10),
582582
# Inside scope of /*~start~method~*/ replace:
583583
# /*~start~method~*/ ... Minimum ... /*~end~method~*/
584584
# /*~start~method~*/ ... obj.Minimum ... /*~end~method~*/

0 commit comments

Comments
 (0)