Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start convert from C# to C++. Issue: https://github.com/linksplatform… #80

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 51 additions & 9 deletions cpp/Platform.Converters/CachingConverterDecorator.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,57 @@
namespace Platform::Converters
#include <iomanip>
#include <string>

#include <functional>
#include <memory>
#include <unordered_map>


namespace Platform::Converters
{
VasiliyevAD marked this conversation as resolved.
Show resolved Hide resolved
template <typename ...> class CachingConverterDecorator;
template <typename TSource, typename TTarget> class CachingConverterDecorator<TSource, TTarget> : public IConverter<TSource, TTarget>
template<typename TCache, typename TConverter, typename TSource>
auto CachedCall(TCache& cache, TConverter&& converter, TSource&& source)
-> std::add_lvalue_reference_t<std::decay_t<std::invoke_result_t<TConverter, TSource>>> {
if (auto cursor = cache.find(source); cursor != cache.end())
{
return cursor->second;
}
else
{
auto target = std::forward<TConverter>(converter)(source);
return cache.insert({ std::forward<TSource>(source), std::move(target) }).first->second;
}
}

template <typename TSource, typename TTarget, typename TCache = std::unordered_map<TSource, TTarget>>
class Cached
{
private: readonly IConverter<TSource, TTarget> *_baseConverter;
private: readonly IDictionary<TSource, TTarget> *_cache;
std::function<TTarget(TSource)> _cachedFunction;
TCache _cache;
public:
Cached(std::function<TTarget(TSource)> cachedFunction)
: _cachedFunction(std::move(cachedFunction)) {};

Cached(std::function<TTarget(TSource)> cachedFunction, TCache cache)
: _cachedFunction(std::move(cachedFunction)), _cache(std::move(cache)) {};

const TTarget& operator()(TSource&& source) &
{
return CachedCall(_cache, _cachedFunction, std::move(source));
}

public: CachingConverterDecorator(IConverter<TSource, TTarget> &baseConverter, IDictionary<TSource, TTarget> &cache) { (_baseConverter, _cache) = (baseConverter, cache); }
const TTarget& operator()(const TSource& source) &
{
return CachedCall(_cache, _cachedFunction, source);
}

public: CachingConverterDecorator(IConverter<TSource, TTarget> &baseConverter) : this(baseConverter, Dictionary<TSource, TTarget>()) { }
TTarget&& operator()(TSource&& source) &&
{
return std::move(CachedCall(_cache, _cachedFunction, std::move(source)));
}

public: TTarget Convert(TSource source) { return _cache.GetOrAdd(source, _baseConverter.Convert); }
TTarget&& operator()(const TSource& source) &&
{
return std::move(CachedCall(_cache, _cachedFunction, source));
}
};
}
}
20 changes: 2 additions & 18 deletions cpp/Platform.Converters/CheckedConverter.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class CheckedConverter;
template <typename TSource, typename TTarget> class CheckedConverter<TSource, TTarget> : public ConverterBase<TSource, TTarget>
{
public: static CheckedConverter<TSource, TTarget> Default
{
get;
} = CompileCheckedConverter();

private: static CheckedConverter<TSource, TTarget> CompileCheckedConverter()
{
auto type = CreateTypeInheritedFrom<CheckedConverter<TSource, TTarget>>();
EmitConvertMethod(type, il => il.CheckedConvert<TSource, TTarget>());
return (CheckedConverter<TSource, TTarget>)Activator.CreateInstance(type.CreateTypeInfo());
}
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.
152 changes: 2 additions & 150 deletions cpp/Platform.Converters/ConverterBase.h
Original file line number Diff line number Diff line change
@@ -1,150 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class ConverterBase;
template <typename TSource, typename TTarget> class ConverterBase<TSource, TTarget> : public IConverter<TSource, TTarget>
{
public: virtual TTarget Convert(TSource source) = 0;

protected: static void ConvertFromObject(ILGenerator &il)
{
auto returnDefault = il.DefineLabel();
il.Emit(OpCodes.Brfalse_S, returnDefault);
il.LoadArgument(1);
il.Emit(OpCodes.Castclass, typeof(IConvertible));
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Callvirt, GetMethodForConversionToTargetType());
il.Return();
il.MarkLabel(returnDefault);
LoadDefault(il, typeof(TTarget));
}

protected: static std::string GetNewName() { return Guid.NewGuid().ToString("N"); }

protected: static TypeBuilder CreateTypeInheritedFrom<TBaseClass>()
{
auto assemblyName = AssemblyName(GetNewName());
auto assembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
auto module = assembly.DefineDynamicModule(GetNewName());
auto type = module.DefineType(GetNewName(), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(TBaseClass));
return type;
}

protected: static void EmitConvertMethod(TypeBuilder typeBuilder, std::function<void(ILGenerator)> emitConversion)
{
typeBuilder.EmitFinalVirtualMethod<Converter<TSource, TTarget>>("Convert", il =>
{
il.LoadArgument(1);
if (typeof(TSource) == typeof(void*) && typeof(TTarget) != typeof(void*))
{
ConvertFromObject(il);
}
else if (typeof(TSource) != typeof(void*) && typeof(TTarget) == typeof(void*))
{
il.Box(typeof(TSource));
}
else
{
emitConversion(il);
}
il.Return();
});
}

protected: static MethodInfo GetMethodForConversionToTargetType()
{
auto targetType = typeof(TTarget);
auto convertibleType = typeof(IConvertible);
auto typeParameters = Types<IFormatProvider>.Array;
if (targetType == typeof(bool))
{
return convertibleType.GetMethod("ToBoolean", typeParameters);
}
else if (targetType == typeof(std::uint8_t))
{
return convertibleType.GetMethod("ToByte", typeParameters);
}
else if (targetType == typeof(char))
{
return convertibleType.GetMethod("ToChar", typeParameters);
}
else if (targetType == typeof(DateTime))
{
return convertibleType.GetMethod("ToDateTime", typeParameters);
}
}
else if (targetType == typeof(double))
{
return convertibleType.GetMethod("ToDouble", typeParameters);
}
else if (targetType == typeof(std::int16_t))
{
return convertibleType.GetMethod("ToInt16", typeParameters);
}
else if (targetType == typeof(std::int32_t))
{
return convertibleType.GetMethod("ToInt32", typeParameters);
}
else if (targetType == typeof(std::int64_t))
{
return convertibleType.GetMethod("ToInt64", typeParameters);
}
else if (targetType == typeof(std::int8_t))
{
return convertibleType.GetMethod("ToSByte", typeParameters);
}
else if (targetType == typeof(float))
{
return convertibleType.GetMethod("ToSingle", typeParameters);
}
else if (targetType == typeof(std::string))
{
return convertibleType.GetMethod("ToString", typeParameters);
}
else if (targetType == typeof(std::uint16_t))
{
return convertibleType.GetMethod("ToUInt16", typeParameters);
}
else if (targetType == typeof(std::uint32_t))
{
return convertibleType.GetMethod("ToUInt32", typeParameters);
}
else if (targetType == typeof(std::uint64_t))
{
return convertibleType.GetMethod("ToUInt64", typeParameters);
}
else
{
throw std::logic_error("Not supported exception.");
}
}

