@@ -19,9 +19,11 @@ private alias cop(string op : "+") = addu;
1919private enum inverseSign (string op) = op == " +" ? " -" : " +" ;
2020
2121package immutable hexStringErrorMsg = " Incorrect hex string for BigUIntView.fromHexString" ;
22+ package immutable binaryStringErrorMsg = " Incorrect binary string for BigUIntView.fromBinaryString" ;
2223version (D_Exceptions)
2324{
2425 package immutable hexStringException = new Exception (hexStringErrorMsg);
26+ package immutable binaryStringException = new Exception (binaryStringErrorMsg);
2527}
2628
2729/+ +
@@ -721,6 +723,144 @@ struct BigUIntView(W, WordEndian endian = TargetEndian)
721723 expectThrow(" __abcd__efab_cdef__" );
722724 expectThrow(" __abcd__efab__cdef__" );
723725 }
726+
727+ /+ +
728+ +/
729+ static BigUIntView fromBinaryString (C, bool allowUnderscores = false )(scope const (C)[] str)
730+ @trusted pure
731+ if (isSomeChar! C)
732+ {
733+ auto length = str.length / (W.sizeof * 8 ) + (str.length % (W.sizeof * 8 ) != 0 );
734+ auto data = new Unqual! W[length];
735+ auto view = BigUIntView! (Unqual! W, endian)(data);
736+ if (view.fromBinaryStringImpl! (C, allowUnderscores)(str))
737+ return BigUIntView (cast (W[])view.coefficients);
738+ version (D_Exceptions)
739+ throw binaryStringException;
740+ else
741+ assert (0 , binaryStringErrorMsg);
742+ }
743+
744+ static if (isMutable! W)
745+ /+ +
746+ +/
747+ bool fromBinaryStringImpl (C, bool allowUnderscores = false )(scope const (C)[] str)
748+ @safe pure @nogc nothrow scope
749+ if (isSomeChar! C)
750+ {
751+ pragma (inline, false );
752+ import mir.utility: _expect;
753+ static if (allowUnderscores) {
754+ if (_expect(str.length == 0 , false )) // can't tell how big the coeff array needs to be, rely on a runtime check
755+ return false ;
756+ } else {
757+ if (_expect(str.length == 0 || str.length > coefficients.length * W.sizeof * 8 , false ))
758+ return false ;
759+ }
760+
761+ leastSignificant = 0 ;
762+ auto work = topLeastSignificantPart(1 );
763+ W current;
764+ size_t i, j;
765+ static if (allowUnderscores) bool recentUnderscore;
766+
767+ do
768+ {
769+ ubyte c;
770+ switch (str[$ - ++ i])
771+ {
772+ case ' 0' : c = 0x0 ; break ;
773+ case ' 1' : c = 0x1 ; break ;
774+ static if (allowUnderscores)
775+ {
776+ case ' _' :
777+ if (recentUnderscore) return false ;
778+ recentUnderscore = true ;
779+ continue ;
780+ }
781+ default : return false ;
782+ }
783+ ++ j;
784+ static if (allowUnderscores) recentUnderscore = false ;
785+ // how far do we need to shift to get to the top bit?
786+ enum s = W.sizeof * 8 - 1 ;
787+ // shift number to the top most bit
788+ W cc = cast (W)(W(c) << s);
789+ // shift unsigned right 1 bit
790+ current >>>= 1 ;
791+ // add number to top most bit of current var
792+ current |= cc;
793+ if (j % (W.sizeof * 8 ) == 0 ) // is this packed var full?
794+ {
795+ work.mostSignificant = current;
796+ current = 0 ;
797+ if (_expect(work.coefficients.length < coefficients.length, true ))
798+ {
799+ work = topLeastSignificantPart(work.coefficients.length + 1 );
800+ }
801+ else if (i < str.length) // if we've run out of coefficients before reaching the end of the string, error
802+ {
803+ return false ;
804+ }
805+ }
806+ }
807+ while (i < str.length);
808+
809+ static if (allowUnderscores)
810+ {
811+ // check for a underscore at the beginning or the end
812+ if (recentUnderscore || str[$ - 1 ] == ' _' ) return false ;
813+ }
814+
815+ if (current)
816+ {
817+ current >>>= (W.sizeof * 8 - j % (W.sizeof * 8 ));
818+ work.mostSignificant = current;
819+ }
820+
821+ coefficients = coefficients[0 .. (j / (W.sizeof * 8 ) + (j % (W.sizeof * 8 ) != 0 ))];
822+
823+ return true ;
824+ }
825+
826+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
827+ // /
828+ version (mir_bignum_test)
829+ @safe pure
830+ unittest
831+ {
832+ auto view = BigUIntView! size_t .fromBinaryString! (char , true )(" 1111_0000_0101" );
833+ assert (cast (ulong )view == 0b1111_0000_0101);
834+ }
835+
836+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
837+ // /
838+ version (mir_bignum_test)
839+ @safe pure
840+ unittest
841+ {
842+ // Check that invalid underscores in hex literals throw an error.
843+ void expectThrow (const (char )[] input) {
844+ bool caught = false ;
845+ try {
846+ auto view = BigUIntView! size_t .fromBinaryString! (char , true )(input);
847+ } catch (Exception e) {
848+ caught = true ;
849+ }
850+
851+ assert (caught);
852+ }
853+
854+ expectThrow(" abcd" );
855+ expectThrow(" 0101__1011__0111" );
856+ expectThrow(" _0101_1011_0111" );
857+ expectThrow(" _0101_1011_0111_" );
858+ expectThrow(" _0101_1011_0111__" );
859+ expectThrow(" __0101_1011_0111_" );
860+ expectThrow(" __0101_1011_0111__" );
861+ expectThrow(" __0101__1011_0111__" );
862+ expectThrow(" __1011__0111__1011__" );
863+ }
724864
725865 static if (isMutable! W && W.sizeof >= 4 )
726866 /+ +
@@ -1502,6 +1642,53 @@ struct BigIntView(W, WordEndian endian = TargetEndian)
15021642 return unsigned.fromHexStringImpl! (C, allowUnderscores)(str);
15031643 }
15041644
1645+ /+ +
1646+ +/
1647+ static BigIntView fromBinaryString (C, bool allowUnderscores = false )(scope const (C)[] str)
1648+ @trusted pure
1649+ if (isSomeChar! C)
1650+ {
1651+ auto length = str.length / (W.sizeof * 8 ) + (str.length % (W.sizeof * 8 ) != 0 );
1652+ auto ret = BigIntView! (Unqual! W, endian)(new Unqual! W[length]);
1653+ if (ret.fromBinaryStringImpl! (C, allowUnderscores)(str))
1654+ return cast (BigIntView) ret;
1655+ version (D_Exceptions)
1656+ throw binaryStringException;
1657+ else
1658+ assert (0 , binaryStringErrorMsg);
1659+ }
1660+
1661+ static if (isMutable! W)
1662+ /+ +
1663+ +/
1664+ bool fromBinaryStringImpl (C, bool allowUnderscores = false )(scope const (C)[] str)
1665+ @safe pure @nogc nothrow
1666+ if (isSomeChar! C)
1667+ {
1668+ pragma (inline, false );
1669+ import mir.utility: _expect;
1670+
1671+ assert (unsigned.coefficients.length);
1672+
1673+ if (_expect(str.length == 0 , false ))
1674+ return false ;
1675+
1676+ sign = false ;
1677+
1678+ if (str[0 ] == ' -' )
1679+ {
1680+ sign = true ;
1681+ str = str[1 .. $];
1682+ }
1683+ else
1684+ if (_expect(str[0 ] == ' +' , false ))
1685+ {
1686+ str = str[1 .. $];
1687+ }
1688+
1689+ return unsigned.fromBinaryStringImpl! (C, allowUnderscores)(str);
1690+ }
1691+
15051692 // /
15061693 T opCast (T, bool wordNormalized = false , bool nonZero = false )() scope const
15071694 if (isFloatingPoint! T && isMutable! T)
@@ -1522,6 +1709,16 @@ struct BigIntView(W, WordEndian endian = TargetEndian)
15221709 assert (a == - 0xa .fbbfae3cd0bp+ 124 );
15231710 }
15241711
1712+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1713+ // /
1714+ version (mir_bignum_test)
1715+ @safe pure
1716+ unittest
1717+ {
1718+ auto a = cast (double ) BigIntView! size_t .fromBinaryString(" -10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001010011101" );
1719+ assert (a == - 0xa .fbbfae3cd0bp+ 124 );
1720+ }
1721+
15251722 static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
15261723 // /
15271724 version (mir_bignum_test)
@@ -1532,6 +1729,16 @@ struct BigIntView(W, WordEndian endian = TargetEndian)
15321729 assert (a == - 0xa .fbbfae3cd0bp+ 124 );
15331730 }
15341731
1732+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1733+ // /
1734+ version (mir_bignum_test)
1735+ @safe pure
1736+ unittest
1737+ {
1738+ auto a = cast (double ) BigIntView! size_t .fromBinaryString! (char , true )(" -1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_1001_1101" );
1739+ assert (a == - 0xa .fbbfae3cd0bp+ 124 );
1740+ }
1741+
15351742 // /
15361743 T opCast (T, bool nonZero = false )() scope const
15371744 if (is (T == long ) || is (T == int ))
@@ -1604,6 +1811,66 @@ struct BigIntView(W, WordEndian endian = TargetEndian)
16041811 assert (cast (int ) view == - 0x22b0021d );
16051812 }
16061813
1814+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1815+ version (mir_bignum_test)
1816+ @safe pure
1817+ unittest
1818+ {
1819+ auto view = BigIntView! size_t .fromBinaryString! (char , true )(" -10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101" );
1820+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1821+ assert (cast (int ) view == - 0x22b0021d );
1822+ }
1823+
1824+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1825+ version (mir_bignum_test)
1826+ @safe pure
1827+ unittest
1828+ {
1829+ auto view = BigIntView! size_t .fromBinaryString! (char , true )(" -1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101" );
1830+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1831+ assert (cast (int ) view == - 0x22b0021d );
1832+ }
1833+
1834+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1835+ version (mir_bignum_test)
1836+ @safe pure
1837+ unittest
1838+ {
1839+ auto view = BigIntView! ushort .fromBinaryString! (char , true )(" -10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101" );
1840+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1841+ assert (cast (int ) view == - 0x22b0021d );
1842+ }
1843+
1844+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1845+ version (mir_bignum_test)
1846+ @safe pure
1847+ unittest
1848+ {
1849+ auto view = BigIntView! ushort .fromBinaryString! (char , true )(" -1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101" );
1850+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1851+ assert (cast (int ) view == - 0x22b0021d );
1852+ }
1853+
1854+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1855+ version (mir_bignum_test)
1856+ @safe pure
1857+ unittest
1858+ {
1859+ auto view = BigIntView! ubyte .fromBinaryString! (char , true )(" -10101111101110111111101011100011110011010000101011111111001001110001010010100001110111100111000000100010101100000000001000011101" );
1860+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1861+ assert (cast (int ) view == - 0x22b0021d );
1862+ }
1863+
1864+ static if (W.sizeof == size_t .sizeof && endian == TargetEndian)
1865+ version (mir_bignum_test)
1866+ @safe pure
1867+ unittest
1868+ {
1869+ auto view = BigIntView! ubyte .fromBinaryString! (char , true )(" -1010_1111_1011_1011_1111_1010_1110_0011_1100_1101_0000_1010_1111_1111_0010_0111_0001_0100_1010_0001_1101_1110_0111_0000_0010_0010_1011_0000_0000_0010_0001_1101" );
1870+ assert (cast (long ) view == - 0x14a1de7022b0021d );
1871+ assert (cast (int ) view == - 0x22b0021d );
1872+ }
1873+
16071874 /+ +
16081875 +/
16091876 T opCast (T : Fp! coefficientSize, size_t internalRoundLastBits = 0 , bool wordNormalized = false , bool nonZero = false , size_t coefficientSize)() scope const
0 commit comments