Browse Source

Initial std::string_view support

pg
josetr 3 years ago
parent
commit
b1c6e07476
  1. 27
      src/AST/TypeExtensions.cs
  2. 11
      src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/Std-symbols.cpp
  3. 2
      src/CppParser/Parser.cpp
  4. 16
      src/Generator/Generators/CSharp/CSharpSources.cs
  5. 6
      src/Generator/Passes/IgnoreSystemDeclarationsPass.cs
  6. 98
      src/Generator/Types/Std/Stdlib.CSharp.cs

27
src/AST/TypeExtensions.cs

@ -1,5 +1,7 @@
namespace CppSharp.AST.Extensions namespace CppSharp.AST.Extensions
{ {
using System.Collections.Generic;
public static class TypeExtensions public static class TypeExtensions
{ {
public static bool IsPrimitiveType(this Type t) public static bool IsPrimitiveType(this Type t)
@ -442,5 +444,30 @@
{ {
return array.Size * array.ElementSize; return array.Size * array.ElementSize;
} }
public static string GetQualifiedName(this ClassTemplateSpecialization specialization)
{
var declContext = specialization.TemplatedDecl.TemplatedDecl;
var names = new Stack<string>();
while (!(declContext is TranslationUnit))
{
var isInlineNamespace = declContext is Namespace && ((Namespace)declContext).IsInline;
if (!isInlineNamespace)
names.Push(declContext.Name);
declContext = declContext.Namespace;
}
var qualifiedBasicString = string.Join(".", names);
return $"global::{qualifiedBasicString}";
}
public static ClassTemplateSpecialization GetClassTemplateSpecialization(this Type type)
{
var desugared = type.Desugar();
var template = (desugared.GetFinalPointee() ?? desugared).Desugar();
var templateSpecializationType = template as TemplateSpecializationType;
if (templateSpecializationType != null)
return templateSpecializationType.GetClassTemplateSpecialization();
return (ClassTemplateSpecialization)((TagType)template).Declaration;
}
} }
} }

11
src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/Std-symbols.cpp

@ -7,5 +7,12 @@
template __declspec(dllexport) std::allocator<char>::allocator() noexcept; template __declspec(dllexport) std::allocator<char>::allocator() noexcept;
template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>>::basic_string() noexcept(true); template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>>::basic_string() noexcept(true);
template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string() noexcept; template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string() noexcept;
template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>>& std::basic_string<char, std::char_traits<char>, std::allocator<char>>::assign(const char* const); template __declspec(dllexport) std::basic_string<char, std::char_traits<char>, std::allocator<char>> &std::basic_string<char, std::char_traits<char>, std::allocator<char>>::assign(const char *const);
template __declspec(dllexport) const char* std::basic_string<char, std::char_traits<char>, std::allocator<char>>::data() const noexcept; template __declspec(dllexport) const char *std::basic_string<char, std::char_traits<char>, std::allocator<char>>::data() const noexcept;
template __declspec(dllexport) char *std::basic_string<char, std::char_traits<char>, std::allocator<char>>::data() noexcept;
using sv = std::basic_string_view<char, std::char_traits<char>>;
template __declspec(dllexport) sv::basic_string_view(sv::const_pointer data, sv::size_type size) noexcept(true);
template __declspec(dllexport) sv::basic_string_view() noexcept(true);
template __declspec(dllexport) const char *sv::data() const noexcept;

2
src/CppParser/Parser.cpp