protected: static void LoadDefault(ILGenerator &il, Type targetType)
{
if (targetType == typeof(std::string))
{
il.Emit(OpCodes.Ldsfld, targetType.GetField("Empty", BindingFlags.Static | BindingFlags.Public));
}
else if (targetType == typeof(DateTime))
{
il.Emit(OpCodes.Ldsfld, targetType.GetField("MinValue", BindingFlags.Static | BindingFlags.Public));
}
}
else if (targetType == typeof(float))
{
il.LoadConstant(0.0F);
}
else if (targetType == typeof(double))
{
il.LoadConstant(0.0D);
}
else if (targetType == typeof(std::int64_t) || targetType == typeof(std::uint64_t))
{
il.LoadConstant(0L);
}
else
{
il.LoadConstant(0);
}
}
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.
11 changes: 2 additions & 9 deletions cpp/Platform.Converters/IConverter[TSource, TTarget].h
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class IConverter;
template <typename TSource, typename TTarget> class IConverter<TSource, TTarget>
{
public:
virtual TTarget Convert(TSource source) = 0;
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.
10 changes: 2 additions & 8 deletions cpp/Platform.Converters/IConverter[T].h
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class IConverter;
template <typename T> class IConverter<T> : public IConverter<T, T>
{
public:
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
Expand Down Expand Up @@ -138,12 +139,22 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CachingConverterDecorator.h" />
<ClInclude Include="CheckedConverter.h" />
<ClInclude Include="Convert.h" />
<ClInclude Include="Converter.h" />
<ClInclude Include="ConverterBase.h" />
<ClInclude Include="IConverter[TSource, TTarget].h" />
<ClInclude Include="To.h" />
<ClInclude Include="is_detected.h" />
<ClInclude Include="Platform.Converters.h" />
<ClInclude Include="StringConverter.h" />
<ClInclude Include="UncheckedConverter.h" />
<ClInclude Include="UncheckedSignExtendingConverter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Platform.Converters.Benchmarks\Int32ToUInt64ConverterBenchmarks.cpp" />
<ClCompile Include="..\Platform.Converters.Benchmarks\Program.cpp" />
<ClCompile Include="..\Platform.Converters.Benchmarks\UInt64ToUInt64ConverterBenchmarks.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,37 @@
<ClInclude Include="StringConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="is_detected.h">
<ClInclude Include="To.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="To.h">
<ClInclude Include="CachingConverterDecorator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CheckedConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ConverterBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IConverter[TSource, TTarget].h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UncheckedConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UncheckedSignExtendingConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Platform.Converters.Benchmarks\Int32ToUInt64ConverterBenchmarks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Platform.Converters.Benchmarks\Program.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Platform.Converters.Benchmarks\UInt64ToUInt64ConverterBenchmarks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
20 changes: 2 additions & 18 deletions cpp/Platform.Converters/UncheckedConverter.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class UncheckedConverter;
template <typename TSource, typename TTarget> class UncheckedConverter<TSource, TTarget> : public ConverterBase<TSource, TTarget>
{
public: static UncheckedConverter<TSource, TTarget> Default
{
get;
} = CompileUncheckedConverter();

private: static UncheckedConverter<TSource, TTarget> CompileUncheckedConverter()
{
auto type = CreateTypeInheritedFrom<UncheckedConverter<TSource, TTarget>>();
EmitConvertMethod(type, il => il.UncheckedConvert<TSource, TTarget>());
return (UncheckedConverter<TSource, TTarget>)Activator.CreateInstance(type.CreateTypeInfo());
}
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.
20 changes: 2 additions & 18 deletions cpp/Platform.Converters/UncheckedSignExtendingConverter.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,2 @@
namespace Platform::Converters
{
template <typename ...> class UncheckedSignExtendingConverter;
template <typename TSource, typename TTarget> class UncheckedSignExtendingConverter<TSource, TTarget> : public ConverterBase<TSource, TTarget>
{
public: static UncheckedSignExtendingConverter<TSource, TTarget> Default
{
get;
} = CompileUncheckedConverter();

private: static UncheckedSignExtendingConverter<TSource, TTarget> CompileUncheckedConverter()
{
auto type = CreateTypeInheritedFrom<UncheckedSignExtendingConverter<TSource, TTarget>>();
EmitConvertMethod(type, il => il.UncheckedConvert<TSource, TTarget>(extendSign: true));
return (UncheckedSignExtendingConverter<TSource, TTarget>)Activator.CreateInstance(type.CreateTypeInfo());
}
};
}
// Для этого файла не требуется перевод на C++.
// No translation to C++ is needed for that file.