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 @@ @@ -1,5 +1,7 @@
namespace CppSharp.AST.Extensions
{
using System.Collections.Generic;
public static class TypeExtensions
{
public static bool IsPrimitiveType(this Type t)
@ -442,5 +444,30 @@ @@ -442,5 +444,30 @@
{
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 @@ @@ -7,5 +7,12 @@
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;
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) 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) 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) @@ -77,6 +77,7 @@ Parser::Parser(CppParserOptions* Opts) : opts(Opts), index(0)
supportedStdTypes.insert(SupportedStdType);
supportedStdTypes.insert("allocator");
supportedStdTypes.insert("basic_string");
supportedStdTypes.insert("basic_string_view");
}
LayoutField Parser::WalkVTablePointer(Class* Class,
@ -918,6 +919,7 @@ bool Parser::IsSupported(const clang::CXXMethodDecl* MD) @@ -918,6 +919,7 @@ bool Parser::IsSupported(const clang::CXXMethodDecl* MD)
using namespace clang;
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<CXXDestructorDecl>(MD) ||
(MD->getDeclName().isIdentifier() &&

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

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

6
src/Generator/Passes/IgnoreSystemDeclarationsPass.cs

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

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

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@ -218,7 +217,12 @@ namespace CppSharp.Types.Std @@ -218,7 +217,12 @@ namespace CppSharp.Types.Std
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:
if (Context.Options.Encoding == Encoding.Default) // aka ANSI with system default code page
@ -312,19 +316,19 @@ namespace CppSharp.Types.Std @@ -312,19 +316,19 @@ namespace CppSharp.Types.Std
typePrinter.PushContext(TypePrinterContextKind.Native);
if (ctx.Type.Desugar().IsAddress())
return new CustomType(typePrinter.IntPtrType);
ClassTemplateSpecialization basicString = GetBasicString(ctx.Type);
ClassTemplateSpecialization basicString = ctx.Type.GetClassTemplateSpecialization();
return new CustomType(basicString.Visit(typePrinter).Type);
}
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
Type type = ctx.Parameter.Type.Desugar();
ClassTemplateSpecialization basicString = GetBasicString(type);
ClassTemplateSpecialization basicString = type.GetClassTemplateSpecialization();
var typePrinter = new CSharpTypePrinter(ctx.Context);
if (!ctx.Parameter.Type.Desugar().IsAddress() &&
ctx.MarshalKind != MarshalKind.NativeField)
ctx.Return.Write($"*({typePrinter.PrintNative(basicString)}*) ");
string qualifiedBasicString = GetQualifiedBasicString(basicString);
string qualifiedBasicString = basicString.GetQualifiedName();
var assign = basicString.Methods.First(m => m.OriginalName == "assign");
if (ctx.MarshalKind == MarshalKind.NativeField)
{
@ -350,10 +354,10 @@ namespace CppSharp.Types.Std @@ -350,10 +354,10 @@ namespace CppSharp.Types.Std
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
{
var type = Type.Desugar(resolveTemplateSubstitution: false);
ClassTemplateSpecialization basicString = GetBasicString(type);
ClassTemplateSpecialization basicString = type.GetClassTemplateSpecialization();
var data = basicString.Methods.First(m => m.OriginalName == "data");
var typePrinter = new CSharpTypePrinter(ctx.Context);
string qualifiedBasicString = GetQualifiedBasicString(basicString);
string qualifiedBasicString = basicString.GetQualifiedName();
string varBasicString = $"__basicStringRet{ctx.ParameterIndex}";
bool usePointer = type.IsAddress() || ctx.MarshalKind == MarshalKind.NativeField ||
ctx.MarshalKind == MarshalKind.ReturnVariableArray;
@ -374,31 +378,6 @@ namespace CppSharp.Types.Std @@ -374,31 +378,6 @@ namespace CppSharp.Types.Std
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)]
@ -409,4 +388,59 @@ namespace CppSharp.Types.Std @@ -409,4 +388,59 @@ namespace CppSharp.Types.Std
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