-
Notifications
You must be signed in to change notification settings - Fork 2
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
base: main
Are you sure you want to change the base?
Conversation
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; |
There was a problem hiding this comment.
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.
{ | ||
private: readonly IConverter<TSource, TTarget> *_baseConverter; | ||
private: readonly IDictionary<TSource, TTarget> *_cache; | ||
private: std::unique_ptr<std::function<TTarget(TSource)>> _baseConverter; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
{ | ||
template <typename ...> class IConverter; | ||
template <typename T> class IConverter<T> : public IConverter<T, T> | ||
{ | ||
public: | ||
}; | ||
{ }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this file
8bfb237
to
48a377f
Compare
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; |
There was a problem hiding this comment.
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)}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
public: TTarget operator()(const TSource& source) { | ||
if (auto cursor = _cache.find(source); cursor != _cache.end()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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()) |
#pragma once | ||
#include <functional> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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() {}; |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return cursor->second;
@poul250 It is better to use |
There was a problem hiding this 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private: std::function<TTarget(TSource) > _baseConverter; | |
private: std::function<TTarget(TSource)>& _cachedFunction; |
@Konard use ideas from our friend's code https://godbolt.org/z/jW4dG6f7K |
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)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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]>
#48
Для начала обсуждения.
Пока получается вот так перевести этот файл