diff --git a/mpir.net/mpir.net-tests/HugeIntTests/IO.cs b/mpir.net/mpir.net-tests/HugeIntTests/IO.cs index 6fd10e7e..4bb6b035 100644 --- a/mpir.net/mpir.net-tests/HugeIntTests/IO.cs +++ b/mpir.net/mpir.net-tests/HugeIntTests/IO.cs @@ -210,6 +210,70 @@ namespace MPIR.Tests.HugeIntTests } } } + + [TestMethod] + public void ImportExportAllocating() + { + using (var a = new HugeInt("0x10123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")) + using (var b = new HugeInt()) + { + foreach (var order in Enum.GetValues(typeof(LimbOrder)).Cast()) + foreach (var endianness in Enum.GetValues(typeof(Endianness)).Cast()) + foreach (var nails in new[] { 0, 5, 10, 16 }) + foreach (var size in new[] { 8, 11, 16 }) + { + var bytes = a.Export(size, order, endianness, nails); + var expected = (int)System.Math.Ceiling(193m / (size * 8 - nails)); + Assert.AreEqual(expected, bytes.Length / size); + + b.SetTo(0); + b.Import(bytes, (ulong)(bytes.Length / size), size, order, endianness, nails); + Assert.AreEqual(a, b); + } + } + } + + [TestMethod] + public void ImportExportAllocatingShort() + { + using (var a = new HugeInt("0x10123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")) + using (var b = new HugeInt()) + { + foreach (var order in Enum.GetValues(typeof(LimbOrder)).Cast()) + foreach (var endianness in Enum.GetValues(typeof(Endianness)).Cast()) + foreach (var nails in new[] { 0, 5, 10, 16 }) + foreach (var size in new[] { 8, 11, 16 }) + { + var bytes = a.Export(size, order, endianness, nails); + var expected = (int)System.Math.Ceiling(193m / (size * 8 - nails)); + Assert.AreEqual(expected, bytes.Length * 2 / size); + + b.SetTo(0); + b.Import(bytes, (ulong)(bytes.Length * 2 / size), size, order, endianness, nails); + Assert.AreEqual(a, b); + } + } + } + + [TestMethod] + public void ImportExportAllocatingZero() + { + using (var a = new HugeInt()) + using (var b = new HugeInt()) + { + var order = LimbOrder.LeastSignificantFirst; + var endianness = Endianness.Native; + var nails = 5; + var size = 4; + + var bytes = a.Export(size, order, endianness, nails); + Assert.AreEqual(0, bytes.Length); + + b.SetTo(1); + b.Import(bytes, 0, size, order, endianness, nails); + Assert.AreEqual(a, b); + } + } //more tests coming here } } diff --git a/mpir.net/mpir.net/HugeInt.h b/mpir.net/mpir.net/HugeInt.h index b7c9241c..4a121edb 100644 --- a/mpir.net/mpir.net/HugeInt.h +++ b/mpir.net/mpir.net/HugeInt.h @@ -1878,6 +1878,12 @@ namespace MPIR /// The number of most-significant bits to ignore in each "limb." generic where T : value class void Import(array^ data, size_t limbCount, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) { + if(limbCount == 0) + { + mpz_set_ui(_value, 0); + return; + } + PIN(data); mpz_import(_value, limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, pinned_data); } @@ -1889,8 +1895,7 @@ namespace MPIR /// Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array. /// Array of binary "limbs" to export to. /// Elements don't necessarily need to be of the size; the data is interpreted as a flat byte array. - /// The total size of the array in bytes must be sufficient for the export. - /// If null, a new array is automatically allocated. + /// The total size of the array in bytes must be sufficient for the export. /// Number of bytes per "limb." /// Specifies the order of the "limbs." /// Specifies the byte order within each "limb." @@ -1900,17 +1905,39 @@ namespace MPIR /// If the number is zero, then the count returned will be zero and nothing written to the data. generic where T : value class size_t Export(array^ data, int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) { - if(IS_NULL(data)) - { - //todo allocate - } - PIN(data); size_t limbCount; mpz_export(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value); return limbCount; } + /// + /// Exports the absolute value of the number to arbitrary words of binary data. An array of type T is allocated for the export. + /// The sign of op is ignored. + /// + /// Type of element in the data array. This must be a value type, but does not need to represent a single limb. Data is interpreted as a flat byte array. + /// Number of bytes per "limb." + /// Specifies the order of the "limbs." + /// Specifies the byte order within each "limb." + /// The number of most-significant bits to reserve, and set to zero, in each "limb." + /// An array of type T containing the exported limb data. + /// If the number is non-zero, then the most significant word produced will be non-zero. + /// If the number is zero, then a zero-length array is returned. + generic where T : value class array^ Export(int bytesPerLimb, LimbOrder limbOrder, Endianness endianness, int nails) + { + if(this->Sign() == 0) + return gcnew array(0); + + auto bitsPerLimb = 8 * bytesPerLimb - nails; + auto limbCount = (mpz_sizeinbase(_value, 2) - 1) / bitsPerLimb + 1; + auto arrayCount = (limbCount * bytesPerLimb - 1) / sizeof(T) + 1; + auto data = gcnew array(arrayCount); + + PIN(data); + mpz_export(pinned_data, &limbCount, (int)limbOrder, bytesPerLimb, (int)endianness, nails, _value); + return data; + } + internal: size_t ReadNoWhite(TextReader^ reader, int base, size_t nread);