<commit_before>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;

namespace Developer.Test
{
    /// <summary>
    /// calculated dynamic property
    /// </summary>
    /// <typeparam name="T"> property value type </typeparam>
    sealed class CalculatedProperty<T> : BasicProperty<T>, IDependencyTarget, IDynamicProperty<T>
    {
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="read"> Called to calculate the value of the property. </param>
        /// <param name="write"> Called whenever the <see cref="IDynamicProperty{T}.Value"/> property setter of this is invoked. </param>
        public CalculatedProperty(Func<T> read, Action<T> write)
        {
            _read = read;
            _write = write;

            base.Init(EvaluatingRead());
        }
        /// <summary>
        /// Gets or sets the value of the property.
        /// </summary>
        public new T Value
        {
            get
            {
                return base.Value;
            }
            set { _write(value); }
        }
        /// <summary>
        /// to subscribe to dependency source
        /// </summary>
        /// <param name="source"> a dependency source - <see cref="BasicProperty{T}"/></param>
        public void SubscribeTo(IDependencySource source)
        {
            if(!_dependency.ContainsKey(source))
                _dependency[source] = source.Subscribe(Invalidate);
        }

        private void ClearDependency()
        {
            foreach (var subscription in _dependency.Values)
            {
                subscription.Dispose();
            }
            _dependency.Clear();
        }

        private void RestoreValidReadCache()
        {
                ClearDependency();
                base.Value = EvaluatingRead();
        }

        private T EvaluatingRead()
        {
            lock (_protection)
            {
                var targets = ThreadStack.Instance;
                targets.Push(this);
                var value = _read();
                var check = targets.Pop();
                Debug.Assert(check == this, "Thread stack is broken.");
                return value;
            }
        }

        private void Invalidate()
        {
            var source = this as IDependencySource;
            source.NotifyAllTargets();
            RestoreValidReadCache();
        }

        private readonly IDictionary<IDependencySource, IDisposable> _dependency = new ConcurrentDictionary<IDependencySource, IDisposable>();
        private readonly Func<T> _read;
        private readonly Action<T> _write;
        private readonly object _protection = new object();
    }
}<commit_msg>Final<commit_after>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace Developer.Test
{
    /// <summary>
    /// calculated dynamic property
    /// </summary>
    /// <typeparam name="T"> property value type </typeparam>
    sealed class CalculatedProperty<T> : BasicProperty<T>, IDependencyTarget, IDynamicProperty<T>
    {
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="read"> Called to calculate the value of the property. </param>
        /// <param name="write"> Called whenever the <see cref="IDynamicProperty{T}.Value"/> property setter of this is invoked. </param>
        public CalculatedProperty(Func<T> read, Action<T> write)
        {
            _read = read;
            _write = write;

            base.Init(EvaluatingRead());
        }
        /// <summary>
        /// Gets or sets the value of the property.
        /// </summary>
        public new T Value
        {
            get
            {
                T val = default(T);
                var done = false;
                while (!done)
                {
                    try
                    {
                        _rwl.AcquireReaderLock(TimeSpan.FromSeconds(1));
                        try
                        {
                            val = base.Value;
                            done = true;
                        }
                        finally
                        {
                            _rwl.ReleaseReaderLock();
                        }
                    }
                    catch (ApplicationException)
                    {
                        done = false;
                    }
                }
                return val;
            }
            set { _write(value); }
        }
        /// <summary>
        /// to subscribe to dependency source
        /// </summary>
        /// <param name="source"> a dependency source - <see cref="BasicProperty{T}"/></param>
        public void SubscribeTo(IDependencySource source)
        {
            if(!_dependency.ContainsKey(source))
                _dependency[source] = source.Subscribe(Invalidate);
        }

        private void ClearDependency()
        {
            foreach (var subscription in _dependency.Values)
            {
                subscription.Dispose();
            }
            _dependency.Clear();
        }

        private void RestoreValidReadCache()
        {
                ClearDependency();
                base.Value = EvaluatingRead();
        }

        private T EvaluatingRead()
        {
            T value = default(T);
            var done = false;
            while (!done)
            {
                try
                {
                    _rwl.AcquireWriterLock(TimeSpan.FromSeconds(1));
                    try
                    {
                        var targets = ThreadStack.Instance;
                        targets.Push(this);
                        value = _read();
                        var check = targets.Pop();
                        Debug.Assert(check == this, "Thread stack is broken.");
                        done = true;
                    }
                    finally
                    {
                        _rwl.ReleaseWriterLock();
                    }
                }
                catch (ApplicationException)
                {
                    done = false;
                }
            }

            return value;

        }

        private void Invalidate()
        {
            var source = this as IDependencySource;
            source.NotifyAllTargets();
            RestoreValidReadCache();
        }

        private readonly IDictionary<IDependencySource, IDisposable> _dependency = new ConcurrentDictionary<IDependencySource, IDisposable>();
        private readonly Func<T> _read;
        private readonly Action<T> _write;
        private readonly ReaderWriterLock _rwl = new ReaderWriterLock();
    }
}
{'fraction_non_alphanumeric': 0.09645640347007793, 'fraction_numerical': 0.00029407440082340834, 'mean_word_length': 1.2764390896921018, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1868520', 'n_tokens_mistral': 1656, 'n_tokens_neox': 1545, 'n_words': 391}