using System;
using System.Collections.Generic;
using System.Text;

namespace NMeCab.Core
{
    /// <summary>
    /// ビット値操作のユーティリティ
    /// BitVector32構造体などでもよいが、パフォーマンスを考慮し、あえて異なる実装とする。
    /// </summary>
    public static class BitUtils
    {
        private const uint One = 0x00000001u;
        private const uint AllZero = 0x00000000u;
        private const uint AllOne = 0xFFFFFFFFu;

        /// <summary>
        /// 指定範囲のビットフィールド値を取り出す
        /// </summary>
        /// <param name="bits">ビット列を表すUInt32値</param>
        /// <param name="offset">開始ビット位置</param>
        /// <param name="len">ビット長</param>
        /// <returns>ビットフィールド値</returns>
        public static uint GetBitField(uint bits, int offset, int len)
        {
            //lenはリテラルのケースが多いため、最適化でmaskが定数化されることを期待する
            uint mask = ~(AllOne << len);

            return (bits >> offset) & mask;
        }

        /// <summary>
        /// 指定位置のビット値を取り出す
        /// </summary>
        /// <param name="bits">ビット列を表すUInt32値</param>
        /// <param name="offset">ビット位置</param>
        /// <returns>ビット値</returns>
        public static bool GetFlag(uint bits, int offset)
        {
            //offsetはリテラルのケースが多いため、最適化でmaskが定数化されることを期待する
            uint mask = One << offset;

            return (bits & mask) != AllZero;
        }

        /// <summary>
        /// 指定範囲のビット値が一致するか比較する
        /// </summary>
        /// <param name="flags1">ビット列1を表すUInt32値</param>
        /// <param name="flags2">ビット列2を表すUInt32値</param>
        /// <param name="offset">開始ビット位置</param>
        /// <param name="len">ビット長</param>
        /// <returns>比較結果</returns>
        public static bool CompareFlags(uint flags1, uint flags2, int offset, int len)
        {
            //len、offsetはリテラルのケースが多いため、最適化でmaskが定数化されることを期待する
            uint mask = ~(AllOne << len) << offset;

            return (flags1 & flags2 & mask) != AllZero;
        }

        //public static unsafe uint TurnEndianness(uint value) 
        //{
        //    //System.Net.IPAddress.HostToNetworkOrderでもよいが、

        //    byte* pVal = (byte*)&value;

        //    byte* pDist = stackalloc byte[4];
        //    pDist += 3;

        //    *pDist-- = *pVal++;
        //    *pDist-- = *pVal++;
        //    *pDist-- = *pVal++;
        //    *pDist = *pVal;

        //    return *(uint*)pDist;
        //}
    }
}
