zhangsongcui

BitOps

Oct 14th, 2019
414
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 28.81 KB | None | 0 0
  1. // https://github.com/k2workflow/Clay/blob/master/src/SourceCode.Clay.Primitives/Numerics/BitOps.cs
  2.  
  3. #region License
  4.  
  5. // Copyright (c) K2 Workflow (SourceCode Technology Holdings Inc.). All rights reserved.
  6. // Licensed under the MIT License. See LICENSE file in the project root for full license information.
  7.  
  8. #endregion
  9.  
  10. using System.Diagnostics;
  11. using System.Runtime.CompilerServices;
  12.  
  13. // See related DotNetCore work by same author:
  14. // https://raw.githubusercontent.com/dotnet/coreclr/master/src/System.Private.CoreLib/shared/System/Numerics/BitOperations.cs
  15.  
  16. // Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson:
  17. // http://graphics.stanford.edu/~seander/bithacks.html
  18.  
  19. /// <summary>
  20. /// Utility methods for intrinsic bit-twiddling operations.
  21. /// The methods use hardware intrinsics when available on the underlying platform,
  22. /// otherwise they use optimized software fallbacks.
  23. /// </summary>
  24. public static class BitOps {
  25.     #region ExtractBit
  26.  
  27.     /// <summary>
  28.     /// Reads whether the specified bit in a mask is set.
  29.     /// Similar in behavior to the x86 instruction BT.
  30.     /// </summary>
  31.     /// <param name="value">The value.</param>
  32.     /// <param name="bitOffset">The ordinal position of the bit to read.
  33.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  34.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  35.     public static bool ExtractBit(byte value, int bitOffset)
  36.     // For bit-length N, it is conventional to treat N as congruent modulo-N under the shift operation.
  37.     // So for uint, 1 << 33 == 1 << 1, and likewise 1 << -46 == 1 << +18.
  38.     // Note -46 % 32 == -14. But -46 & 31 (0011_1111) == +18.
  39.     // So we use & not %.
  40.     {
  41.         uint mask = 1u << (bitOffset & 7);
  42.         return (value & mask) != 0;
  43.     }
  44.  
  45.     /// Reads whether the specified bit in a mask is set.
  46.     /// Similar in behavior to the x86 instruction BT.
  47.     /// </summary>
  48.     /// <param name="value">The mask.</param>
  49.     /// <param name="bitOffset">The ordinal position of the bit to read.
  50.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  51.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52.     public static bool ExtractBit(ushort value, int bitOffset) {
  53.         uint mask = 1u << (bitOffset & 15);
  54.         return (value & mask) != 0;
  55.     }
  56.  
  57.     /// <summary>
  58.     /// Reads whether the specified bit in a mask is set.
  59.     /// Similar in behavior to the x86 instruction BT.
  60.     /// </summary>
  61.     /// <param name="value">The value.</param>
  62.     /// <param name="bitOffset">The ordinal position of the bit to read.
  63.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  64.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  65.     public static bool ExtractBit(uint value, int bitOffset) {
  66.         uint mask = 1u << bitOffset;
  67.         return (value & mask) != 0;
  68.     }
  69.  
  70.     /// <summary>
  71.     /// Reads whether the specified bit in a mask is set.
  72.     /// Similar in behavior to the x86 instruction BT.
  73.     /// </summary>
  74.     /// <param name="value">The mask.</param>
  75.     /// <param name="bitOffset">The ordinal position of the bit to read.
  76.     /// Any value outside the range [0..63] is treated as congruent mod 63.</param>
  77.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  78.     public static bool ExtractBit(ulong value, int bitOffset) {
  79.         ulong mask = 1ul << bitOffset;
  80.         return (value & mask) != 0;
  81.     }
  82.  
  83.     #endregion
  84.  
  85.     #region WriteBit
  86.  
  87.     /// <summary>
  88.     /// Conditionally writes the specified bit in a mask and returns the new value.
  89.     /// Similar in behavior to the x86 instructions BTS and BTR.
  90.     /// </summary>
  91.     /// <param name="value">The mask.</param>
  92.     /// <param name="bitOffset">The ordinal position of the bit to write.
  93.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  94.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  95.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  96.     public static byte WriteBit(byte value, int bitOffset, bool on) {
  97.         uint mask = 1u << (bitOffset & 7);
  98.  
  99.         if (on)
  100.             return (byte)(value | mask);
  101.  
  102.         return (byte)(value & ~mask);
  103.     }
  104.  
  105.     /// <summary>
  106.     /// Writes the specified bit in a mask and returns the new value.
  107.     /// Similar in behavior to the x86 instructions BTS and BTR.
  108.     /// Executes without branching.
  109.     /// </summary>
  110.     /// <param name="value">The mask.</param>
  111.     /// <param name="bitOffset">The ordinal position of the bit to write.
  112.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  113.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  114.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  115.     public static ushort WriteBit(ushort value, int bitOffset, bool on) {
  116.         uint mask = 1u << (bitOffset & 15);
  117.  
  118.         if (on)
  119.             return (ushort)(value | mask);
  120.  
  121.         return (ushort)(value & ~mask);
  122.     }
  123.  
  124.     /// <summary>
  125.     /// Conditionally writes the specified bit in a mask and returns the new value.
  126.     /// Similar in behavior to the x86 instructions BTS and BTR.
  127.     /// </summary>
  128.     /// <param name="value">The mask.</param>
  129.     /// <param name="bitOffset">The ordinal position of the bit to write.
  130.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  131.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  132.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  133.     public static uint WriteBit(uint value, int bitOffset, bool on) {
  134.         uint mask = 1u << bitOffset;
  135.  
  136.         if (on)
  137.             return value | mask;
  138.  
  139.         return value & ~mask;
  140.     }
  141.  
  142.     /// <summary>
  143.     /// Writes the specified bit in a mask and returns the new value.
  144.     /// Similar in behavior to the x86 instructions BTS and BTR.
  145.     /// Executes without branching.
  146.     /// </summary>
  147.     /// <param name="value">The mask.</param>
  148.     /// <param name="bitOffset">The ordinal position of the bit to write.
  149.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  150.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  151.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  152.     public static ulong WriteBit(ulong value, int bitOffset, bool on) {
  153.         ulong mask = 1ul << bitOffset;
  154.  
  155.         if (on)
  156.             return value | mask;
  157.  
  158.         return value & ~mask;
  159.     }
  160.  
  161.     /// <summary>
  162.     /// Conditionally writes the specified bit in a mask and returns whether it was originally set.
  163.     /// Similar in behavior to the x86 instructions BTS and BTR.
  164.     /// </summary>
  165.     /// <param name="value">The mask.</param>
  166.     /// <param name="bitOffset">The ordinal position of the bit to write.
  167.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  168.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  169.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  170.     public static bool WriteBit(ref byte value, int bitOffset, bool on) {
  171.         uint mask = 1u << (bitOffset & 7);
  172.         bool btw = (value & mask) != 0;
  173.  
  174.         if (on)
  175.             value = (byte)(value | mask);
  176.         else
  177.             value = (byte)(value & ~mask);
  178.  
  179.         return btw;
  180.     }
  181.  
  182.     /// <summary>
  183.     /// Conditionally writes the specified bit in a mask and returns whether it was originally set.
  184.     /// Similar in behavior to the x86 instructions BTS and BTR.
  185.     /// </summary>
  186.     /// <param name="value">The mask.</param>
  187.     /// <param name="bitOffset">The ordinal position of the bit to write.
  188.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  189.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  190.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  191.     public static bool WriteBit(ref ushort value, int bitOffset, bool on) {
  192.         uint mask = 1u << (bitOffset & 15);
  193.         bool btw = (value & mask) != 0;
  194.  
  195.         if (on)
  196.             value = (ushort)(value | mask);
  197.         else
  198.             value = (ushort)(value & ~mask);
  199.  
  200.         return btw;
  201.     }
  202.  
  203.     /// <summary>
  204.     /// Conditionally writes the specified bit in a mask and returns whether it was originally set.
  205.     /// Similar in behavior to the x86 instructions BTS and BTR.
  206.     /// </summary>
  207.     /// <param name="value">The mask.</param>
  208.     /// <param name="bitOffset">The ordinal position of the bit to write.
  209.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  210.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  211.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  212.     public static bool WriteBit(ref uint value, int bitOffset, bool on) {
  213.         uint mask = 1u << bitOffset;
  214.         bool btw = (value & mask) != 0;
  215.  
  216.         if (on)
  217.             value |= mask;
  218.         else
  219.             value &= ~mask;
  220.  
  221.         return btw;
  222.     }
  223.  
  224.     /// <summary>
  225.     /// Conditionally writes the specified bit in a mask and returns whether it was originally set.
  226.     /// Similar in behavior to the x86 instructions BTS and BTR.
  227.     /// </summary>
  228.     /// <param name="value">The mask.</param>
  229.     /// <param name="bitOffset">The ordinal position of the bit to write.
  230.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  231.     /// <param name="on">True to set the bit to 1, or false to set it to 0.</param>
  232.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  233.     public static bool WriteBit(ref ulong value, int bitOffset, bool on) {
  234.         ulong mask = 1ul << bitOffset;
  235.         bool btw = (value & mask) != 0;
  236.  
  237.         if (on)
  238.             value |= mask;
  239.         else
  240.             value &= ~mask;
  241.  
  242.         return btw;
  243.     }
  244.  
  245.     #endregion
  246.  
  247.     #region ClearBit
  248.  
  249.     /// <summary>
  250.     /// Clears the specified bit in a mask and returns the new value.
  251.     /// </summary>
  252.     /// <param name="value">The value.</param>
  253.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  254.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  255.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  256.     public static byte ClearBit(byte value, int bitOffset) {
  257.         uint mask = 1u << (bitOffset & 7);
  258.         return (byte)(value & ~mask);
  259.     }
  260.  
  261.     /// <summary>
  262.     /// Clears the specified bit in a mask and returns the new value.
  263.     /// </summary>
  264.     /// <param name="value">The mask.</param>
  265.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  266.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  267.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  268.     public static ushort ClearBit(ushort value, int bitOffset) {
  269.         uint mask = 1u << (bitOffset & 15);
  270.         return (ushort)(value & ~mask);
  271.     }
  272.  
  273.     /// <summary>
  274.     /// Clears the specified bit in a mask and returns the new value.
  275.     /// </summary>
  276.     /// <param name="value">The value.</param>
  277.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  278.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  279.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  280.     public static uint ClearBit(uint value, int bitOffset) {
  281.         uint mask = 1u << bitOffset;
  282.         return value & ~mask;
  283.     }
  284.  
  285.     /// <summary>
  286.     /// Clears the specified bit in a mask and returns the new value.
  287.     /// </summary>
  288.     /// <param name="value">The mask.</param>
  289.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  290.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  291.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  292.     public static ulong ClearBit(ulong value, int bitOffset) {
  293.         ulong mask = 1ul << bitOffset;
  294.         return value & ~mask;
  295.     }
  296.  
  297.     /// <summary>
  298.     /// Clears the specified bit in a mask and returns whether it was originally set.
  299.     /// Similar in behavior to the x86 instruction BTR.
  300.     /// </summary>
  301.     /// <param name="value">The value.</param>
  302.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  303.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  304.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  305.     public static bool ClearBit(ref byte value, int bitOffset) {
  306.         uint mask = 1u << (bitOffset & 7);
  307.         bool btr = (value & mask) != 0;
  308.  
  309.         value = (byte)(value & ~mask);
  310.  
  311.         return btr;
  312.     }
  313.  
  314.     /// <summary>
  315.     /// Clears the specified bit in a mask and returns whether it was originally set.
  316.     /// Similar in behavior to the x86 instruction BTR.
  317.     /// </summary>
  318.     /// <param name="value">The mask.</param>
  319.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  320.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  321.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  322.     public static bool ClearBit(ref ushort value, int bitOffset) {
  323.         uint mask = 1u << (bitOffset & 15);
  324.         bool btr = (value & mask) != 0;
  325.  
  326.         value = (ushort)(value & ~mask);
  327.  
  328.         return btr;
  329.     }
  330.  
  331.     /// <summary>
  332.     /// Clears the specified bit in a mask and returns whether it was originally set.
  333.     /// Similar in behavior to the x86 instruction BTR.
  334.     /// </summary>
  335.     /// <param name="value">The value.</param>
  336.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  337.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  338.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  339.     public static bool ClearBit(ref uint value, int bitOffset) {
  340.         uint mask = 1u << bitOffset;
  341.         bool btr = (value & mask) != 0;
  342.  
  343.         value &= ~mask;
  344.  
  345.         return btr;
  346.     }
  347.  
  348.     /// <summary>
  349.     /// Clears the specified bit in a mask and returns whether it was originally set.
  350.     /// Similar in behavior to the x86 instruction BTR.
  351.     /// </summary>
  352.     /// <param name="value">The mask.</param>
  353.     /// <param name="bitOffset">The ordinal position of the bit to clear.
  354.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  355.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  356.     public static bool ClearBit(ref ulong value, int bitOffset) {
  357.         ulong mask = 1ul << bitOffset;
  358.         bool btr = (value & mask) != 0;
  359.  
  360.         value &= ~mask;
  361.  
  362.         return btr;
  363.     }
  364.  
  365.     #endregion
  366.  
  367.     #region InsertBit
  368.  
  369.     /// <summary>
  370.     /// Sets the specified bit in a mask and returns the new value.
  371.     /// </summary>
  372.     /// <param name="value">The value.</param>
  373.     /// <param name="bitOffset">The ordinal position of the bit to write.
  374.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  375.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  376.     public static byte InsertBit(byte value, int bitOffset) {
  377.         uint mask = 1u << (bitOffset & 7);
  378.         return (byte)(value | mask);
  379.     }
  380.  
  381.     /// <summary>
  382.     /// Sets the specified bit in a mask and returns the new value.
  383.     /// </summary>
  384.     /// <param name="value">The mask.</param>
  385.     /// <param name="bitOffset">The ordinal position of the bit to write.
  386.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  387.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  388.     public static ushort InsertBit(ushort value, int bitOffset) {
  389.         uint mask = 1u << (bitOffset & 15);
  390.         return (ushort)(value | mask);
  391.     }
  392.  
  393.     /// <summary>
  394.     /// Sets the specified bit in a mask and returns the new value.
  395.     /// </summary>
  396.     /// <param name="value">The value.</param>
  397.     /// <param name="bitOffset">The ordinal position of the bit to write.
  398.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  399.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  400.     public static uint InsertBit(uint value, int bitOffset) {
  401.         uint mask = 1u << bitOffset;
  402.         return value | mask;
  403.     }
  404.  
  405.     /// <summary>
  406.     /// Sets the specified bit in a mask and returns the new value.
  407.     /// </summary>
  408.     /// <param name="value">The mask.</param>
  409.     /// <param name="bitOffset">The ordinal position of the bit to write.
  410.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  411.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  412.     public static ulong InsertBit(ulong value, int bitOffset) {
  413.         ulong mask = 1ul << bitOffset;
  414.         return value | mask;
  415.     }
  416.  
  417.     /// <summary>
  418.     /// Sets the specified bit in a mask and returns whether it was originally set.
  419.     /// Similar in behavior to the x86 instruction BTS.
  420.     /// </summary>
  421.     /// <param name="value">The value.</param>
  422.     /// <param name="bitOffset">The ordinal position of the bit to write.
  423.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  424.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  425.     public static bool InsertBit(ref byte value, int bitOffset) {
  426.         uint mask = 1u << (bitOffset & 7);
  427.         bool bts = (value & mask) != 0;
  428.  
  429.         value = (byte)(value | mask);
  430.  
  431.         return bts;
  432.     }
  433.  
  434.     /// <summary>
  435.     /// Sets the specified bit in a mask and returns whether it was originally set.
  436.     /// Similar in behavior to the x86 instruction BTS.
  437.     /// </summary>
  438.     /// <param name="value">The mask.</param>
  439.     /// <param name="bitOffset">The ordinal position of the bit to write.
  440.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  441.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  442.     public static bool InsertBit(ref ushort value, int bitOffset) {
  443.         uint mask = 1u << (bitOffset & 15);
  444.         bool bts = (value & mask) != 0;
  445.  
  446.         value = (ushort)(value | mask);
  447.  
  448.         return bts;
  449.     }
  450.  
  451.     /// <summary>
  452.     /// Sets the specified bit in a mask and returns whether it was originally set.
  453.     /// Similar in behavior to the x86 instruction BTS.
  454.     /// </summary>
  455.     /// <param name="value">The value.</param>
  456.     /// <param name="bitOffset">The ordinal position of the bit to write.
  457.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  458.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  459.     public static bool InsertBit(ref uint value, int bitOffset) {
  460.         uint mask = 1u << bitOffset;
  461.         bool bts = (value & mask) != 0;
  462.  
  463.         value |= mask;
  464.  
  465.         return bts;
  466.     }
  467.  
  468.     /// <summary>
  469.     /// Sets the specified bit in a mask and returns whether it was originally set.
  470.     /// Similar in behavior to the x86 instruction BTS.
  471.     /// </summary>
  472.     /// <param name="value">The mask.</param>
  473.     /// <param name="bitOffset">The ordinal position of the bit to write.
  474.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  475.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  476.     public static bool InsertBit(ref ulong value, int bitOffset) {
  477.         ulong mask = 1ul << bitOffset;
  478.         bool bts = (value & mask) != 0;
  479.  
  480.         value |= mask;
  481.  
  482.         return bts;
  483.     }
  484.  
  485.     #endregion
  486.  
  487.     #region ComplementBit
  488.  
  489.     // Truth table (1)
  490.     // v   m  | ~m  ^v  ~
  491.     // 00  01 | 10  10  01
  492.     // 01  01 | 10  11  00
  493.     // 10  01 | 10  00  11
  494.     // 11  01 | 10  01  10
  495.     //
  496.     // 00  10 | 01  01  10
  497.     // 01  10 | 01  00  11
  498.     // 10  10 | 01  11  00
  499.     // 11  10 | 01  10  01
  500.  
  501.     /// <summary>
  502.     /// Complements the specified bit in a mask and returns the new value.
  503.     /// </summary>
  504.     /// <param name="value">The mask.</param>
  505.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  506.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  507.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  508.     public static byte ComplementBit(byte value, int bitOffset) {
  509.         uint mask = 1u << (bitOffset & 7);
  510.         return (byte)~(~mask ^ value);
  511.     }
  512.  
  513.     /// <summary>
  514.     /// Complements the specified bit in a mask and returns the new value.
  515.     /// </summary>
  516.     /// <param name="value">The mask.</param>
  517.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  518.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  519.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  520.     public static ushort ComplementBit(ushort value, int bitOffset) {
  521.         uint mask = 1u << (bitOffset & 15);
  522.         return (ushort)~(~mask ^ value);
  523.     }
  524.  
  525.     /// <summary>
  526.     /// Complements the specified bit in a mask and returns the new value.
  527.     /// </summary>
  528.     /// <param name="value">The mask.</param>
  529.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  530.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  531.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  532.     public static uint ComplementBit(uint value, int bitOffset) {
  533.         uint mask = 1u << bitOffset;
  534.         return ~(~mask ^ value);
  535.     }
  536.  
  537.     /// <summary>
  538.     /// Complements the specified bit in a mask and returns whether it was originally set.
  539.     /// </summary>
  540.     /// <param name="value">The mask.</param>
  541.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  542.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  543.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  544.     public static ulong ComplementBit(ulong value, int bitOffset) {
  545.         ulong mask = 1ul << bitOffset;
  546.         return ~(~mask ^ value);
  547.     }
  548.  
  549.     /// <summary>
  550.     /// Complements the specified bit in a mask and returns whether it was originally set.
  551.     /// Similar in behavior to the x86 instruction BTC.
  552.     /// </summary>
  553.     /// <param name="value">The mask.</param>
  554.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  555.     /// Any value outside the range [0..7] is treated as congruent mod 8.</param>
  556.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  557.     public static bool ComplementBit(ref byte value, int bitOffset) {
  558.         uint mask = 1u << (bitOffset & 7);
  559.         bool btc = (value & mask) != 0;
  560.  
  561.         value = (byte)~(~mask ^ value);
  562.  
  563.         return btc;
  564.     }
  565.  
  566.     /// <summary>
  567.     /// Complements the specified bit in a mask and returns whether it was originally set.
  568.     /// Similar in behavior to the x86 instruction BTC.
  569.     /// </summary>
  570.     /// <param name="value">The mask.</param>
  571.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  572.     /// Any value outside the range [0..15] is treated as congruent mod 16.</param>
  573.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  574.     public static bool ComplementBit(ref ushort value, int bitOffset) {
  575.         uint mask = 1u << (bitOffset & 15);
  576.         bool btc = (value & mask) != 0;
  577.  
  578.         value = (ushort)~(~mask ^ value);
  579.  
  580.         return btc;
  581.     }
  582.  
  583.     /// <summary>
  584.     /// Complements the specified bit in a mask and returns whether it was originally set.
  585.     /// Similar in behavior to the x86 instruction BTC.
  586.     /// </summary>
  587.     /// <param name="value">The mask.</param>
  588.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  589.     /// Any value outside the range [0..31] is treated as congruent mod 32.</param>
  590.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  591.     public static bool ComplementBit(ref uint value, int bitOffset) {
  592.         uint mask = 1u << bitOffset;
  593.         bool btc = (value & mask) != 0;
  594.  
  595.         value = ~(~mask ^ value);
  596.  
  597.         return btc;
  598.     }
  599.  
  600.     /// <summary>
  601.     /// Complements the specified bit in a mask and returns whether it was originally set.
  602.     /// Similar in behavior to the x86 instruction BTC.
  603.     /// </summary>
  604.     /// <param name="value">The mask.</param>
  605.     /// <param name="bitOffset">The ordinal position of the bit to complement.
  606.     /// Any value outside the range [0..63] is treated as congruent mod 64.</param>
  607.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  608.     public static bool ComplementBit(ref ulong value, int bitOffset) {
  609.         ulong mask = 1ul << bitOffset;
  610.         bool btc = (value & mask) != 0;
  611.  
  612.         value = ~(~mask ^ value);
  613.  
  614.         return btc;
  615.     }
  616.  
  617.     #endregion
  618.  
  619.     /// <summary>
  620.     /// Casts the underlying <see cref="byte"/> value from a <see cref="bool"/> without normalization.
  621.     /// Does not incur branching.
  622.     /// </summary>
  623.     /// <param name="condition">The value to cast.</param>
  624.     /// <returns>Returns 0 if <paramref name="condition"/> is false, else returns a non-zero number per the remarks.</returns>
  625.     /// <remarks>The ECMA 335 CLI specification permits a "true" boolean value to be represented by any nonzero value.
  626.     /// See https://github.com/dotnet/roslyn/blob/master/docs/compilers/Boolean%20Representation.md
  627.     /// </remarks>
  628.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  629.     public static byte AsByte(bool condition)
  630.         => Unsafe.As<bool, byte>(ref condition);
  631.  
  632.     /// <summary>
  633.     /// Casts the underlying <see cref="byte"/> value from a <see cref="bool"/> without normalization.
  634.     /// Does not incur branching.
  635.     /// </summary>
  636.     /// <param name="condition">The value to cast.</param>
  637.     /// <returns>Returns 0 if <paramref name="condition"/> is false, else returns a non-zero number per the remarks.</returns>
  638.     /// <remarks>The ECMA 335 CLI specification permits a "true" boolean value to be represented by any nonzero value.
  639.     /// See https://github.com/dotnet/roslyn/blob/master/docs/compilers/Boolean%20Representation.md
  640.     /// </remarks>
  641.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  642.     public static byte AsByte(ref bool condition)
  643.         => Unsafe.As<bool, byte>(ref condition);
  644.  
  645.     /// <summary>
  646.     /// Checks a <paramref name="condition"/> and returns <paramref name="trueValue"/> if it is true.
  647.     /// Else returns 0.
  648.     /// Does not incur branching.
  649.     /// </summary>
  650.     /// <param name="condition">The condition to check.</param>
  651.     /// <param name="trueValue">The value to return if the <paramref name="condition"/> is true.</param>
  652.     /// <returns></returns>
  653.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  654.     public static uint Iff(bool condition, uint trueValue)
  655.         => Iff(ref condition, trueValue);
  656.  
  657.     /// <summary>
  658.     /// Checks a <paramref name="condition"/> and returns <paramref name="trueValue"/> if it is true.
  659.     /// Else returns 0.
  660.     /// Does not incur branching.
  661.     /// </summary>
  662.     /// <param name="condition">The condition to check.</param>
  663.     /// <param name="trueValue">The value to return if the <paramref name="condition"/> is true.</param>
  664.     /// <returns></returns>
  665.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  666.     public static uint Iff(ref bool condition, uint trueValue) {
  667.         uint sel = (uint)-Unsafe.As<bool, byte>(ref condition); // T=FFFFFFFF, F=00000000
  668.         Debug.Assert(sel == 0xFFFF_FFFF || sel == 0); // CLR permits other values for bool
  669.  
  670.         return trueValue & sel;
  671.     }
  672.  
  673.     /// <summary>
  674.     /// Checks a <paramref name="condition"/> and returns <paramref name="trueValue"/> if it is true.
  675.     /// Else returns <paramref name="falseValue"/>.
  676.     /// Does not incur branching.
  677.     /// </summary>
  678.     /// <param name="condition">The condition to check.</param>
  679.     /// <param name="trueValue">The value to return if the <paramref name="condition"/> is true.</param>
  680.     /// <param name="falseValue">The value to return if the <paramref name="condition"/> is false.</param>
  681.     /// <returns></returns>
  682.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  683.     public static uint Iff(bool condition, uint trueValue, uint falseValue)
  684.         => Iff(ref condition, trueValue, falseValue);
  685.  
  686.     /// <summary>
  687.     /// Checks a <paramref name="condition"/> and returns <paramref name="trueValue"/> if it is true.
  688.     /// Else returns <paramref name="falseValue"/>.
  689.     /// Does not incur branching.
  690.     /// </summary>
  691.     /// <param name="condition">The condition to check.</param>
  692.     /// <param name="trueValue">The value to return if the <paramref name="condition"/> is true.</param>
  693.     /// <param name="falseValue">The value to return if the <paramref name="condition"/> is false.</param>
  694.     /// <returns></returns>
  695.     [MethodImpl(MethodImplOptions.AggressiveInlining)]
  696.     public static uint Iff(ref bool condition, uint trueValue, uint falseValue) {
  697.         // Branchless equivalent of: value == 0 ? x : y
  698.         uint sel = (uint)-Unsafe.As<bool, byte>(ref condition); // T=FFFFFFFF, F=00000000
  699.         Debug.Assert(sel == 0xFFFF_FFFF || sel == 0); // CLR permits other values for bool
  700.  
  701.         uint tv = trueValue & sel;
  702.         uint fv = /*Bmi1.IsSupported ? Bmi1.AndNot(falseValue, sel) :*/ falseValue & ~sel;
  703.         return tv | fv;
  704.     }
  705. }
Advertisement
Add Comment
Please, Sign In to add comment