<commit_before>﻿using Microsoft.Extensions.Internal;
using Serenity.Abstractions;
using System;
using System.Collections.Generic;

namespace Serenity.Caching
{
    /// <summary>
    /// In memory distributed cache implementation, which emulates an IDistributedCache.
    /// </summary>
    public class DistributedCacheEmulator : IDistributedCache
    {
        private readonly ISystemClock clock;

        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param name="clock">Clock source for testing purposes</param>
        public DistributedCacheEmulator(ISystemClock clock)
        {
            this.clock = clock ?? throw new ArgumentNullException(nameof(clock));
        }

        /// <summary>
        /// The synchronization lock
        /// </summary>
        private readonly object sync = new object();

        /// <summary>
        /// The dictionary that contains cached items
        /// </summary>
        private readonly Dictionary<string, object> dictionary =
            new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// The dictionary that contains expiration dates for keys that added with an expiration
        /// </summary>
        private readonly Dictionary<string, DateTimeOffset> expiration = new Dictionary<string, DateTimeOffset>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// Increments value with specified key and returns the new value.
        /// If value doesn't exist, its new value will be 1.
        /// </summary>
        /// <param name="key">Key.</param>
        /// <param name="amount">Increase amount.</param>
        /// <returns>Increased amount, or 1 if it didn't exist before</returns>
        public long Increment(string key, int amount = 1)
        {
            lock (sync)
            {
                if (!dictionary.TryGetValue(key, out object value))<commit_msg>allow null clock<commit_after>﻿using Microsoft.Extensions.Internal;
using Serenity.Abstractions;
using System;
using System.Collections.Generic;

namespace Serenity.Caching
{
    /// <summary>
    /// In memory distributed cache implementation, which emulates an IDistributedCache.
    /// </summary>
    public class DistributedCacheEmulator : IDistributedCache
    {
        private readonly ISystemClock clock;

        /// <summary>
        /// Creates a new instance
        /// </summary>
        /// <param name="clock">Clock source for testing purposes</param>
        public DistributedCacheEmulator(ISystemClock clock = null)
        {
            this.clock = clock ?? new SystemClock();
        }

        /// <summary>
        /// The synchronization lock
        /// </summary>
        private readonly object sync = new object();

        /// <summary>
        /// The dictionary that contains cached items
        /// </summary>
        private readonly Dictionary<string, object> dictionary =
            new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// The dictionary that contains expiration dates for keys that added with an expiration
        /// </summary>
        private readonly Dictionary<string, DateTimeOffset> expiration = new Dictionary<string, DateTimeOffset>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// Increments value with specified key and returns the new value.
        /// If value doesn't exist, its new value will be 1.
        /// </summary>
        /// <param name="key">Key.</param>
        /// <param name="amount">Increase amount.</param>
        /// <returns>Increased amount, or 1 if it didn't exist before</returns>
        public long Increment(string key, int amount = 1)
        {
            lock (sync)
            {
                if (!dictionary.TryGetValue(key, out object value))
{'fraction_non_alphanumeric': 0.10891603847153626, 'fraction_numerical': 0.0015596568754873928, 'mean_word_length': 2.1960132890365447, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 51, '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': '5933455', 'n_tokens_mistral': 934, 'n_tokens_neox': 897, 'n_words': 299}