﻿namespace HighPerformance
{
    using System;
    using System.Collections.Generic;
    using BenchmarkDotNet.Attributes;

    /// <summary>
    /// in relation to simple assignments, boxing and unboxing are computationally expensive processes. 
    /// when a value type is boxed, a new object must be allocated and constructed. 
    /// to a lesser degree, the cast required for unboxing is also expensive computationally. 
    /// </summary>
    /// <remarks>
    /// boxing is used to store value in the garbage-collected heap. Boxing is an implicit conversion of a value type
    /// to the type object or to any interface type implemented by this value type.
    /// Boxing a value type allocates an object instance on the heap and copies the value into the new object.
    /// Unboxing operation consists of: 
    /// 1. checking the object instance to make sure it is a boxed value of given value type
    /// 2. copying the value from the instance to the value type variable
    /// </remarks>
    [CoreJob, ClrJob]
    public class Boxing
    {
        public int N { get; set; } = 1000;

        public void BoxedValueIsDifferentFromOriginalOne()
        {
            int a = 123;
            // boxing copies the value of i into object o
            object o = a;

            a = 456;

            Console.Out.WriteLine($"the value in value type is: {a}");
            Console.Out.WriteLine($"the value in boxed object is: {o}");
        }

        [Benchmark]
        public void RunWithBoxing()
        {
            var list = new List<object>();
            for (int i = 0; i < N; i++)
            {
                list.Add(i);
            }

            int sum = 0;
            foreach (var ele in list)
            {
                sum += (int)ele;
            }

            Console.WriteLine(sum);
        }

        [Benchmark(Baseline = true)]
        public void RunWithoutBoxing()
        {
            var list = new List<int>();
            for (int i = 0; i < N; i++)
            {
                list.Add(i);
            }

            int sum = 0;
            foreach (var ele in list)
            {
                sum += ele;
            }

            Console.WriteLine(sum);
        }
    }
}
