<commit_before>﻿// Copyright (c) <NAME>. All rights reserved.
//
// This file is distributed under the MIT License. See LICENSE.md for details.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace NonBlocking
{
    //TODO: replace with counter that scales
    internal sealed class Counter
    {
        private int cnt;
        public int get()
        {
            return Volatile.Read(ref cnt);
        }
        internal int estimate_get()
        {
            return cnt;
        }

        public void increment()
        {
            Interlocked.Increment(ref cnt);
        }
        public void decrement()
        {
            Interlocked.Decrement(ref cnt);
        }
    }
}<commit_msg>simple striped counter<commit_after>﻿// Copyright (c) <NAME>. All rights reserved.
//
// This file is distributed under the MIT License. See LICENSE.md for details.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace NonBlocking
{
    internal sealed class Counter
    {
        [StructLayout(LayoutKind.Explicit)]
        private struct Cell
        {
            // do not overlap with other counters or with array.Length
            [FieldOffset(60)]
            public int cnt;
        }

        private Cell[] cells;

        //private int lastCnt;
        //private long lastTicks;

        public Counter()
            : this(4)
        {
        }

        private Counter(int size)
        {
            cells = new Cell[size];
        }

        public int get()
        {
            var cells = this.cells;
            var sum = 0;
            for(int i = 0; i < cells.Length; i++)
            {
                sum += cells[i].cnt;
            }

            return sum;
        }

        internal int estimate_get()
        {
            return get();

            // TODO: is there a scenario where the following is cheaper?
            //       we woud need to have a lot of counters.

            //var curTicks = DateTime.UtcNow.Ticks;
            //// more than millisecond passed?
            //if (curTicks - lastTicks > TimeSpan.TicksPerMillisecond)
            //{
            //    lastCnt = get();
            //    lastTicks = curTicks;
            //}

            //return lastCnt;
        }

        public void increment()
        {
            var cells = this.cells;
            int idx = GetIndex(cells);

            int val = cells[idx].cnt;
            Interlocked.Increment(ref cells[idx].cnt);
        }

        public void decrement()
        {
            var cells = this.cells;
            int idx = GetIndex(cells);

            int val = cells[idx].cnt;
            Interlocked.Decrement(ref cells[idx].cnt);
        }

        private static int GetIndex(Cell[] cells)
        {
            var mask = cells.Length - 1;
            return mask == 0 ?
                mask :
                Environment.CurrentManagedThreadId & mask;
        }

        internal static long CurrentTimeMillis()
        {
            return DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
        }
    }
}
{'fraction_non_alphanumeric': 0.08969996906897618, 'fraction_numerical': 0.0021651716671821837, 'mean_word_length': 1.4574468085106382, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, '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': '2121136', 'n_tokens_mistral': 865, 'n_tokens_neox': 837, 'n_words': 247}