Refactored to use the more straightforward, but perhaps slightly slower, double allocation

This commit is contained in:
Alex Dyachenko 2014-03-15 20:51:02 -04:00
parent 8f6e3bc004
commit c6434c61b3
5 changed files with 92 additions and 157 deletions

View File

@ -20,39 +20,23 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
#include "Stdafx.h"
#include "Common.h"
static bool AllocationFunctionsConfigured = false;
//This custom allocation is used in order to store an MP* struct immediately
//before the limb data it references. They are always allocated together.
//Therefore, our managed classes only need to store a pointer to the MP struct,
//rather than the MP struct itself.
//Becasue we cannot store an unmanaged struct in a managed class or struct,
//we would need to either pin or copy the struct on stack field by field
//every time we had to use it, this way we can just pass "const" pointers around.
//for pointers that may be reallocated to MPIR, the struct must still be copied
//to stack, but that's only one of three or so for a typical MPIR call.
void* CustomAllocate (size_t alloc_size)
void CustomFree (void* ptr)
{
auto ptr = malloc(alloc_size + StructSize);
return (char*)ptr + StructSize;
void (*freeFunc) (void*, size_t);
mp_get_memory_functions (NULL, NULL, &freeFunc);
freeFunc(ptr, 0);
}
void* CustomReallocate (void* ptr, size_t old_size, size_t new_size)
void* CustomAllocate(size_t size)
{
auto newPtr = realloc((char*)ptr - StructSize, new_size + StructSize);
return (char*)newPtr + StructSize;
void* (*allocateFunc) (size_t);
mp_get_memory_functions(&allocateFunc, NULL, NULL);
return allocateFunc(size);
}
void CustomFree (void* ptr, size_t size)
void* CustomReallocate(void* old, size_t size)
{
free((char*)ptr - StructSize);
void* (*reallocateFunc) (void*, size_t, size_t);
mp_get_memory_functions(NULL, &reallocateFunc, NULL);
return reallocateFunc(old, 0, size);
}
void SetCustomAllocationFunctions()
{
if(!AllocationFunctionsConfigured)
{
mp_set_memory_functions(CustomAllocate, CustomReallocate, CustomFree);
AllocationFunctionsConfigured = true;
}
}

View File

@ -19,9 +19,6 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
#pragma once
//call this method from the static constructor of all MPIR.Net wrapper classes.
void SetCustomAllocationFunctions();
void* CustomAllocate (size_t alloc_size);
void* CustomReallocate (void* ptr, size_t old_size, size_t new_size);
void CustomFree (void* ptr, size_t size);
void* CustomReallocate (void* ptr, size_t new_size);
void CustomFree (void* ptr);

View File

@ -20,69 +20,68 @@ 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(HugeInt^ destination) \
{ \
EDIT_PTR(destination);
#define DEFINE_ASSIGNMENT_EPILOG \
SAVE_PTR(destination); \
}
#define DEFINE_ASSIGNMENT_PROLOG(name) void Mpir##name##Expression::AssignTo(HugeInt^ destination)
#define DEFINE_UNARY_ASSIGNMENT(name, operation) \
DEFINE_ASSIGNMENT_PROLOG(name) \
operation(src_destination, CONST_PTR(Operand)); \
DEFINE_ASSIGNMENT_EPILOG
{ \
operation(destination->_value, Operand->_value); \
}
#define DEFINE_BINARY_ASSIGNMENT(name, operation, left, right) \
DEFINE_ASSIGNMENT_PROLOG(name) \
operation(src_destination, left, right); \
DEFINE_ASSIGNMENT_EPILOG
{ \
operation(destination->_value, left, right); \
}
#define DEFINE_BINARY_ASSIGNMENT_REF_REF(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, CONST_PTR(Left), CONST_PTR(Right))
#define DEFINE_BINARY_ASSIGNMENT_REF_VAL(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, CONST_PTR(Left), Right)
#define DEFINE_BINARY_ASSIGNMENT_VAL_REF(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, Left, CONST_PTR(Right))
#define DEFINE_BINARY_ASSIGNMENT_REF_REF(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, Left->_value, Right->_value)
#define DEFINE_BINARY_ASSIGNMENT_REF_VAL(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, Left->_value, Right)
#define DEFINE_BINARY_ASSIGNMENT_VAL_REF(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, Left, Right->_value)
#define DEFINE_BINARY_ASSIGNMENT_VAL_VAL(name, operation) DEFINE_BINARY_ASSIGNMENT(name, operation, Left, Right)
#define DEFINE_BINARY_ASSIGNMENT_REF_SI(name, positiveOp, negativeOp) \
DEFINE_ASSIGNMENT_PROLOG(name) \
if (Right >= 0) \
positiveOp(src_destination, CONST_PTR(Left), static_cast<mpir_ui>(Right)); \
else \
negativeOp(src_destination, CONST_PTR(Left), -static_cast<mpir_ui>(Right)); \
DEFINE_ASSIGNMENT_EPILOG
#define DEFINE_BINARY_ASSIGNMENT_REF_SI(name, positiveOp, negativeOp) \
DEFINE_ASSIGNMENT_PROLOG(name) \
{ \
if (Right >= 0) \
positiveOp(destination->_value, Left->_value, static_cast<mpir_ui>(Right)); \
else \
negativeOp(destination->_value, Left->_value, -static_cast<mpir_ui>(Right)); \
}
#define DEFINE_BINARY_ASSIGNMENT_SI_REF(name, positiveOp, negativeOp1, negativeOp2) \
DEFINE_ASSIGNMENT_PROLOG(name) \
if (Left >= 0) \
positiveOp(src_destination, static_cast<mpir_ui>(Left), CONST_PTR(Right)); \
else \
{ \
negativeOp1(src_destination, CONST_PTR(Right), -static_cast<mpir_ui>(Left)); \
negativeOp2(src_destination, src_destination); \
} \
DEFINE_ASSIGNMENT_EPILOG
#define DEFINE_BINARY_ASSIGNMENT_SI_REF(name, positiveOp, negativeOp1, negativeOp2) \
DEFINE_ASSIGNMENT_PROLOG(name) \
{ \
if (Left >= 0) \
positiveOp(destination->_value, static_cast<mpir_ui>(Left), Right->_value); \
else \
{ \
negativeOp1(destination->_value, Right->_value, -static_cast<mpir_ui>(Left)); \
negativeOp2(destination->_value, destination->_value); \
} \
}
#define DEFINE_ADDMUL_ASSIGNMENT(name, operation, left, right) \
DEFINE_ASSIGNMENT_PROLOG(name) \
if(destination != Left) \
mpz_set(src_destination, Left->_value); \
operation(src_destination, left, right); \
DEFINE_ASSIGNMENT_EPILOG
#define DEFINE_ADDMUL_ASSIGNMENT(name, operation, left, right) \
DEFINE_ASSIGNMENT_PROLOG(name) \
{ \
if(destination != Left) \
mpz_set(destination->_value, Left->_value); \
operation(destination->_value, left, right); \
}
#define DEFINE_ADDMUL_ASSIGNMENT_SI(name, positiveOp, negativeOp, left, right) \
DEFINE_ASSIGNMENT_PROLOG(name) \
if(destination != Left) \
mpz_set(src_destination, Left->_value); \
if (right >= 0) \
positiveOp(src_destination, left, static_cast<mpir_ui>(right)); \
else \
negativeOp(src_destination, left, -static_cast<mpir_ui>(right)); \
DEFINE_ASSIGNMENT_EPILOG
#define DEFINE_ADDMUL_ASSIGNMENT_SI(name, positiveOp, negativeOp, left, right) \
DEFINE_ASSIGNMENT_PROLOG(name) \
{ \
if(destination != Left) \
mpz_set(destination->_value, Left->_value); \
if (right >= 0) \
positiveOp(destination->_value, left, static_cast<mpir_ui>(right)); \
else \
negativeOp(destination->_value, left, -static_cast<mpir_ui>(right)); \
}
#define DEFINE_ADDMUL_ASSIGNMENT_REF_REF(name, operation) DEFINE_ADDMUL_ASSIGNMENT(name, operation, CONST_PTR(Right->Left), CONST_PTR(Right->Right))
#define DEFINE_ADDMUL_ASSIGNMENT_REF_VAL(name, operation) DEFINE_ADDMUL_ASSIGNMENT(name, operation, CONST_PTR(Right->Left), Right->Right)
#define DEFINE_ADDMUL_ASSIGNMENT_REF_SI(name, positiveop, negativeOp) DEFINE_ADDMUL_ASSIGNMENT_SI(name, positiveop, negativeOp, CONST_PTR(Right->Left), Right->Right)
#define DEFINE_ADDMUL_ASSIGNMENT_REF_REF(name, operation) DEFINE_ADDMUL_ASSIGNMENT(name, operation, Right->Left->_value, Right->Right->_value)
#define DEFINE_ADDMUL_ASSIGNMENT_REF_VAL(name, operation) DEFINE_ADDMUL_ASSIGNMENT(name, operation, Right->Left->_value, Right->Right)
#define DEFINE_ADDMUL_ASSIGNMENT_REF_SI(name, positiveop, negativeOp) DEFINE_ADDMUL_ASSIGNMENT_SI(name, positiveop, negativeOp, Right->Left->_value, Right->Right)
using namespace System::Runtime::InteropServices;
@ -90,28 +89,16 @@ namespace MPIR
{
#pragma region construction
static HugeInt::HugeInt()
{
SetCustomAllocationFunctions();
}
HugeInt::HugeInt(mpz_srcptr src_this)
{
SAVE_PTR(this);
}
HugeInt::HugeInt()
{
mpz_t src_this;
mpz_init(src_this);
SAVE_PTR(this);
AllocateStruct();
mpz_init(_value);
}
HugeInt::HugeInt(mp_bitcnt_t value)
HugeInt::HugeInt(mp_bitcnt_t bits)
{
mpz_t src_this;
mpz_init2(src_this, value);
SAVE_PTR(this);
AllocateStruct();
mpz_init2(_value, bits);
}
HugeInt::HugeInt(String^ value)
@ -126,33 +113,31 @@ namespace MPIR
void HugeInt::FromString(String^ value, int base)
{
mpz_t src_this;
AllocateStruct();
IntPtr ptr = Marshal::StringToHGlobalAnsi(value);
bool success = 0 == mpz_init_set_str(src_this, (char*)(void*)ptr, base);
bool success = 0 == mpz_init_set_str(_value, (char*)(void*)ptr, base);
Marshal::FreeHGlobal(ptr);
if(!success)
{
mpz_clear(src_this);
DeallocateStruct();
throw gcnew ArgumentException("InvalidNumber", "value");
}
SAVE_PTR(this);
}
HugeInt^ HugeInt::FromLong(mpir_si value)
{
mpz_t src_a;
mpz_init_set_si(src_a, value);
return gcnew HugeInt(src_a);
auto result = gcnew HugeInt();
mpz_set_si(result->_value, value);
return result;
}
HugeInt^ HugeInt::FromUlong(mpir_ui value)
{
mpz_t src_a;
mpz_init_set_ui(src_a, value);
return gcnew HugeInt(src_a);
auto result = gcnew HugeInt();
mpz_set_ui(result->_value, value);
return result;
}
//unmanaged destructor makes the compiler implement IDisposable
@ -166,10 +151,7 @@ namespace MPIR
HugeInt::!HugeInt()
{
if(_value != 0)
{
mpz_clear(_value);
_value = 0;
}
DeallocateStruct();
}
#pragma endregion
@ -185,7 +167,7 @@ namespace MPIR
{
char* str = mpz_get_str(NULL, base, _value);
String^ result = gcnew String(str);
CustomFree(str, 0);
CustomFree(str);
return result;
}

View File

@ -21,40 +21,6 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
using namespace System;
typedef __mpz_struct StructType;
static const int StructSize = sizeof(StructType);
//makes a local var from the managed mpz struct data of the specified instance.
//this must be done when we're about to call an MPIR method that may realloc
//the limb data, since we're using a custom alloc scheme where the referencing MP* struct
//is stored in the same allocated block.
//Local var must subsequently be saved with SAVE_PTR.
//all other pointers used in the same method that are "const" for MPIR
//must be wrapped in CONST_PTR
#define EDIT_PTR(x) mpz_t src_##x; src_##x[0] = *x->_value
////makes a local var from the managed mpz struct data of this instance
//#define THIS_PTR EDIT_PTR(this)
//converts from allocated limbs pointer to the mpz struct pointer the class will keep
#define ToStructPtr(x) (StructType*)((char*)x - StructSize)
//updates the managed mpz struct data for the specified instance from a local var
#define SAVE_PTR(x) \
x->_value = ToStructPtr(src_##x->_mp_d); \
*x->_value = src_##x[0]
////updates the managed mpz struct data for this instance from a local var
//#define SAVE_THIS SAVE_PTR(this)
//wraps a "const" pointer for safe calling into MPIR methods.
//The underlying MP* structs for any editable pointers are copied to local vars.
//"const" pointers distinct from those are used unchanged;
//but if a "const" pointer is the same as one that was copied,
//it must reference the same local var because some MPIR methods compare them and
//optimize for such equality.
#define CONST_PTR(x) (x != destination ? x->_value : src_destination)
//defines a unary expression class
#define DEFINE_UNARY_EXPRESSION(name, type) \
public ref class Mpir##name##Expression : IMpirExpression \
@ -132,12 +98,21 @@ namespace MPIR
private:
//construction
HugeInt(mpz_srcptr src);
void AllocateStruct()
{
_value = (__mpz_struct*)CustomAllocate(sizeof(__mpz_struct));
}
void DeallocateStruct()
{
mpz_clear(_value);
CustomFree(_value);
_value = nullptr;
}
//HugeInt(mpz_srcptr src);
void FromString(String^ value, int base);
public:
//construction
static HugeInt();
HugeInt();
HugeInt(mp_bitcnt_t bits);
HugeInt(String^ value);
@ -165,11 +140,7 @@ namespace MPIR
virtual void AssignTo(HugeInt^ destination)
{
if(this != destination)
{
EDIT_PTR(destination);
mpz_set(src_destination, _value);
SAVE_PTR(destination);
}
mpz_set(destination->_value, _value);
}
//arithmetic

View File

@ -24,4 +24,5 @@ along with the MPIR Library. If not, see http://www.gnu.org/licenses/.
#pragma once
#include "mpir.h"
#include "Common.h"
#include "HugeInt.h"