判断脏数据时更纯粹,跟是否来自数据库无关
大石头 authored at 2018-11-01 10:59:31
3.10 KiB
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace XCode
{
    /// <summary>脏属性集合</summary>
    /// <remarks>
    /// 脏数据需要并行高性能,要节省内存,允许重复。
    /// 普通集合加锁成本太高,并行集合内存消耗太大,并行字典只有一两项的时候也要占用7.9k内存。
    /// </remarks>
    [Serializable]
    public class DirtyCollection : IEnumerable<String>
    {
        private String[] _items = new String[8];
        private Int32 _size;
        private Int32 _length;

        /// <summary>获取或设置与指定的属性是否有脏数据。</summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public Boolean this[String item]
        {
            get => Contains(item);
            set
            {
                if (value)
                    Add(item);
                else
                    Remove(item);
            }
        }

        private void Add(String item)
        {
            if (Contains(item)) return;

            // 抢位置
            var n = Interlocked.Increment(ref _length);

            var ms = _items;
            while (ms.Length < _length)
            {
                // 扩容
                var arr = new String[ms.Length * 2];
                Array.Copy(ms, arr, ms.Length);
                if (Interlocked.CompareExchange(ref _items, arr, ms) == ms) break;

                ms = _items;
            }

            _items[n - 1] = item;

            Interlocked.Increment(ref _size);
        }

        private void Remove(String item)
        {
            var len = _length;
            var ms = _items;
            if (len > ms.Length) len = ms.Length;
            for (var i = 0; i < len; i++)
            {
                if (ms[i] == item)
                {
                    ms[i] = null;

                    Interlocked.Decrement(ref _size);
                }
            }
        }

        private Boolean Contains(String item)
        {
            var len = _length;
            var ms = _items;
            if (len > ms.Length) len = ms.Length;
            for (var i = 0; i < len; i++)
            {
                if (ms[i] == item) return true;
            }

            return false;
        }

        /// <summary>清空</summary>
        public void Clear()
        {
            _length = 0;
            _size = 0;
            Array.Clear(_items, 0, _items.Length);
        }

        /// <summary>个数</summary>
        public Int32 Count => _size;

        /// <summary>枚举迭代</summary>
        /// <returns></returns>
        public IEnumerator<String> GetEnumerator()
        {
            var len = _length;
            var ms = _items;
            if (len > ms.Length) len = ms.Length;
            for (var i = 0; i < len; i++)
            {
                if (ms[i] != null) yield return ms[i];
            }
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
}