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

Conversation

VasiliyevAD
Copy link

#48

Для начала обсуждения.
Пока получается вот так перевести этот файл

@VasiliyevAD VasiliyevAD self-assigned this Nov 14, 2021
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
private: readonly IDictionary<TSource, TTarget> *_cache;

public: CachingConverterDecorator(IConverter<TSource, TTarget> &baseConverter, IDictionary<TSource, TTarget> &cache) { (_baseConverter, _cache) = (baseConverter, cache); }
private: std::unique_ptr<IConverter<TSource, TTarget>> _baseConverter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_baseConverter should be a reference to a callable object.

cpp/Platform.Converters/CachingConverterDecorator.h Outdated Show resolved Hide resolved
{
private: readonly IConverter<TSource, TTarget> *_baseConverter;
private: readonly IDictionary<TSource, TTarget> *_cache;
private: std::unique_ptr<std::function<TTarget(TSource)>> _baseConverter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not depend directly on std::function type here.
Let the user specify any callable type here.
The is no need to restrict the user with pointer here.
Catching converter can be a container for callable object.

Copy link
Member

@uselessgoddess uselessgoddess Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Forward converter as template parameter.

template<typename F>
struct Converter {
    F base;
    Converter(F&& base) : base(base) {}
}

template<typename F>
Converter(F) -> Converter<F>;

{
template <typename ...> class CachingConverterDecorator;
template <typename TSource, typename TTarget> class CachingConverterDecorator<TSource, TTarget> : public IConverter<TSource, TTarget>
template <typename TSource, typename TTarget> class CachingConverterDecorator<TSource, TTarget>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might have only single function type as a type parameter. TSource and TTarget can be inferred from the callable object type.

Copy link
Member

@uselessgoddess uselessgoddess Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Konard, please, show this magic. There is no way to do this in C++.
In extreme case, use deduction guides.

Comment on lines 2 to 6
{
template <typename ...> class IConverter;
template <typename T> class IConverter<T> : public IConverter<T, T>
{
public:
};
{ };
}
Copy link
Member

@uselessgoddess uselessgoddess Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file

public: TTarget Convert(TSource source) { return _cache.GetOrAdd(source, _baseConverter.Convert); }
public: auto operator()(auto&& source)
{
static std::unordered_map<std::decay_t<decltype(source)>> cached;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This std::unordered_map should be a member of the class.

}
else
{
return *cached.insert({source, _baseConverter(source)})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return *cached.insert({source, _baseConverter(source)})
return *cached.insert({ source, _baseConverter(source )})

template <typename ...> class CachingConverterDecorator;
template <typename TSource, typename TTarget> class CachingConverterDecorator<TSource, TTarget> : public IConverter<TSource, TTarget>
template <typename ...> class Cached;
template <typename Function> class Cached<Function>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
template <typename Function> class Cached<Function>
template <typename TFunction, typename TSource, typename TTarget> class Cached<Function>

We should add these types back to make it possible to store unordered_map as a class member.

Comment on lines 19 to 20
public: TTarget operator()(const TSource& source) {
if (auto cursor = _cache.find(source); cursor != _cache.end())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public: TTarget operator()(const TSource& source) {
if (auto cursor = _cache.find(source); cursor != _cache.end())
public: TTarget operator()(const TSource& source)
{
if (auto cursor = _cache.find(source); cursor != _cache.end())

Comment on lines 1 to 2
#pragma once
#include <functional>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#pragma once
#include <functional>
#pragma once
#include <functional>

{
private: readonly IConverter<TSource, TTarget> *_baseConverter;
private: readonly IDictionary<TSource, TTarget> *_cache;
private: std::unique_ptr<std::function<TTarget(TSource)>> _baseConverter;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like unique_ptr is superfluous here

private: std::function<TTarget(TSource)>> _baseConverter;

private: readonly IDictionary<TSource, TTarget> *_cache;
private: std::unique_ptr<std::function<TTarget(TSource)>> _baseConverter;

private: std::unordered_map<TSource, TTarget> _cache;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Definitely need to accept an allocator in template parameters


public: CachingConverterDecorator(IConverter<TSource, TTarget> &baseConverter) : this(baseConverter, Dictionary<TSource, TTarget>()) { }
public: Cached(std::function<TTarget(TSource)>& baseConverter) : _baseConverter(baseConverter), _cache() {};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

manual default cache initialization is optional here unnecessary, it can be removed

public: Cached(std::function<TTarget(TSource)> baseConverter) : _baseConverter(std::move(baseConverter)) {}


public: TTarget Convert(TSource source) { return _cache.GetOrAdd(source, _baseConverter.Convert); }
public: TTarget operator()(const TSource& source) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If TTarget is a heavy object, it may be unnecessary copies here. Maybe worth It to return const TTarget& here, but it's better to ask @Konard

Copy link
Member

@uselessgoddess uselessgoddess Jan 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@poul250 Oh my God, return isn't move?


public: TTarget Convert(TSource source) { return _cache.GetOrAdd(source, _baseConverter.Convert); }
public: TTarget operator()(const TSource& source) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add overloading for rvalues here

public: TTarget operator()(TSource&& source)

public: TTarget operator()(const TSource& source) {
if (auto cursor = _cache.find(source); cursor != _cache.end())
{
return *cursor;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return cursor->second;

@FreePhoenix888
Copy link
Member

@poul250 It is better to use Suggestion feature instead of raw example to see what changes you suggest :)

Copy link
Member

@Konard Konard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to let user decide how function and cache are stored?


public: CachingConverterDecorator(IConverter<TSource, TTarget> &baseConverter, IDictionary<TSource, TTarget> &cache) { (_baseConverter, _cache) = (baseConverter, cache); }
private: std::unordered_map<TSource, TTarget> _cache;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private: std::unordered_map<TSource, TTarget> _cache;
private: TCache& _cache;

{
private: readonly IConverter<TSource, TTarget> *_baseConverter;
private: readonly IDictionary<TSource, TTarget> *_cache;
private: std::function<TTarget(TSource) > _baseConverter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private: std::function<TTarget(TSource) > _baseConverter;
private: std::function<TTarget(TSource)>& _cachedFunction;

@uselessgoddess
Copy link
Member

Is it possible to let user decide how function and cache are stored?

@Konard use ideas from our friend's code https://godbolt.org/z/jW4dG6f7K

Comment on lines 47 to 55
TTarget&& operator()(TSource&& source) &&
{
return std::move(CachedCall(_cache, _cachedFunction, std::move(source)));
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Co-authored-by: uselessgoddess <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants