Raw binary IO. This necessitated some refactoring to the MPIR code.

This commit is contained in:
Alex Dyachenko 2014-04-11 21:09:39 -04:00
parent 2f5bbb1f80
commit 248eb1c5dc
9 changed files with 212 additions and 24 deletions

View File

@ -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" />

View File

@ -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));

View 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
}
}

View File

@ -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)

View File

@ -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
{

View File

@ -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
};

View File

@ -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
};
};

View File

@ -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);
}

View File

@ -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;
}