@ -77,6 +77,7 @@ Parser::Parser(CppParserOptions* Opts) : opts(Opts), index(0)
supportedStdTypes.insert(SupportedStdType); supportedStdTypes.insert(SupportedStdType);
supportedStdTypes.insert("allocator"); supportedStdTypes.insert("allocator");
supportedStdTypes.insert("basic_string"); supportedStdTypes.insert("basic_string");
supportedStdTypes.insert("basic_string_view");
} }
LayoutField Parser::WalkVTablePointer(Class* Class, LayoutField Parser::WalkVTablePointer(Class* Class,
@ -918,6 +919,7 @@ bool Parser::IsSupported(const clang::CXXMethodDecl* MD)
using namespace clang; using namespace clang;
return !c->getSourceManager().isInSystemHeader(MD->getBeginLoc()) || return !c->getSourceManager().isInSystemHeader(MD->getBeginLoc()) ||
(llvm::isa<clang::CXXConstructorDecl>(MD) && (MD->getNumParams() == 0 || MD->getParent()->getName() == "basic_string_view")) ||
(isa<CXXConstructorDecl>(MD) && MD->getNumParams() == 0) || (isa<CXXConstructorDecl>(MD) && MD->getNumParams() == 0) ||
isa<CXXDestructorDecl>(MD) || isa<CXXDestructorDecl>(MD) ||
(MD->getDeclName().isIdentifier() && (MD->getDeclName().isIdentifier() &&

16
src/Generator/Generators/CSharp/CSharpSources.cs

@ -3,13 +3,11 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Permissions;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Extensions; using CppSharp.Extensions;
using CppSharp.Parser;
using CppSharp.Types; using CppSharp.Types;
using CppSharp.Utils; using CppSharp.Utils;
using Attribute = CppSharp.AST.Attribute; using Attribute = CppSharp.AST.Attribute;
@ -635,6 +633,12 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
foreach (var function in functions) foreach (var function in functions)
GenerateInternalFunction(function); GenerateInternalFunction(function);
if (@class.QualifiedName == "Std::BasicStringViewExtensions")
{
foreach (var function in functions.Where(x => x.Name == "BasicStringView"))
GenerateInternalFunction(function, false);
}
} }
TypePrinter.PopContext(); TypePrinter.PopContext();
@ -747,14 +751,14 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
} }
} }
private IEnumerable<string> GatherInternalParams(Function function, out TypePrinterResult retType) private IEnumerable<string> GatherInternalParams(Function function, out TypePrinterResult retType, bool marshalParams = true)
{ {
TypePrinter.PushContext(TypePrinterContextKind.Native); TypePrinter.PushContext(TypePrinterContextKind.Native);
retType = function.ReturnType.Visit(TypePrinter); retType = function.ReturnType.Visit(TypePrinter);
var @params = function.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi).Select(p => var @params = function.GatherInternalParams(Context.ParserOptions.IsItaniumLikeAbi).Select(p =>
$"{p.Visit(TypePrinter)} {p.Name}").ToList(); $"{(marshalParams ? p.Visit(TypePrinter) : p.Type.Desugar().ToString())} {p.Name}").ToList();
TypePrinter.PopContext(); TypePrinter.PopContext();
@ -3497,7 +3501,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
return identifier.ToString(); return identifier.ToString();
} }
public void GenerateInternalFunction(Function function) public void GenerateInternalFunction(Function function, bool marshalParams = true)
{ {
if (function.IsPure) if (function.IsPure)
return; return;
@ -3514,7 +3518,7 @@ internal static{(@new ? " new" : string.Empty)} {printedClass} __GetInstance({Ty
WriteLine("[return: MarshalAs(UnmanagedType.I1)]"); WriteLine("[return: MarshalAs(UnmanagedType.I1)]");
TypePrinterResult retType; TypePrinterResult retType;
var @params = GatherInternalParams(function, out retType); var @params = GatherInternalParams(function, out retType, marshalParams);
WriteLine("internal static extern {0} {1}({2});", retType, WriteLine("internal static extern {0} {1}({2});", retType,
GetFunctionNativeIdentifier(function), GetFunctionNativeIdentifier(function),

6
src/Generator/Passes/IgnoreSystemDeclarationsPass.cs

@ -38,12 +38,16 @@ namespace CppSharp.Passes
foreach (var specialization in @class.Specializations.Where(s => s.IsGenerated)) foreach (var specialization in @class.Specializations.Where(s => s.IsGenerated))
specialization.ExplicitlyIgnore(); specialization.ExplicitlyIgnore();
if (@class.Name == "basic_string_view")
@class.Type = ClassType.ValueType;
// we only need a few members for marshalling so strip the rest // we only need a few members for marshalling so strip the rest
switch (@class.Name) switch (@class.Name)
{ {
case "basic_string": case "basic_string":
case "allocator": case "allocator":
case "char_traits": case "char_traits":
case "basic_string_view":
@class.GenerationKind = GenerationKind.Generate; @class.GenerationKind = GenerationKind.Generate;
foreach (var specialization in from s in @class.Specializations foreach (var specialization in from s in @class.Specializations
where !s.Arguments.Any(a => where !s.Arguments.Any(a =>
@ -53,6 +57,8 @@ namespace CppSharp.Passes
select s) select s)
{ {
specialization.GenerationKind = GenerationKind.Generate; specialization.GenerationKind = GenerationKind.Generate;
if (@class.Name == "basic_string_view")
specialization.Type = ClassType.ValueType;
InternalizeSpecializationsInFields(specialization); InternalizeSpecializationsInFields(specialization);
} }
break; break;

98
src/Generator/Types/Std/Stdlib.CSharp.cs

@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -218,7 +217,12 @@ namespace CppSharp.Types.Std
private (Encoding Encoding, string Name) GetEncoding() private (Encoding Encoding, string Name) GetEncoding()
{ {
switch (GetCharWidth()) return GetEncoding(Context, GetCharWidth());
}
public static (Encoding Encoding, string Name) GetEncoding(BindingContext Context, uint charWidth)
{
switch (charWidth)
{ {
case 8: case 8:
if (Context.Options.Encoding == Encoding.Default) // aka ANSI with system default code page if (Context.Options.Encoding == Encoding.Default) // aka ANSI with system default code page
@ -312,19 +316,19 @@ namespace CppSharp.Types.Std
typePrinter.PushContext(TypePrinterContextKind.Native); typePrinter.PushContext(TypePrinterContextKind.Native);
if (ctx.Type.Desugar().IsAddress()) if (ctx.Type.Desugar().IsAddress())
return new CustomType(typePrinter.IntPtrType); return new CustomType(typePrinter.IntPtrType);
ClassTemplateSpecialization basicString = GetBasicString(ctx.Type); ClassTemplateSpecialization basicString = ctx.Type.GetClassTemplateSpecialization();
return new CustomType(basicString.Visit(typePrinter).Type); return new CustomType(basicString.Visit(typePrinter).Type);
} }
public override void CSharpMarshalToNative(CSharpMarshalContext ctx) public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{ {
Type type = ctx.Parameter.Type.Desugar(); Type type = ctx.Parameter.Type.Desugar();
ClassTemplateSpecialization basicString = GetBasicString(type); ClassTemplateSpecialization basicString = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(ctx.Context); var typePrinter = new CSharpTypePrinter(ctx.Context);
if (!ctx.Parameter.Type.Desugar().IsAddress() && if (!ctx.Parameter.Type.Desugar().IsAddress() &&
ctx.MarshalKind != MarshalKind.NativeField) ctx.MarshalKind != MarshalKind.NativeField)
ctx.Return.Write($"*({typePrinter.PrintNative(basicString)}*) "); ctx.Return.Write($"*({typePrinter.PrintNative(basicString)}*) ");
string qualifiedBasicString = GetQualifiedBasicString(basicString); string qualifiedBasicString = basicString.GetQualifiedName();
var assign = basicString.Methods.First(m => m.OriginalName == "assign"); var assign = basicString.Methods.First(m => m.OriginalName == "assign");
if (ctx.MarshalKind == MarshalKind.NativeField) if (ctx.MarshalKind == MarshalKind.NativeField)
{ {
@ -350,10 +354,10 @@ namespace CppSharp.Types.Std
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
{ {
var type = Type.Desugar(resolveTemplateSubstitution: false); var type = Type.Desugar(resolveTemplateSubstitution: false);
ClassTemplateSpecialization basicString = GetBasicString(type); ClassTemplateSpecialization basicString = type.GetClassTemplateSpecialization();
var data = basicString.Methods.First(m => m.OriginalName == "data"); var data = basicString.Methods.First(m => m.OriginalName == "data");
var typePrinter = new CSharpTypePrinter(ctx.Context); var typePrinter = new CSharpTypePrinter(ctx.Context);
string qualifiedBasicString = GetQualifiedBasicString(basicString); string qualifiedBasicString = basicString.GetQualifiedName();
string varBasicString = $"__basicStringRet{ctx.ParameterIndex}"; string varBasicString = $"__basicStringRet{ctx.ParameterIndex}";
bool usePointer = type.IsAddress() || ctx.MarshalKind == MarshalKind.NativeField || bool usePointer = type.IsAddress() || ctx.MarshalKind == MarshalKind.NativeField ||
ctx.MarshalKind == MarshalKind.ReturnVariableArray; ctx.MarshalKind == MarshalKind.ReturnVariableArray;
@ -374,31 +378,6 @@ namespace CppSharp.Types.Std
ctx.Return.Write(retString); ctx.Return.Write(retString);
} }
} }
private static string GetQualifiedBasicString(ClassTemplateSpecialization basicString)
{
var declContext = basicString.TemplatedDecl.TemplatedDecl;
var names = new Stack<string>();
while (!(declContext is TranslationUnit))
{
var isInlineNamespace = declContext is Namespace && ((Namespace)declContext).IsInline;
if (!isInlineNamespace)
names.Push(declContext.Name);
declContext = declContext.Namespace;
}
var qualifiedBasicString = string.Join(".", names);
return $"global::{qualifiedBasicString}";
}
private static ClassTemplateSpecialization GetBasicString(Type type)
{
var desugared = type.Desugar();
var template = (desugared.GetFinalPointee() ?? desugared).Desugar();
var templateSpecializationType = template as TemplateSpecializationType;
if (templateSpecializationType != null)
return templateSpecializationType.GetClassTemplateSpecialization();
return (ClassTemplateSpecialization)((TagType)template).Declaration;
}
} }
[TypeMap("FILE", GeneratorKind = GeneratorKind.CSharp)] [TypeMap("FILE", GeneratorKind = GeneratorKind.CSharp)]
@ -409,4 +388,59 @@ namespace CppSharp.Types.Std
return new CILType(typeof(System.IntPtr)); return new CILType(typeof(System.IntPtr));
} }
} }
[TypeMap("basic_string_view<char, char_traits<char>>", GeneratorKind = GeneratorKind.CSharp)]
public class StringView : TypeMap
{
public override Type CSharpSignatureType(TypePrinterContext ctx)
{
if (ctx.Kind == TypePrinterContextKind.Managed)
return new CILType(typeof(string));
var specialization = ctx.Type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(TypePrinterContextKind.Native);
return new CustomType(specialization.Visit(typePrinter).Type);
}
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
if (ctx.MarshalKind == MarshalKind.NativeField)
{
ctx.Before.WriteLine($"throw new {typeof(System.NotImplementedException).FullName}();");
ctx.Return.Write("default");
return;
}
var type = ctx.Parameter.Type.Desugar();
var name = ctx.Parameter.Name;
var specialization = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(ctx.Context);
var bytes = Generator.GeneratedIdentifier($"{name}Bytes");
var bytesPtr = Generator.GeneratedIdentifier($"{name}BytesPtr");
var view = Generator.GeneratedIdentifier($"{name}StringView");
var viewPtr = $"new IntPtr(&{view})";
var encoding = ConstCharPointer.GetEncoding(Context, Context.TargetInfo.CharWidth);
var extensionClass = $"{specialization.GetQualifiedName()}Extensions";
ctx.HasCodeBlock = true;
ctx.Before.WriteLine($"var {view} = new {specialization.Visit(typePrinter)}();");
ctx.Before.WriteLine($"var {bytes} = {name} != null ? global::{typeof(Encoding).FullName}.{encoding.Name}.GetBytes({name}) : null;");
ctx.Before.WriteLine($"fixed (byte* {bytesPtr} = {bytes})");
ctx.Before.WriteOpenBraceAndIndent();
ctx.Before.WriteLine($"{extensionClass}.{Helpers.InternalStruct}.{specialization.Name}({viewPtr}, new {typePrinter.IntPtrType}({bytesPtr}), (uint)({bytes}?.Length ?? 0));");
ctx.Return.Write(type.IsAddress() || ctx.Parameter.IsIndirect ? viewPtr : $"{view}.{Helpers.InstanceIdentifier}");
}
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
{
var type = Type.Desugar(resolveTemplateSubstitution: false);
var specialization = type.GetClassTemplateSpecialization();
var data = specialization.Methods.First(m => m.OriginalName == "data");
var typePrinter = new CSharpTypePrinter(ctx.Context);
var qualifiedBasicString = specialization.GetQualifiedName();
var view = Generator.GeneratedIdentifier($"{ctx.ReturnVarName}StringView");
var returnvarNameOrPtr = type.IsAddress() ? $"new {typePrinter.IntPtrType}(&{ctx.ReturnVarName})" : ctx.ReturnVarName;
ctx.Return.Write($"{qualifiedBasicString}Extensions.{data.Name}({specialization.Visit(typePrinter)}.{Helpers.CreateInstanceIdentifier}({returnvarNameOrPtr}))");
}
}
} }

Loading…
Cancel
Save