<commit_before>﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Take.Elephant.Specialized.Cache
{
    public class OnDemandCacheSetMap<TKey, TValue> : OnDemandCacheMap<TKey, ISet<TValue>>, ISetMap<TKey, TValue>
    {
        private readonly bool _cacheEmptyValues;

        public OnDemandCacheSetMap(ISetMap<TKey, TValue> source, ISetMap<TKey, TValue> cache, TimeSpan cacheExpiration = default, TimeSpan cacheFaultTolerance = default, bool cacheEmptyValues = false)
            : base(source, cache, cacheExpiration, cacheFaultTolerance)
        {
            _cacheEmptyValues = cacheEmptyValues;
        }

        public OnDemandCacheSetMap(ISetMap<TKey, TValue> source, ISetMap<TKey, TValue> cache, CacheOptions cacheOptions, ILogger logger, bool cacheEmptyValues = false)
            : base(source, cache, cacheOptions, logger)
        {
            _cacheEmptyValues = cacheEmptyValues;
        }

        public override async Task<ISet<TValue>> GetValueOrDefaultAsync(TKey key, CancellationToken cancellationToken = default)
        {
            var cacheValue = await Cache.GetValueOrDefaultAsync(key, cancellationToken).ConfigureAwait(false);
            if (cacheValue != null)
            {
                // The source should be lazy to avoid queries on the source for checking availability
                return new OnDemandCacheSet<TValue>(
                    new LazySet<TValue>(() => ((ISetMap<TKey, TValue>)Source).GetValueOrEmptyAsync(key, cancellationToken)),
                    cacheValue);
            }

            var sourceValue = await ((ISetMap<TKey, TValue>)Source).GetValueOrDefaultAsync(key, cancellationToken).ConfigureAwait(false);

            if (sourceValue is null)
            {
                if (_cacheEmptyValues)
                {
                    if (await Cache.TryAddAsync(key, null, false, cancellationToken).ConfigureAwait(false))
                    {
                        return new OnDemandCacheSet<TValue>(
                            new LazySet<TValue>(() => ((ISetMap<TKey, TValue>)Source).GetValueOrEmptyAsync(key, cancellationToken)),
                            // using GetValueOrDefault here so that it uses the empty support logic
                            new LazySet<TValue>(() => ((ISetMap<TKey, TValue>)Cache).GetValueOrDefaultAsync(key, cancellationToken)));
                    }
                }

                return null;
            }

            // Try add the source values to the cache
            await TryAddWithExpirationAsync(key, sourceValue, true, Cache, cancellationToken).ConfigureAwait(false);

            // Gets an updated reference to the cache set
            cacheValue = await ((ISetMap<TKey, TValue>)Cache)
                .GetValueOrEmptyAsync(key, cancellationToken)
                .ConfigureAwait(false);

            return new OnDemandCacheSet<TValue>(sourceValue, GetKeyExpirationCacheSet(key, cacheValue));
        }

        public virtual async Task<ISet<TValue>> GetValueOrEmptyAsync(TKey key, CancellationToken cancellationToken = default)
        {
            var cacheValue = await ((ISetMap<TKey, TValue>)Cache).GetValueOrEmptyAsync(key, cancellationToken).ConfigureAwait(false);
            if (await cacheValue.GetLengthAsync(cancellationToken).ConfigureAwait(false) > 0)
            {
                // The source should be lazy to avoid queries on the source for checking availability<commit_msg>Remove empty logic from OnDemandCacheSetMap<commit_after>﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Take.Elephant.Specialized.Cache
{
    public class OnDemandCacheSetMap<TKey, TValue> : OnDemandCacheMap<TKey, ISet<TValue>>, ISetMap<TKey, TValue>
    {
        public OnDemandCacheSetMap(ISetMap<TKey, TValue> source, ISetMap<TKey, TValue> cache, TimeSpan cacheExpiration = default, TimeSpan cacheFaultTolerance = default)
            : base(source, cache, cacheExpiration, cacheFaultTolerance)
        {
        }

        public OnDemandCacheSetMap(ISetMap<TKey, TValue> source, ISetMap<TKey, TValue> cache, CacheOptions cacheOptions, ILogger logger)
            : base(source, cache, cacheOptions, logger)
        {
        }

        public override async Task<ISet<TValue>> GetValueOrDefaultAsync(TKey key, CancellationToken cancellationToken = default)
        {
            var cacheValue = await Cache.GetValueOrDefaultAsync(key, cancellationToken).ConfigureAwait(false);
            if (cacheValue != null)
            {
                // The source should be lazy to avoid queries on the source for checking availability
                return new OnDemandCacheSet<TValue>(
                    new LazySet<TValue>(() => ((ISetMap<TKey, TValue>)Source).GetValueOrEmptyAsync(key, cancellationToken)),
                    cacheValue);
            }

            var sourceValue = await ((ISetMap<TKey, TValue>)Source).GetValueOrDefaultAsync(key, cancellationToken).ConfigureAwait(false);

            if (sourceValue is null)
            {
                return null;
            }

            // Try add the source values to the cache
            await TryAddWithExpirationAsync(key, sourceValue, true, Cache, cancellationToken).ConfigureAwait(false);

            // Gets an updated reference to the cache set
            cacheValue = await ((ISetMap<TKey, TValue>)Cache)
                .GetValueOrEmptyAsync(key, cancellationToken)
                .ConfigureAwait(false);

            return new OnDemandCacheSet<TValue>(sourceValue, GetKeyExpirationCacheSet(key, cacheValue));
        }

        public virtual async Task<ISet<TValue>> GetValueOrEmptyAsync(TKey key, CancellationToken cancellationToken = default)
        {
            var cacheValue = await ((ISetMap<TKey, TValue>)Cache).GetValueOrEmptyAsync(key, cancellationToken).ConfigureAwait(false);
            if (await cacheValue.GetLengthAsync(cancellationToken).ConfigureAwait(false) > 0)
            {
                // The source should be lazy to avoid queries on the source for checking availability
{'fraction_non_alphanumeric': 0.08324066719618745, 'fraction_numerical': 0.0003177124702144559, 'mean_word_length': 2.6948356807511735, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 52, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6813730', 'n_tokens_mistral': 1653, 'n_tokens_neox': 1626, 'n_words': 395}