Raw binary IO. This necessitated some refactoring to the MPIR code.
This commit is contained in:
parent
2f5bbb1f80
commit
248eb1c5dc
@ -100,6 +100,7 @@
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Conversions.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Comparisons.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\ExpressionTests.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\IO.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\Math.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\HugeIntTests\XmlCommentsTests.cs" />
|
||||
<Compile Include="..\..\..\mpir.net\mpir.net-tests\Utilities\Accessors.cs" />
|
||||
|
16
gmp-h.in
16
gmp-h.in
@ -300,6 +300,17 @@ typedef struct
|
||||
} __gmp_randstate_struct;
|
||||
typedef __gmp_randstate_struct gmp_randstate_t[1];
|
||||
|
||||
/* Output of mp?_out_raw_m */
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* allocated;
|
||||
size_t allocatedSize;
|
||||
unsigned char* written;
|
||||
size_t writtenSize;
|
||||
} __mpir_out_struct;
|
||||
typedef __mpir_out_struct mpir_out_struct[1];
|
||||
typedef __mpir_out_struct *mpir_out_ptr;
|
||||
|
||||
/* Types for function declarations in gmp files. */
|
||||
/* ??? Should not pollute user name space with these ??? */
|
||||
typedef __gmp_const __mpz_struct *mpz_srcptr;
|
||||
@ -967,6 +978,9 @@ __GMP_DECLSPEC int mpz_init_set_str __GMP_PROTO ((mpz_ptr, __gmp_const char *, i
|
||||
#define mpz_init_set_ui __gmpz_init_set_ui
|
||||
__GMP_DECLSPEC void mpz_init_set_ui __GMP_PROTO ((mpz_ptr, mpir_ui));
|
||||
|
||||
__GMP_DECLSPEC void mpz_inp_raw_p __GMP_PROTO ((mpz_ptr x, unsigned char* csize_bytes, mpir_out_ptr out));
|
||||
__GMP_DECLSPEC void mpz_inp_raw_m __GMP_PROTO ((mpz_ptr x, mpir_out_ptr out));
|
||||
|
||||
#define mpz_inp_raw __gmpz_inp_raw
|
||||
#ifdef _GMP_H_HAVE_FILE
|
||||
__GMP_DECLSPEC size_t mpz_inp_raw __GMP_PROTO ((mpz_ptr, FILE *));
|
||||
@ -1052,6 +1066,8 @@ __GMP_DECLSPEC void mpz_nextprime __GMP_PROTO ((mpz_ptr, mpz_srcptr));
|
||||
#define mpz_next_prime_candidate __gmpz_next_prime_candidate
|
||||
__GMP_DECLSPEC void mpz_next_prime_candidate __GMP_PROTO ((mpz_ptr, mpz_srcptr, gmp_randstate_t));
|
||||
|
||||
__GMP_DECLSPEC void mpz_out_raw_m __GMP_PROTO ((mpir_out_ptr, mpz_srcptr));
|
||||
|
||||
#define mpz_out_raw __gmpz_out_raw
|
||||
#ifdef _GMP_H_HAVE_FILE
|
||||
__GMP_DECLSPEC size_t mpz_out_raw __GMP_PROTO ((FILE *, mpz_srcptr));
|
||||
|
46
mpir.net/mpir.net-tests/HugeIntTests/IO.cs
Normal file
46
mpir.net/mpir.net-tests/HugeIntTests/IO.cs
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2014 Alex Dyachenko
|
||||
|
||||
This file is part of the MPIR Library.
|
||||
|
||||
The MPIR Library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
The MPIR Library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace MPIR.Tests.HugeIntTests
|
||||
{
|
||||
[TestClass]
|
||||
public class IO
|
||||
{
|
||||
[TestMethod]
|
||||
public void InputOutputRaw()
|
||||
{
|
||||
using (var a = new HugeInt("0x10123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"))
|
||||
using (var b = new HugeInt())
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
a.Value = a ^ 100;
|
||||
a.Write(ms);
|
||||
ms.Position = 0;
|
||||
b.Read(ms);
|
||||
Assert.AreEqual(a, b);
|
||||
Assert.AreEqual(ms.Length, ms.Position);
|
||||
}
|
||||
}
|
||||
//more tests coming here
|
||||
}
|
||||
}
|
@ -18,13 +18,17 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "Stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
void CustomFree (void* ptr)
|
||||
{
|
||||
CustomFree(ptr, 0);
|
||||
}
|
||||
|
||||
void CustomFree(void* ptr, size_t size)
|
||||
{
|
||||
void (*freeFunc) (void*, size_t);
|
||||
mp_get_memory_functions (NULL, NULL, &freeFunc);
|
||||
freeFunc(ptr, 0);
|
||||
freeFunc(ptr, size);
|
||||
}
|
||||
|
||||
void* CustomAllocate(size_t size)
|
||||
|
@ -22,6 +22,7 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
|
||||
void* CustomAllocate (size_t alloc_size);
|
||||
void* CustomReallocate (void* ptr, size_t new_size);
|
||||
void CustomFree (void* ptr);
|
||||
void CustomFree (void* ptr, size_t size);
|
||||
|
||||
enum EvaluationOptions : __int8
|
||||
{
|
||||
|
@ -18,7 +18,6 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "Stdafx.h"
|
||||
#include "Common.h"
|
||||
|
||||
#define DEFINE_ASSIGNMENT_PROLOG(name) void Mpir##name##Expression::AssignTo(mpz_ptr destination)
|
||||
|
||||
@ -504,4 +503,68 @@ namespace MPIR
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region IO
|
||||
|
||||
#define chunkSize 1024
|
||||
|
||||
void HugeInt::Write(Stream^ stream)
|
||||
{
|
||||
mpir_out_struct out;
|
||||
mpz_out_raw_m(out, _value);
|
||||
|
||||
auto buffer = gcnew array<unsigned char>(chunkSize);
|
||||
auto ptr = out->written;
|
||||
|
||||
while(out->writtenSize > 0)
|
||||
{
|
||||
auto len = Math::Min(chunkSize, (int)out->writtenSize);
|
||||
Marshal::Copy(IntPtr(ptr), buffer, 0, len);
|
||||
stream->Write(buffer, 0, len);
|
||||
ptr += len;
|
||||
out->writtenSize -= len;
|
||||
}
|
||||
|
||||
CustomFree(out->allocated, out->allocatedSize);
|
||||
}
|
||||
|
||||
void HugeInt::Read(Stream^ stream)
|
||||
{
|
||||
unsigned char csize_bytes[4];
|
||||
mpir_out_struct out;
|
||||
|
||||
/* 4 bytes for size */
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
auto byte = stream->ReadByte();
|
||||
if(byte < 0)
|
||||
throw gcnew Exception("Unexpected end of stream");
|
||||
|
||||
csize_bytes[i] = byte;
|
||||
}
|
||||
|
||||
mpz_inp_raw_p(_value, csize_bytes, out);
|
||||
|
||||
if(out->writtenSize != 0)
|
||||
{
|
||||
auto buffer = gcnew array<unsigned char>(chunkSize);
|
||||
auto ptr = out->written;
|
||||
auto toRead = (int)out->writtenSize;
|
||||
|
||||
while(toRead > 0)
|
||||
{
|
||||
auto len = Math::Min(chunkSize, toRead);
|
||||
if (len != stream->Read(buffer, 0, len))
|
||||
throw gcnew Exception("Unexpected end of stream");
|
||||
|
||||
Marshal::Copy(buffer, 0, IntPtr(ptr), len);
|
||||
ptr += len;
|
||||
toRead -= len;
|
||||
}
|
||||
|
||||
mpz_inp_raw_m(_value, out);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
};
|
@ -20,6 +20,7 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
|
||||
#pragma once
|
||||
|
||||
using namespace System;
|
||||
using namespace System::IO;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
|
||||
#define IS_NULL(a) (Object::ReferenceEquals(a, nullptr))
|
||||
@ -1742,6 +1743,27 @@ namespace MPIR
|
||||
/// <returns>The number of digits the number would take written in the specified base, possibly 1 too big, not counting a leading minus.</returns>
|
||||
mp_size_t ApproximateSizeInBase(int base) { return mpz_sizeinbase(_value, base); }
|
||||
|
||||
/// <summary>
|
||||
/// Output the integer to the <paramref name="stream"/> in raw binary format.
|
||||
/// <para>The number is written in a portable format, with 4 bytes of size information, and that many bytes of limbs.
|
||||
/// Both the size and the limbs are written in decreasing significance order (i.e., in big-endian).
|
||||
/// </para>The output can be read with Read(Stream).
|
||||
/// <para>The output cannot be read by mpz_inp_raw from GMP 1, because of changes necessary
|
||||
/// for compatibility between 32-bit and 64-bit machines.
|
||||
/// </para></summary>
|
||||
/// <param name="stream">Stream to output the number to</param>
|
||||
void Write(Stream^ stream);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the integer value from the <paramref name="stream"/> in raw binary format, as it would have been written by Write(Stream).
|
||||
/// <para>The number is read in a portable format, with 4 bytes of size information, and that many bytes of limbs.
|
||||
/// Both the size and the limbs are written in decreasing significance order (i.e., in big-endian).
|
||||
/// </para>This routine can read the output from mpz_out_raw also from GMP 1, in spite of changes
|
||||
/// necessary for compatibility between 32-bit and 64-bit machines.
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to input the number from</param>
|
||||
void Read(Stream^ stream);
|
||||
|
||||
#pragma endregion
|
||||
};
|
||||
};
|
@ -52,11 +52,7 @@ size_t
|
||||
mpz_inp_raw (mpz_ptr x, FILE *fp)
|
||||
{
|
||||
unsigned char csize_bytes[4];
|
||||
mp_size_t csize, abs_xsize, i;
|
||||
size_t abs_csize;
|
||||
char *cp;
|
||||
mp_ptr xp, sp, ep;
|
||||
mp_limb_t slimb, elimb;
|
||||
mpir_out_struct out;
|
||||
|
||||
if (fp == 0)
|
||||
fp = stdin;
|
||||
@ -65,6 +61,24 @@ mpz_inp_raw (mpz_ptr x, FILE *fp)
|
||||
if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
|
||||
return 0;
|
||||
|
||||
mpz_inp_raw_p(x, csize_bytes, out);
|
||||
|
||||
if(out->writtenSize != 0)
|
||||
{
|
||||
if (fread (out->written, out->writtenSize, 1, fp) != 1)
|
||||
return 0;
|
||||
|
||||
mpz_inp_raw_m(x, out);
|
||||
}
|
||||
return out->writtenSize + 4;
|
||||
}
|
||||
|
||||
void mpz_inp_raw_p (mpz_ptr x, unsigned char* csize_bytes, mpir_out_ptr out)
|
||||
{
|
||||
mp_size_t csize, abs_xsize, i;
|
||||
size_t abs_csize;
|
||||
mp_ptr xp;
|
||||
|
||||
csize =
|
||||
( (mp_size_t) csize_bytes[0] << 24)
|
||||
+ ((mp_size_t) csize_bytes[1] << 16)
|
||||
@ -93,10 +107,22 @@ mpz_inp_raw (mpz_ptr x, FILE *fp)
|
||||
/* Get limb boundaries right in the read, for the benefit of the
|
||||
non-nails case. */
|
||||
xp[0] = 0;
|
||||
cp = (char *) (xp + abs_xsize) - abs_csize;
|
||||
if (fread (cp, abs_csize, 1, fp) != 1)
|
||||
return 0;
|
||||
out->written = (unsigned char *) (xp + abs_xsize) - abs_csize;
|
||||
}
|
||||
out->writtenSize = abs_csize;
|
||||
out->allocatedSize = abs_xsize;
|
||||
SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
|
||||
}
|
||||
|
||||
void mpz_inp_raw_m(mpz_ptr x, mpir_out_ptr out)
|
||||
{
|
||||
mp_ptr xp, sp, ep;
|
||||
mp_size_t abs_xsize, i;
|
||||
mp_limb_t slimb, elimb;
|
||||
|
||||
abs_xsize = out->allocatedSize;
|
||||
|
||||
xp = PTR(x);
|
||||
if (GMP_NAIL_BITS == 0)
|
||||
{
|
||||
/* Reverse limbs to least significant first, and byte swap. If
|
||||
@ -128,9 +154,9 @@ mpz_inp_raw (mpz_ptr x, FILE *fp)
|
||||
limb = 0;
|
||||
bits = 0;
|
||||
tpos = 0;
|
||||
for (i = abs_csize-1; i >= 0; i--)
|
||||
for (i = out->writtenSize-1; i >= 0; i--)
|
||||
{
|
||||
byte = (unsigned char) cp[i];
|
||||
byte = out->written[i];
|
||||
limb |= (byte << bits);
|
||||
bits += 8;
|
||||
if (bits >= GMP_NUMB_BITS)
|
||||
@ -157,8 +183,5 @@ mpz_inp_raw (mpz_ptr x, FILE *fp)
|
||||
limbs resulting from this. Should be a non-zero value here, but
|
||||
for safety don't assume that. */
|
||||
MPN_NORMALIZE (xp, abs_xsize);
|
||||
}
|
||||
|
||||
SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
|
||||
return abs_csize + 4;
|
||||
SIZ(x) = (SIZ(x) >= 0 ? abs_xsize : -abs_xsize);
|
||||
}
|
||||
|
@ -47,9 +47,7 @@ MA 02110-1301, USA. */
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
size_t
|
||||
mpz_out_raw (FILE *fp, mpz_srcptr x)
|
||||
void mpz_out_raw_m (mpir_out_ptr mpir_out, mpz_srcptr x)
|
||||
{
|
||||
mp_size_t xsize, abs_xsize, bytes, i;
|
||||
mp_srcptr xp;
|
||||
@ -151,11 +149,25 @@ mpz_out_raw (FILE *fp, mpz_srcptr x)
|
||||
bp[-1] = bytes;
|
||||
bp -= 4;
|
||||
|
||||
mpir_out->allocated = tp;
|
||||
mpir_out->allocatedSize = tsize;
|
||||
mpir_out->written = bp;
|
||||
mpir_out->writtenSize = ssize;
|
||||
}
|
||||
|
||||
size_t
|
||||
mpz_out_raw (FILE* fp, mpz_srcptr x)
|
||||
{
|
||||
mpir_out_struct out;
|
||||
|
||||
if (fp == 0)
|
||||
fp = stdout;
|
||||
if (fwrite (bp, ssize, 1, fp) != 1)
|
||||
ssize = 0;
|
||||
|
||||
(*__gmp_free_func) (tp, tsize);
|
||||
return ssize;
|
||||
mpz_out_raw_m(out, x);
|
||||
|
||||
if (fwrite (out->written, out->writtenSize, 1, fp) != 1)
|
||||
out->writtenSize = 0;
|
||||
|
||||
(*__gmp_free_func) (out->allocated, out->allocatedSize);
|
||||
return out->writtenSize;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user