<commit_before>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8) && !defined(MCL_STATIC_CODE)
	#define MCL_USE_XBYAK
#endif
#if defined(MCL_USE_XBYAK) || defined(MCL_STATIC_CODE)
	#define MCL_X64_ASM
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x134; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048, // printable hex string
	IoEcAffineSerialize = 4096 // serialize [x:y]
};

namespace fp {

inline bool isIoSerializeMode(int ioMode)
{
	return ioMode & (IoArray | IoArrayRaw | IoSerialize | IoEcAffineSerialize | IoSerializeHexStr);
}

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec

#ifndef MCL_MAX_MUL_VEC_NGLV
	#define MCL_MAX_MUL_VEC_NGLV 16
#endif
const size_t maxMulVecNGLV = MCL_MAX_MUL_VEC_NGLV; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

enum MaskMode {
	NoMask = 0, // throw if greater or equal
	SmallMask = 1, // 1-bit smaller mask if greater or equal
	MaskAndMod = 2, // mask and substract if greater or equal
	Mod = 3 // mod p
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
#endif
#ifdef MCL_X64_ASM
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void2u fp_mul2A_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void2u fp2_mul2A_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	void2u fp2Dbl_mul_xiA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void3u fp_mul2;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_inv;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_X64_ASM
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp_mul2A_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fp2_mul2A_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		fp2Dbl_mul_xiA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_mul2 = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_inv = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr | IoEcAffineSerialize)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<commit_msg>v1.35<commit_after>#pragma once
/**
	@file
	@brief definition of Op
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/gmp_util.hpp>
#include <memory.h>
#include <mcl/array.hpp>

#if defined(__EMSCRIPTEN__) || defined(__wasm__)
	#define MCL_DONT_USE_XBYAK
	#define MCL_DONT_USE_OPENSSL
#endif
#if !defined(MCL_DONT_USE_XBYAK) && (defined(_WIN64) || defined(__x86_64__)) && (MCL_SIZEOF_UNIT == 8) && !defined(MCL_STATIC_CODE)
	#define MCL_USE_XBYAK
#endif
#if defined(MCL_USE_XBYAK) || defined(MCL_STATIC_CODE)
	#define MCL_X64_ASM
	#define MCL_XBYAK_DIRECT_CALL
#endif

#define MCL_MAX_HASH_BIT_SIZE 512

namespace mcl {

static const int version = 0x135; /* 0xABC = A.BC */

/*
	specifies available string format mode for X::setIoMode()
	// for Fp, Fp2, Fp6, Fp12
	default(0) : IoDec
	printable string(zero terminated, variable size)
	IoBin(2) | IoDec(10) | IoHex(16) | IoBinPrefix | IoHexPrefix

	byte string(not zero terminated, fixed size)
	IoArray | IoArrayRaw
	IoArray = IoSerialize

	// for Ec
	affine(0) | IoEcCompY | IoComp
	default : affine

	affine and IoEcCompY are available with ioMode for Fp
	IoSerialize ignores ioMode for Fp

	IoAuto
		dec or hex according to ios_base::fmtflags
	IoBin
		binary number([01]+)
	IoDec
		decimal number
	IoHex
		hexadecimal number([0-9a-fA-F]+)
	IoBinPrefix
		0b + <binary number>
	IoHexPrefix
		0x + <hexadecimal number>
	IoArray
		array of Unit(fixed size = Fp::getByteSize())
	IoArrayRaw
		array of Unit(fixed size = Fp::getByteSize()) without Montgomery conversion

	// for Ec::setIoMode()
	IoEcAffine(default)
	"0" ; infinity
	"1 <x> <y>" ; affine coordinate

	IoEcProj
	"4" <x> <y> <z> ; projective or jacobi coordinate

	IoEcCompY
		1-bit y prepresentation of elliptic curve
		"2 <x>" ; compressed for even y
		"3 <x>" ; compressed for odd y

	IoSerialize
		if isMSBserialize(): // p is not full bit
			size = Fp::getByteSize()
			use MSB of array of x for 1-bit y for prime p where (p % 8 != 0)
			[0] ; infinity
			<x> ; for even y
			<x>|1 ; for odd y ; |1 means set MSB of x
		else:
			size = Fp::getByteSize() + 1
			[0] ; infinity
			2 <x> ; for even y
			3 <x> ; for odd y
*/
enum IoMode {
	IoAuto = 0, // dec or hex according to ios_base::fmtflags
	IoBin = 2, // binary number without prefix
	IoDec = 10, // decimal number without prefix
	IoHex = 16, // hexadecimal number without prefix
	IoArray = 32, // array of Unit(fixed size)
	IoArrayRaw = 64, // raw array of Unit without Montgomery conversion
	IoPrefix = 128, // append '0b'(bin) or '0x'(hex)
	IoBinPrefix = IoBin | IoPrefix,
	IoHexPrefix = IoHex | IoPrefix,
	IoEcAffine = 0, // affine coordinate
	IoEcCompY = 256, // 1-bit y representation of elliptic curve
	IoSerialize = 512, // use MBS for 1-bit y
	IoFixedSizeByteSeq = IoSerialize, // obsolete
	IoEcProj = 1024, // projective or jacobi coordinate
	IoSerializeHexStr = 2048, // printable hex string
	IoEcAffineSerialize = 4096 // serialize [x:y]
};

namespace fp {

inline bool isIoSerializeMode(int ioMode)
{
	return ioMode & (IoArray | IoArrayRaw | IoSerialize | IoEcAffineSerialize | IoSerializeHexStr);
}

const size_t UnitBitSize = sizeof(Unit) * 8;

const size_t maxUnitSize = (MCL_MAX_BIT_SIZE + UnitBitSize - 1) / UnitBitSize;
#define MCL_MAX_UNIT_SIZE ((MCL_MAX_BIT_SIZE + MCL_UNIT_BIT_SIZE - 1) / MCL_UNIT_BIT_SIZE)

const size_t maxMulVecN = 32; // inner loop of mulVec

#ifndef MCL_MAX_MUL_VEC_NGLV
	#define MCL_MAX_MUL_VEC_NGLV 16
#endif
const size_t maxMulVecNGLV = MCL_MAX_MUL_VEC_NGLV; // inner loop of mulVec with GLV

struct FpGenerator;
struct Op;

typedef void (*void1u)(Unit*);
typedef void (*void2u)(Unit*, const Unit*);
typedef void (*void2uI)(Unit*, const Unit*, Unit);
typedef void (*void2uIu)(Unit*, const Unit*, Unit, const Unit*);
typedef void (*void2uOp)(Unit*, const Unit*, const Op&);
typedef void (*void3u)(Unit*, const Unit*, const Unit*);
typedef void (*void4u)(Unit*, const Unit*, const Unit*, const Unit*);
typedef int (*int2u)(Unit*, const Unit*);

typedef Unit (*u1uII)(Unit*, Unit, Unit);
typedef Unit (*u3u)(Unit*, const Unit*, const Unit*);

/*
	disable -Wcast-function-type
	the number of arguments of some JIT functions is smaller than that of T
*/
template<class T, class S>
T func_ptr_cast(S func)
{
	return reinterpret_cast<T>(reinterpret_cast<void*>(func));
}
struct Block {
	const Unit *p; // pointer to original FpT.v_
	size_t n;
	Unit v_[maxUnitSize];
};

enum Mode {
	FP_AUTO,
	FP_GMP,
	FP_GMP_MONT,
	FP_LLVM,
	FP_LLVM_MONT,
	FP_XBYAK
};

enum PrimeMode {
	PM_GENERIC = 0,
	PM_NIST_P192,
	PM_SECP256K1,
	PM_NIST_P521
};

enum MaskMode {
	NoMask = 0, // throw if greater or equal
	SmallMask = 1, // 1-bit smaller mask if greater or equal
	MaskAndMod = 2, // mask and substract if greater or equal
	Mod = 3 // mod p
};

struct Op {
	/*
		don't change the layout of rp and p
		asm code assumes &rp + 1 == p
	*/
	Unit rp;
	Unit p[maxUnitSize];
	mpz_class mp;
	uint32_t pmod4;
	mcl::SquareRoot sq;
	mcl::Modp modp;
	Unit half[maxUnitSize]; // (p + 1) / 2
	Unit oneRep[maxUnitSize]; // 1(=inv R if Montgomery)
	/*
		for Montgomery
		one = 1
		R = (1 << (N * sizeof(Unit) * 8)) % p
		R2 = (R * R) % p
		R3 = RR^3
	*/
	Unit one[maxUnitSize];
	Unit R2[maxUnitSize];
	Unit R3[maxUnitSize];
#ifdef MCL_USE_XBYAK
	FpGenerator *fg;
#endif
#ifdef MCL_X64_ASM
	mcl::Array<Unit> invTbl;
#endif
	void3u fp_addA_;
	void3u fp_subA_;
	void2u fp_negA_;
	void3u fp_mulA_;
	void2u fp_sqrA_;
	void2u fp_mul2A_;
	void3u fp2_addA_;
	void3u fp2_subA_;
	void2u fp2_negA_;
	void3u fp2_mulA_;
	void2u fp2_sqrA_;
	void2u fp2_mul2A_;
	void3u fpDbl_addA_;
	void3u fpDbl_subA_;
	void2u fpDbl_modA_;
	void3u fp2Dbl_mulPreA_;
	void2u fp2Dbl_sqrPreA_;
	void2u fp2Dbl_mul_xiA_;
	size_t maxN;
	size_t N;
	size_t bitSize;
	bool (*fp_isZero)(const Unit*);
	void1u fp_clear;
	void2u fp_copy;
	void2u fp_shr1;
	void3u fp_neg;
	void4u fp_add;
	void4u fp_sub;
	void4u fp_mul;
	void3u fp_sqr;
	void3u fp_mul2;
	void2uOp fp_invOp;
	void2uIu fp_mulUnit; // fpN1_mod + fp_mulUnitPre

	void3u fpDbl_mulPre;
	void2u fpDbl_sqrPre;
	int2u fp_preInv;
	void2uI fp_mulUnitPre; // z[N + 1] = x[N] * y
	void3u fpN1_mod; // y[N] = x[N + 1] % p[N]

	void4u fpDbl_add;
	void4u fpDbl_sub;
	void3u fpDbl_mod;

	u3u fp_addPre; // without modulo p
	u3u fp_subPre; // without modulo p
	u3u fpDbl_addPre;
	u3u fpDbl_subPre;
	/*
		for Fp2 = F[u] / (u^2 + 1)
		x = a + bu
	*/
	int xi_a; // xi = xi_a + u
	void4u fp2_mulNF;
	void2u fp2_inv;
	void2u fp2_mul_xiA_;
	uint32_t (*hash)(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize);

	PrimeMode primeMode;
	bool isFullBit; // true if bitSize % uniSize == 0
	bool isMont; // true if use Montgomery
	bool isFastMod; // true if modulo is fast

	Op()
	{
		clear();
	}
	~Op()
	{
#ifdef MCL_USE_XBYAK
		destroyFpGenerator(fg);
#endif
	}
	void clear()
	{
		rp = 0;
		memset(p, 0, sizeof(p));
		mp = 0;
		pmod4 = 0;
		sq.clear();
		// fg is not set
		memset(half, 0, sizeof(half));
		memset(oneRep, 0, sizeof(oneRep));
		memset(one, 0, sizeof(one));
		memset(R2, 0, sizeof(R2));
		memset(R3, 0, sizeof(R3));
#ifdef MCL_X64_ASM
		invTbl.clear();
#endif
		fp_addA_ = 0;
		fp_subA_ = 0;
		fp_negA_ = 0;
		fp_mulA_ = 0;
		fp_sqrA_ = 0;
		fp_mul2A_ = 0;
		fp2_addA_ = 0;
		fp2_subA_ = 0;
		fp2_negA_ = 0;
		fp2_mulA_ = 0;
		fp2_sqrA_ = 0;
		fp2_mul2A_ = 0;
		fpDbl_addA_ = 0;
		fpDbl_subA_ = 0;
		fpDbl_modA_ = 0;
		fp2Dbl_mulPreA_ = 0;
		fp2Dbl_sqrPreA_ = 0;
		fp2Dbl_mul_xiA_ = 0;
		maxN = 0;
		N = 0;
		bitSize = 0;
		fp_isZero = 0;
		fp_clear = 0;
		fp_copy = 0;
		fp_shr1 = 0;
		fp_neg = 0;
		fp_add = 0;
		fp_sub = 0;
		fp_mul = 0;
		fp_sqr = 0;
		fp_mul2 = 0;
		fp_invOp = 0;
		fp_mulUnit = 0;

		fpDbl_mulPre = 0;
		fpDbl_sqrPre = 0;
		fp_preInv = 0;
		fp_mulUnitPre = 0;
		fpN1_mod = 0;

		fpDbl_add = 0;
		fpDbl_sub = 0;
		fpDbl_mod = 0;

		fp_addPre = 0;
		fp_subPre = 0;
		fpDbl_addPre = 0;
		fpDbl_subPre = 0;

		xi_a = 0;
		fp2_mulNF = 0;
		fp2_inv = 0;
		fp2_mul_xiA_ = 0;
		hash = 0;

		primeMode = PM_GENERIC;
		isFullBit = false;
		isMont = false;
		isFastMod = false;
	}
	void fromMont(Unit* y, const Unit *x) const
	{
		/*
			M(x, y) = xyR^-1
			y = M(x, 1) = xR^-1
		*/
		fp_mul(y, x, one, p);
	}
	void toMont(Unit* y, const Unit *x) const
	{
		/*
			y = M(x, R2) = xR^2 R^-1 = xR
		*/
		fp_mul(y, x, R2, p);
	}
	bool init(const mpz_class& p, size_t maxBitSize, int xi_a, Mode mode, size_t mclMaxBitSize = MCL_MAX_BIT_SIZE);
#ifdef MCL_USE_XBYAK
	static FpGenerator* createFpGenerator();
	static void destroyFpGenerator(FpGenerator *fg);
#endif
private:
	Op(const Op&);
	void operator=(const Op&);
};

inline const char* getIoSeparator(int ioMode)
{
	return (ioMode & (IoArray | IoArrayRaw | IoSerialize | IoSerializeHexStr | IoEcAffineSerialize)) ? "" : " ";
}

inline void dump(const void *buf, size_t n)
{
	const uint8_t *s = (const uint8_t *)buf;
	for (size_t i = 0; i < n; i++) {
		printf("%02x ", s[i]);
	}
	printf("\n");
}

#ifndef CYBOZU_DONT_USE_STRING
int detectIoMode(int ioMode, const std::ios_base& ios);

inline void dump(const std::string& s)
{
	dump(s.c_str(), s.size());
}
#endif

} } // mcl::fp
<|endoftext|>


<commit_before>/******************************************************************************
 *   Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
 *                                                                            *
 *   This file is part of the FreeCAD CAx development system.                 *
 *                                                                            *
 *   This library is free software; you can redistribute it and/or            *
 *   modify it under the terms of the GNU Library General Public              *
 *   License as published by the Free Software Foundation; either             *
 *   version 2 of the License, or (at your option) any later version.         *
 *                                                                            *
 *   This 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 Library General Public License for more details.                     *
 *                                                                            *
 *   You should have received a copy of the GNU Library General Public        *
 *   License along with this library; see the file COPYING.LIB. If not,       *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,            *
 *   Suite 330, Boston, MA  02111-1307, USA                                   *
 *                                                                            *
 ******************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepBuilderAPI_Transform.hxx>
# include <BRepAlgoAPI_Fuse.hxx>
# include <BRepAlgoAPI_Cut.hxx>
# include <BRep_Builder.hxx>
# include <TopExp.hxx>
# include <TopExp_Explorer.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
# include <Precision.hxx>
# include <BRepBuilderAPI_Copy.hxx>
#endif

#include "FeatureTransformed.h"
#include "FeatureMultiTransform.h"
#include "FeatureAdditive.h"
#include "FeatureSubtractive.h"
#include "FeatureMirrored.h"

#include <Base/Console.h>

using namespace PartDesign;

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::Transformed, PartDesign::Feature)

Transformed::Transformed() : rejected(0)
{
    ADD_PROPERTY(Originals,(0));
    Originals.setSize(0);
    Placement.StatusBits.set(2, true);
}

void Transformed::positionBySupport(void)
{
    Part::Feature *support = static_cast<Part::Feature*>(getSupportObject());
    if ((support != NULL) && support->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
        this->Placement.setValue(support->Placement.getValue());
}

App::DocumentObject* Transformed::getSupportObject() const
{
    if (!Originals.getValues().empty())
        return Originals.getValues().front();
    else
        return NULL;
}

App::DocumentObject* Transformed::getSketchObject() const
{
    std::vector<DocumentObject*> originals = Originals.getValues();
    if (!originals.empty() && originals.front()->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId()))
        return (static_cast<PartDesign::SketchBased*>(originals.front()))->getVerifiedSketch();
    else
        return NULL;
}

short Transformed::mustExecute() const
{
    if (Originals.isTouched())
        return 1;
    return PartDesign::Feature::mustExecute();
}

App::DocumentObjectExecReturn *Transformed::execute(void)
{
    rejected.clear();

    std::vector<App::DocumentObject*> originals = Originals.getValues();
    if (originals.empty()) // typically InsideMultiTransform
        return App::DocumentObject::StdReturn;

    this->positionBySupport();

    // get transformations from subclass by calling virtual method
    std::list<gp_Trsf> transformations;
    try {
        transformations = getTransformations(originals);
    } catch (Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }

    if (transformations.empty())
        return App::DocumentObject::StdReturn; // No transformations defined, exit silently

    // Get the support
    // NOTE: Because of the way we define the support, FeatureTransformed can only work on
    // one Body feature at a time
    // TODO: Currently, the support is simply the first Original. Change this to the Body feature later
    Part::Feature* supportFeature = static_cast<Part::Feature*>(getSupportObject());
    const Part::TopoShape& supportTopShape = supportFeature->Shape.getShape();
    if (supportTopShape._Shape.IsNull())
        return new App::DocumentObjectExecReturn("Cannot transform invalid support shape");

    // create an untransformed copy of the support shape
    Part::TopoShape supportShape(supportTopShape);
    supportShape.setTransform(Base::Matrix4D());
    TopoDS_Shape support = supportShape._Shape;

    // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then
    // transform the compounds as a whole. But we choose to apply the transformations to each
    // Original separately. This way it is easier to discover what feature causes a fuse/cut
    // to fail. The downside is that performance suffers when there are many originals. But it seems
    // safe to assume that in most cases there are few originals and many transformations
    for (std::vector<App::DocumentObject*>::const_iterator o = originals.begin(); o != originals.end(); o++)
    {
        TopoDS_Shape shape;
        bool fuse;

        if ((*o)->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) {
            PartDesign::Additive* addFeature = static_cast<PartDesign::Additive*>(*o);
            shape = addFeature->AddShape.getShape()._Shape;
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Shape of additive feature is empty");
            fuse = true;
        } else if ((*o)->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) {
            PartDesign::Subtractive* subFeature = static_cast<PartDesign::Subtractive*>(*o);
            shape = subFeature->SubShape.getShape()._Shape;
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Shape of subtractive feature is empty");
            fuse = false;
        } else {
            return new App::DocumentObjectExecReturn("Only additive and subtractive features can be transformed");
        }

        // Transform the add/subshape and build a compound from the transformations,
        BRep_Builder builder;
        TopoDS_Compound transformedShapes;
        builder.MakeCompound(transformedShapes);
        std::vector<TopoDS_Shape> v_transformedShapes; // collect all the transformed shapes for intersection testing
        std::list<gp_Trsf>::const_iterator t = transformations.begin();
        t++; // Skip first transformation, which is always the identity transformation

        for (; t != transformations.end(); t++)
        {
            // Make an explicit copy of the shape because the "true" parameter to BRepBuilderAPI_Transform
            // seems to be pretty broken
            BRepBuilderAPI_Copy copy(shape);
            shape = copy.Shape();
            if (shape.IsNull())
                throw Base::Exception("Transformed: Linked shape object is empty");

            BRepBuilderAPI_Transform mkTrf(shape, *t, false); // No need to copy, now
            if (!mkTrf.IsDone())
                return new App::DocumentObjectExecReturn("Transformation failed", (*o));

            // Check for intersection with support
            if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) {
                Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument());
                // Note: The removal happens in getSolid() after the fuse
                rejected.push_back(*t);
            }
            builder.Add(transformedShapes, mkTrf.Shape());
            v_transformedShapes.push_back(mkTrf.Shape());

            /*
            // Note: This method is only stable for Linear and Polar transformations. No need to
            // make an explicit copy of the shape, either
            TopoDS_Shape trfShape = shape.Moved(TopLoc_Location(*t));

            // Check for intersection with support
            Bnd_Box transformed_bb;
            BRepBndLib::Add(trfShape, transformed_bb);
            if (support_bb.Distance(transformed_bb) > Precision::Confusion()) {
                Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument());
                // Note: The removal happens in getSolid() after the fuse
            }
            builder.Add(transformedShapes, trfShape);
            v_transformedShapes.push_back(trfShape);
            */
        }

        // Check for intersection of the original and the transformed shape
        for (std::vector<TopoDS_Shape>::const_iterator s = v_transformedShapes.begin(); s != v_transformedShapes.end(); s++)
        {
            // If there is only one transformed feature, this check is not necessary (though it might seem
            // illogical to the user why we allow overlapping shapes in this case!
            if (v_transformedShapes.size() == 1)
                break;

            if (Part::checkIntersection(shape, *s, false, false))
                return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o));
                // Note: This limitation could be overcome by fusing the transformed features instead of
                // compounding them, probably at the expense of quite a bit of performance and complexity
                // in this code

            // For MultiTransform, just checking the first transformed shape is not sufficient - any two
            // features might overlap, even if the original and the first shape don't overlap!
            if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId())
                break;
            else {
                // Check intersection with all other transformed shapes as well
                std::vector<TopoDS_Shape>::const_iterator s2 = s;
                s2++;
                for (; s2 != v_transformedShapes.end(); s2++)
                    if (Part::checkIntersection(*s, *s2, false, false))
                        return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o));
            }
        }

        // Fuse/Cut the compounded transformed shapes with the support
        TopoDS_Shape result;

        if (fuse) {
            BRepAlgoAPI_Fuse mkFuse(support, transformedShapes);
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Fusion with support failed", *o);
            // we have to get the solids (fuse sometimes creates compounds)
            // Note: Because getSolid() only returns the first solid in the explorer, all
            // solids that are outside the support automatically disappear!
            result = this->getSolid(mkFuse.Shape());
            // lets check if the result is a solid
            if (result.IsNull())
                return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *o);
            // check if mkFuse created more than one solids
            TopExp_Explorer xp;
            xp.Init(mkFuse.Shape(),TopAbs_SOLID);
            if (xp.More())
                xp.Next();
            if (!xp.More())        // There are no rejected transformations even
                rejected.clear();  // if the bb check guessed that there would be
        } else {
            BRepAlgoAPI_Cut mkCut(support, transformedShapes);
            if (!mkCut.IsDone())
                return new App::DocumentObjectExecReturn("Cut out of support failed", *o);
            result = mkCut.Shape();
        }

        support = result; // Use result of this operation for fuse/cut of next original
    }

    this->Shape.setValue(support);

    return App::DocumentObject::StdReturn;
}

}
<commit_msg>PartDesign: Show overlapping transformations as rejected<commit_after>/******************************************************************************
 *   Copyright (c)2012 Jan Rheinlaender <jrheinlaender@users.sourceforge.net> *
 *                                                                            *
 *   This file is part of the FreeCAD CAx development system.                 *
 *                                                                            *
 *   This library is free software; you can redistribute it and/or            *
 *   modify it under the terms of the GNU Library General Public              *
 *   License as published by the Free Software Foundation; either             *
 *   version 2 of the License, or (at your option) any later version.         *
 *                                                                            *
 *   This 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 Library General Public License for more details.                     *
 *                                                                            *
 *   You should have received a copy of the GNU Library General Public        *
 *   License along with this library; see the file COPYING.LIB. If not,       *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,            *
 *   Suite 330, Boston, MA  02111-1307, USA                                   *
 *                                                                            *
 ******************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRepBuilderAPI_Transform.hxx>
# include <BRepAlgoAPI_Fuse.hxx>
# include <BRepAlgoAPI_Cut.hxx>
# include <BRep_Builder.hxx>
# include <TopExp.hxx>
# include <TopExp_Explorer.hxx>
# include <TopTools_IndexedMapOfShape.hxx>
# include <Precision.hxx>
# include <BRepBuilderAPI_Copy.hxx>
#endif

#include "FeatureTransformed.h"
#include "FeatureMultiTransform.h"
#include "FeatureAdditive.h"
#include "FeatureSubtractive.h"
#include "FeatureMirrored.h"

#include <Base/Console.h>

using namespace PartDesign;

namespace PartDesign {

PROPERTY_SOURCE(PartDesign::Transformed, PartDesign::Feature)

Transformed::Transformed() : rejected(0)
{
    ADD_PROPERTY(Originals,(0));
    Originals.setSize(0);
    Placement.StatusBits.set(2, true);
}

void Transformed::positionBySupport(void)
{
    Part::Feature *support = static_cast<Part::Feature*>(getSupportObject());
    if ((support != NULL) && support->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
        this->Placement.setValue(support->Placement.getValue());
}

App::DocumentObject* Transformed::getSupportObject() const
{
    if (!Originals.getValues().empty())
        return Originals.getValues().front();
    else
        return NULL;
}

App::DocumentObject* Transformed::getSketchObject() const
{
    std::vector<DocumentObject*> originals = Originals.getValues();
    if (!originals.empty() && originals.front()->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId()))
        return (static_cast<PartDesign::SketchBased*>(originals.front()))->getVerifiedSketch();
    else
        return NULL;
}

short Transformed::mustExecute() const
{
    if (Originals.isTouched())
        return 1;
    return PartDesign::Feature::mustExecute();
}

App::DocumentObjectExecReturn *Transformed::execute(void)
{
    rejected.clear();

    std::vector<App::DocumentObject*> originals = Originals.getValues();
    if (originals.empty()) // typically InsideMultiTransform
        return App::DocumentObject::StdReturn;

    this->positionBySupport();

    // get transformations from subclass by calling virtual method
    std::vector<gp_Trsf> transformations;
    try {
        std::list<gp_Trsf> t_list = getTransformations(originals);
        transformations.insert(transformations.end(), t_list.begin(), t_list.end());
    } catch (Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }

    if (transformations.empty())
        return App::DocumentObject::StdReturn; // No transformations defined, exit silently

    // Get the support
    // NOTE: Because of the way we define the support, FeatureTransformed can only work on
    // one Body feature at a time
    // TODO: Currently, the support is simply the first Original. Change this to the Body feature later
    Part::Feature* supportFeature = static_cast<Part::Feature*>(getSupportObject());
    const Part::TopoShape& supportTopShape = supportFeature->Shape.getShape();
    if (supportTopShape._Shape.IsNull())
        return new App::DocumentObjectExecReturn("Cannot transform invalid support shape");

    // create an untransformed copy of the support shape
    Part::TopoShape supportShape(supportTopShape);
    supportShape.setTransform(Base::Matrix4D());
    TopoDS_Shape support = supportShape._Shape;

    std::set<std::vector<gp_Trsf>::const_iterator> nointersect_trsfms;
    std::set<std::vector<gp_Trsf>::const_iterator> overlapping_trsfms;

    // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then
    // transform the compounds as a whole. But we choose to apply the transformations to each
    // Original separately. This way it is easier to discover what feature causes a fuse/cut
    // to fail. The downside is that performance suffers when there are many originals. But it seems
    // safe to assume that in most cases there are few originals and many transformations
    for (std::vector<App::DocumentObject*>::const_iterator o = originals.begin(); o != originals.end(); o++)
    {
        // Extract the original shape and determine whether to cut or to fuse
        TopoDS_Shape shape;
        bool fuse;

        if ((*o)->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) {
            PartDesign::Additive* addFeature = static_cast<PartDesign::Additive*>(*o);
            shape = addFeature->AddShape.getShape()._Shape;
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Shape of additive feature is empty");
            fuse = true;
        } else if ((*o)->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) {
            PartDesign::Subtractive* subFeature = static_cast<PartDesign::Subtractive*>(*o);
            shape = subFeature->SubShape.getShape()._Shape;
            if (shape.IsNull())
                return new App::DocumentObjectExecReturn("Shape of subtractive feature is empty");
            fuse = false;
        } else {
            return new App::DocumentObjectExecReturn("Only additive and subtractive features can be transformed");
        }

        // Transform the add/subshape and collect the resulting shapes for overlap testing
        std::vector<std::vector<gp_Trsf>::const_iterator> v_transformations;
        std::vector<TopoDS_Shape> v_transformedShapes;

        std::vector<gp_Trsf>::const_iterator t = transformations.begin();
        t++; // Skip first transformation, which is always the identity transformation
        for (; t != transformations.end(); t++) {
            // Make an explicit copy of the shape because the "true" parameter to BRepBuilderAPI_Transform
            // seems to be pretty broken
            BRepBuilderAPI_Copy copy(shape);
            shape = copy.Shape();
            if (shape.IsNull())
                throw Base::Exception("Transformed: Linked shape object is empty");

            BRepBuilderAPI_Transform mkTrf(shape, *t, false); // No need to copy, now
            if (!mkTrf.IsDone())
                return new App::DocumentObjectExecReturn("Transformation failed", (*o));

            // Check for intersection with support
            if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) {
                Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument());
                nointersect_trsfms.insert(t);
            } else {
                v_transformations.push_back(t);
                v_transformedShapes.push_back(mkTrf.Shape());
                // Note: Transformations that do not intersect the support are ignored in the overlap tests
            }
        }

        if (v_transformedShapes.empty())
            break; // Skip the overlap check and go on to next original

        // Check for overlapping of the original and the transformed shapes, and remove the overlapping transformations
        if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId()) {
            // If there is only one transformed feature, we allow an overlap (though it might seem
            // illogical to the user why we allow overlapping shapes in this case!)
            if (v_transformedShapes.size() > 1)
                if (Part::checkIntersection(shape, v_transformedShapes.front(), false, false)) {
                    // For single transformations, if one overlaps, all overlap, as long as we have uniform increments
                    overlapping_trsfms.insert(v_transformations.begin(),v_transformations.end());
                    v_transformedShapes.clear();
                }
        } else {
            // For MultiTransform, just checking the first transformed shape is not sufficient - any two
            // features might overlap, even if the original and the first shape don't overlap!

            std::set<std::vector<TopoDS_Shape>::iterator> rejected_iterators;

            std::vector<TopoDS_Shape>::iterator s1 = v_transformedShapes.begin();
            std::vector<TopoDS_Shape>::iterator s2 = s1;
            s2++;
            std::vector<std::vector<gp_Trsf>::const_iterator>::const_iterator t1 = v_transformations.begin();
            std::vector<std::vector<gp_Trsf>::const_iterator>::const_iterator t2 = t1;
            t2++;
            for (; s2 != v_transformedShapes.end();) {
                // Check intersection with the original
                if (Part::checkIntersection(shape, *s1, false, false)) {
                    rejected_iterators.insert(s1);
                    overlapping_trsfms.insert(*t1);
                }
                // Check intersection with other transformations
                for (; s2 != v_transformedShapes.end(); s2++, t2++)
                    if (Part::checkIntersection(*s1, *s2, false, false)) {
                        rejected_iterators.insert(s1);
                        rejected_iterators.insert(s2);
                        overlapping_trsfms.insert(*t1);
                        overlapping_trsfms.insert(*t2);
                    }
                s1++;
                s2 = s1;
                s2++;
                t1++;
                t2 = t1;
                t2++;
            }
            // Check intersection of last transformation with the original
            if (Part::checkIntersection(shape, *s1, false, false)) {
                rejected_iterators.insert(s1);
                overlapping_trsfms.insert(*t1);
            }

            for (std::set<std::vector<TopoDS_Shape>::iterator>::reverse_iterator it = rejected_iterators.rbegin();
                 it != rejected_iterators.rend(); it++)
                v_transformedShapes.erase(*it);
        }

        if (v_transformedShapes.empty())
            break; // Skip the boolean operation and go on to next original

        // Build a compound from all the valid transformations
        BRep_Builder builder;
        TopoDS_Compound transformedShapes;
        builder.MakeCompound(transformedShapes);
        for (std::vector<TopoDS_Shape>::const_iterator s = v_transformedShapes.begin(); s != v_transformedShapes.end(); s++)
            builder.Add(transformedShapes, *s);

        // Fuse/Cut the compounded transformed shapes with the support
        TopoDS_Shape result;

        if (fuse) {
            BRepAlgoAPI_Fuse mkFuse(support, transformedShapes);
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Fusion with support failed", *o);
            // we have to get the solids (fuse sometimes creates compounds)
            result = this->getSolid(mkFuse.Shape());
            // lets check if the result is a solid
            if (result.IsNull())
                return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *o);
        } else {
            BRepAlgoAPI_Cut mkCut(support, transformedShapes);
            if (!mkCut.IsDone())
                return new App::DocumentObjectExecReturn("Cut out of support failed", *o);
            result = mkCut.Shape();
        }

        support = result; // Use result of this operation for fuse/cut of next original
    }

    if (!overlapping_trsfms.empty())
        // Concentrate on overlapping shapes since they are more serious
        for (std::set<std::vector<gp_Trsf>::const_iterator>::const_iterator it = overlapping_trsfms.begin();
             it != overlapping_trsfms.end(); it++)
            rejected.push_back(**it);
    else
        for (std::set<std::vector<gp_Trsf>::const_iterator>::const_iterator it = nointersect_trsfms.begin();
             it != nointersect_trsfms.end(); it++)
            rejected.push_back(**it);

    this->Shape.setValue(support);
    if (!overlapping_trsfms.empty())
        return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences");
        // Note: This limitation could be overcome by fusing the transformed features instead of
        // compounding them, probably at the expense of quite a bit of performance and complexity
        // in this code
    else
        return App::DocumentObject::StdReturn;
}

}
<|endoftext|>


<commit_before>#ifndef STRONG_STRONG_HPP
#define STRONG_STRONG_HPP

#include <type_traits>
#include <utility>

/**
 * Namespace for creating strong typedefs.
 */
namespace strong {

/**
 * A strong typedef wrapper around some Type.
 *
 * Allows the programmer to define a strong type to avoid comparing values that have the same type
 * but are logically different. For example, IDs in a geographic map application for intersections
 * and streets may both be integers, but one should not logically compare an intersection ID with
 * a street ID.
 *
 * Strong typedefs that inherit from this class can be explicitly converted to their base Type,
 * but not implicitly converted. For more information please see:
 * http://en.cppreference.com/w/cpp/language/cast_operator
 *
 * @tparam Tag A unique identifier for this type
 * @tparam Type The actual type (e.g. int) to use
 */
template<class Tag, typename Type>
class type {
public:
  /**
   * The default constructor of type will attempt to initialize the underlying value with its own
   * default constructor.
   */
  constexpr type() : value()
  {
  }

  /**
   * Initialize the underlying value via a copy or move.
   *
   * @param v The value to copy.
   */
  explicit constexpr type(Type const &v) : value(v)
  {
  }

  /**
   * Move constructor.
   *
   * If Type's move constructor does not throw, then this move constructor will have noexcept
   * enabled, which will allow for certain optimizations. For more information, please refer
   * to https://akrzemi1.wordpress.com/2014/04/24/noexcept-what-for/
   *
   * @param v The value to move.
   */
  explicit constexpr type(Type && v) noexcept(std::is_nothrow_move_constructible<Type>::value)
    : value(static_cast<Type &&>(v))
  {
  }

  /**
   * Enables explicit conversion of the type.
   *
   * @return The underlying value.
   */
  explicit operator Type &() noexcept
  {
    return value;
  }

  /**
   * Enables const-correct explicit conversion of the type.
   *
   * @return The underlying value.
   */
  explicit constexpr operator Type const &() const noexcept
  {
    return value;
  }
private:
  Type value;
};

namespace detail {
/**
 * A dummy function used to help determine the type of the underlying value of a strong typedef.
 */
template <class Tag, typename Type>
Type dummy_function(type<Tag, Type>);
}

/**
 * Determine the type of the underlying value of a strong typedef.
 */
template <class Typedef>
using underlying_type = decltype(detail::dummy_function(std::declval<Typedef>()));

/**
 * Operations to enable on strong typedefs.
 */
namespace op {

template<class Typedef, typename Result = bool>
class equality {
public:
  friend constexpr Result operator==(Typedef const &lhs, Typedef const &rhs) {
    using type = underlying_type<Typedef>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  friend constexpr Result operator!=(Typedef const &lhs, Typedef const &rhs) {
    return !(lhs == rhs);
  }
};

template<class Typedef, typename OtherType = Typedef, typename Result = bool>
class mixed_equality {
public:
  friend constexpr Result operator==(Typedef const &lhs, OtherType const &rhs)
  {
    using type = underlying_type<Typedef>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  friend constexpr Result operator!=(Typedef const &lhs, OtherType const &rhs)
  {
    return !(lhs == rhs);
  }

  friend constexpr Result operator==(OtherType const &lhs, Typedef const &rhs)
  {
    using type = underlying_type<Typedef>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  friend constexpr Result operator!=(OtherType const &lhs, Typedef const &rhs)
  {
    return !(lhs == rhs);
  }
};
}

}

#endif //STRONG_STRONG_HPP
<commit_msg>Improve documentation of equality operator<commit_after>#ifndef STRONG_STRONG_HPP
#define STRONG_STRONG_HPP

#include <type_traits>
#include <utility>

/**
 * Namespace for creating strong typedefs.
 */
namespace strong {

/**
 * A strong typedef wrapper around some Type.
 *
 * Allows the programmer to define a strong type to avoid comparing values that have the same type
 * but are logically different. For example, IDs in a geographic map application for intersections
 * and streets may both be integers, but one should not logically compare an intersection ID with
 * a street ID.
 *
 * Strong typedefs that inherit from this class can be explicitly converted to their base Type,
 * but not implicitly converted. For more information please see:
 * http://en.cppreference.com/w/cpp/language/cast_operator
 *
 * @tparam Tag A unique identifier for this type
 * @tparam Type The actual type (e.g. int) to use
 */
template<class Tag, typename Type>
class type {
public:
  /**
   * The default constructor of type will attempt to initialize the underlying value with its own
   * default constructor.
   */
  constexpr type() : value()
  {
  }

  /**
   * Initialize the underlying value via a copy or move.
   *
   * @param v The value to copy.
   */
  explicit constexpr type(Type const &v) : value(v)
  {
  }

  /**
   * Move constructor.
   *
   * If Type's move constructor does not throw, then this move constructor will have noexcept
   * enabled, which will allow for certain optimizations. For more information, please refer
   * to https://akrzemi1.wordpress.com/2014/04/24/noexcept-what-for/
   *
   * @param v The value to move.
   */
  explicit constexpr type(Type && v) noexcept(std::is_nothrow_move_constructible<Type>::value)
    : value(static_cast<Type &&>(v))
  {
  }

  /**
   * Enables explicit conversion of the type.
   *
   * @return The underlying value.
   */
  explicit operator Type &() noexcept
  {
    return value;
  }

  /**
   * Enables const-correct explicit conversion of the type.
   *
   * @return The underlying value.
   */
  explicit constexpr operator Type const &() const noexcept
  {
    return value;
  }
private:
  Type value;
};

namespace detail {
/**
 * A dummy function used to help determine the type of the underlying value of a strong typedef.
 */
template <class Tag, typename Type>
Type dummy_function(type<Tag, Type>);
}

/**
 * Determine the type of the underlying value of a strong typedef.
 */
template <class Typedef>
using underlying_type = decltype(detail::dummy_function(std::declval<Typedef>()));

/**
 * Operations to enable on strong typedefs.
 */
namespace op {

/**
 * Tests for equality or inequality between identical strong types.
 *
 * @tparam Tag The strong typedef to compare.
 * @tparam Result The return type of the comparison
 */
template<class Tag, typename Result = bool>
class equality {
public:
  /**
   * Test for equality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator==(Tag const &lhs, Tag const &rhs) {
    using type = underlying_type<Tag>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  /**
   * Test for inequality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator!=(Tag const &lhs, Tag const &rhs) {
    return !(lhs == rhs);
  }
};

/**
 * Tests for equality or inequality between different strong types.
 *
 * @tparam Tag The strong typedef to compare.
 * @tparam OtherTag The other strong typedef to compare.
 * @tparam Result The return type of the comparison
 */
template<class Tag, typename OtherTag, typename Result = bool>
class mixed_equality {
public:
  /**
   * Test for equality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator==(Tag const &lhs, OtherTag const &rhs)
  {
    using type = underlying_type<Tag>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  /**
   * Test for inequality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator!=(Tag const &lhs, OtherTag const &rhs)
  {
    return !(lhs == rhs);
  }

  /**
   * Test for equality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator==(OtherTag const &lhs, Tag const &rhs)
  {
    using type = underlying_type<Tag>;
    return static_cast<type const &>(lhs) == static_cast<type const &>(rhs);
  }

  /**
   * Test for inequality.
   *
   * @param lhs The left-hand side of the relational expression.
   * @param rhs The right-hand side of the relational expression.
   * @return The result of the comparison.
   */
  friend constexpr Result operator!=(OtherTag const &lhs, Tag const &rhs)
  {
    return !(lhs == rhs);
  }
};
}

}

#endif //STRONG_STRONG_HPP
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: certvalidity.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 17:25:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This 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 this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <xmlsecurity/certvalidity.hxx>

#ifndef _COM_SUN_STAR_SECURITY_CERTIFICATEVALIDITY_HPP_
#include <com/sun/star/security/CertificateValidity.hpp>
#endif

using ::rtl::OUString ;
using namespace ::com::sun::star::security ;

#define VALID_STR "valid certificate"
#define INVALID_STR "invalid certificate"
#define UNTRUSTED_STR "untrusted certificate"
#define TIMEOUT_STR "expired certificate"
#define REVOKED_STR "revoked certificate"
#define UNKNOWN_REVOKATION_STR "unknown certificate revocation status"
#define SIGNATURE_INVALID_STR "invalid certificate signature"
#define EXTENSION_INVALID_STR "invalid certificate extension"
#define EXTENSION_UNKNOWN_STR "unknown critical certificate extension"
#define ISSUER_UNKNOWN_STR "unknown certificate issuer"
#define ISSUER_UNTRUSTED_STR "untrusted certificate issuer"
#define ISSUER_INVALID_STR "invalid certificate issuer"
#define ROOT_UNKNOWN_STR "unknown root certificate"
#define ROOT_UNTRUSTED_STR "untrusted root certificate"
#define ROOT_INVALID_STR "invalid root certificate"
#define CHAIN_INCOMPLETE_STR "invalid certification path"

rtl::OUString certificateValidityToOUString( ::sal_Int32 certValidity ) {
    OUString aValidity ;

    if( !certValidity ) {
        aValidity = OUString::createFromAscii( ( const char* )VALID_STR ) ;
    } else if( ( certValidity & CertificateValidity::INVALID ) == CertificateValidity::INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::UNTRUSTED ) ==  CertificateValidity::UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )UNTRUSTED_STR ) ;
    } else if( ( certValidity & CertificateValidity::TIMEOUT ) == CertificateValidity::TIMEOUT ) {
         aValidity = OUString::createFromAscii( ( const char* )TIMEOUT_STR ) ;
    } else if( ( certValidity & CertificateValidity::REVOKED ) == CertificateValidity::REVOKED ) {
         aValidity = OUString::createFromAscii( ( const char* )REVOKED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::UNKNOWN_REVOKATION ) == CertificateValidity::UNKNOWN_REVOKATION ) {
         aValidity = OUString::createFromAscii( ( const char* )UNKNOWN_REVOKATION_STR ) ;
    } else if( ( certValidity &  CertificateValidity::SIGNATURE_INVALID ) == CertificateValidity::SIGNATURE_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )SIGNATURE_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::EXTENSION_INVALID ) == CertificateValidity::EXTENSION_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )EXTENSION_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::EXTENSION_UNKNOWN ) == CertificateValidity::EXTENSION_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )EXTENSION_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_UNKNOWN ) == CertificateValidity::ISSUER_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_UNTRUSTED ) == CertificateValidity::ISSUER_UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_UNTRUSTED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_INVALID ) == CertificateValidity::ISSUER_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_UNKNOWN ) == CertificateValidity::ROOT_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_UNTRUSTED ) == CertificateValidity::ROOT_UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_UNTRUSTED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_INVALID ) == CertificateValidity::ROOT_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::CHAIN_INCOMPLETE ) == CertificateValidity::CHAIN_INCOMPLETE ) {
         aValidity = OUString::createFromAscii( ( const char* )CHAIN_INCOMPLETE_STR ) ;
    } else {
         aValidity = OUString::createFromAscii( ( const char* )INVALID_STR ) ;
    }

    return aValidity ;
}

<commit_msg>INTEGRATION: CWS xmlsec13 (1.3.24); FILE MERGED 2005/10/31 13:37:40 jl 1.3.24.2: RESYNC: (1.3-1.4); FILE MERGED 2005/10/25 08:19:19 jl 1.3.24.1: #54495# #54047# extra verification of certificates, better errorhandling<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: certvalidity.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-11-11 09:19:09 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This 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 this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <xmlsecurity/certvalidity.hxx>

#ifndef _COM_SUN_STAR_SECURITY_CERTIFICATEVALIDITY_HPP_
#include <com/sun/star/security/CertificateValidity.hpp>
#endif

using ::rtl::OUString ;
using namespace ::com::sun::star::security ;

#define VALID_STR "valid certificate"
#define INVALID_STR "invalid certificate"
#define UNTRUSTED_STR "untrusted certificate"
#define TIME_INVALID_STR "expired certificate"
#define NOT_NESTED_TIME_STR "invalid time nesting"
#define REVOKED_STR "revoked certificate"
#define UNKNOWN_REVOKATION_STR "unknown certificate revocation status"
#define SIGNATURE_INVALID_STR "invalid certificate signature"
#define EXTENSION_INVALID_STR "invalid certificate extension"
#define EXTENSION_UNKNOWN_STR "unknown critical certificate extension"
#define ISSUER_UNKNOWN_STR "unknown certificate issuer"
#define ISSUER_UNTRUSTED_STR "untrusted certificate issuer"
#define ISSUER_INVALID_STR "invalid certificate issuer"
#define ROOT_UNKNOWN_STR "unknown root certificate"
#define ROOT_UNTRUSTED_STR "untrusted root certificate"
#define ROOT_INVALID_STR "invalid root certificate"
#define CHAIN_INCOMPLETE_STR "invalid certification path"

rtl::OUString certificateValidityToOUString( ::sal_Int32 certValidity ) {
    OUString aValidity ;

    if( (certValidity & CertificateValidity::VALID) == CertificateValidity::VALID ) {
        aValidity = OUString::createFromAscii( ( const char* )VALID_STR ) ;
    } else if( ( certValidity & CertificateValidity::INVALID ) == CertificateValidity::INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::UNTRUSTED ) ==  CertificateValidity::UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )UNTRUSTED_STR ) ;
    } else if( ( certValidity & CertificateValidity::TIME_INVALID ) == CertificateValidity::TIME_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )TIME_INVALID_STR ) ;
    } else if( ( certValidity & CertificateValidity::NOT_TIME_NESTED ) == CertificateValidity::NOT_TIME_NESTED ) {
         aValidity = OUString::createFromAscii( ( const char* )NOT_NESTED_TIME_STR ) ;
    } else if( ( certValidity & CertificateValidity::REVOKED ) == CertificateValidity::REVOKED ) {
         aValidity = OUString::createFromAscii( ( const char* )REVOKED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::UNKNOWN_REVOKATION ) == CertificateValidity::UNKNOWN_REVOKATION ) {
         aValidity = OUString::createFromAscii( ( const char* )UNKNOWN_REVOKATION_STR ) ;
    } else if( ( certValidity &  CertificateValidity::SIGNATURE_INVALID ) == CertificateValidity::SIGNATURE_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )SIGNATURE_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::EXTENSION_INVALID ) == CertificateValidity::EXTENSION_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )EXTENSION_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::EXTENSION_UNKNOWN ) == CertificateValidity::EXTENSION_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )EXTENSION_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_UNKNOWN ) == CertificateValidity::ISSUER_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_UNTRUSTED ) == CertificateValidity::ISSUER_UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_UNTRUSTED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ISSUER_INVALID ) == CertificateValidity::ISSUER_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )ISSUER_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_UNKNOWN ) == CertificateValidity::ROOT_UNKNOWN ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_UNKNOWN_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_UNTRUSTED ) == CertificateValidity::ROOT_UNTRUSTED ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_UNTRUSTED_STR ) ;
    } else if( ( certValidity &  CertificateValidity::ROOT_INVALID ) == CertificateValidity::ROOT_INVALID ) {
         aValidity = OUString::createFromAscii( ( const char* )ROOT_INVALID_STR ) ;
    } else if( ( certValidity &  CertificateValidity::CHAIN_INCOMPLETE ) == CertificateValidity::CHAIN_INCOMPLETE ) {
         aValidity = OUString::createFromAscii( ( const char* )CHAIN_INCOMPLETE_STR ) ;
    } else {
         aValidity = OUString::createFromAscii( ( const char* )INVALID_STR ) ;
    }

    return aValidity ;
}

<|endoftext|>


<commit_before>#include "chain_factory.h"
#include "path/radix_tree.h"
#include "../chain_of_responsibility/node_interface.h"

#include <memory>

namespace endpoints
{

class chain_maker {
	radix_tree<chain_generator_t, '/', false> t_;

public:
	chain_maker(radix_tree<chain_generator_t, '/', false> tree) noexcept
		: t_{std::move(tree)}
	{}
	radix_tree<chain_generator_t, '/', false>* operator()() noexcept { return &t_; }
};

chain_factory::chain_factory(chain_generator_t fallback_logic) noexcept
	: fallback_logic{std::move(fallback_logic)}
{}

chain_factory::~chain_factory() noexcept
{}

void chain_factory::get(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(GET, host, path, std::move(logic));
}

void chain_factory::post(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(POST, host, path, std::move(logic));
}

void chain_factory::put(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(PUT, host, path, std::move(logic));
}

chain_factory::chain_ptr chain_factory::get_chain(const http::http_request &original_request) const
{
	return get_chain_private(original_request);
}

chain_factory::chain_ptr chain_factory::get_chain_and_params(http::http_request &original_request) const
{
	return get_chain_private<true>(original_request);
}

void chain_factory::addPattern(chain_factory::method m, const std::string& host, const std::string& path, chain_generator_t logic)
{
	if ( ! host_trees[m] )
		host_trees[m] = std::make_unique<radix_tree<tree_generator_t, '.', true>>();

	radix_tree<chain_generator_t, '/', false> tree;
	tree.addPattern(path, std::move(logic));
	chain_maker maker{std::move(tree)};

	host_trees[m]->addPattern(host.empty() ? "*" : host, std::move(maker));
}

}
<commit_msg>fixed chain_factory<commit_after>#include "chain_factory.h"
#include "path/radix_tree.h"
#include "../chain_of_responsibility/node_interface.h"

#include <memory>

namespace endpoints
{

class chain_maker {
	radix_tree<chain_generator_t, '/', false> t_;

public:
	chain_maker(radix_tree<chain_generator_t, '/', false> tree) noexcept
		: t_{std::move(tree)}
	{}
	radix_tree<chain_generator_t, '/', false>* operator()() noexcept { return &t_; }
};

chain_factory::chain_factory(chain_generator_t fallback_logic) noexcept
	: fallback_logic{std::move(fallback_logic)}
{}

chain_factory::~chain_factory() noexcept
{}

void chain_factory::get(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(GET, host, path, std::move(logic));
}

void chain_factory::post(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(POST, host, path, std::move(logic));
}

void chain_factory::put(const std::string& host, const std::string &path, chain_generator_t logic)
{
	addPattern(PUT, host, path, std::move(logic));
}

chain_factory::chain_ptr chain_factory::get_chain(const http::http_request &original_request) const
{
	return get_chain_private(original_request);
}

chain_factory::chain_ptr chain_factory::get_chain_and_params(http::http_request &original_request) const
{
	return get_chain_private<true>(original_request);
}

void chain_factory::addPattern(chain_factory::method m, const std::string& host, const std::string& path, chain_generator_t logic)
{
	if ( ! host_trees[m] )
		host_trees[m] = std::make_unique<radix_tree<tree_generator_t, '.', true>>();

	if(host_trees[m]->matches(host)) {
		auto ptr = host_trees[m]->get(host);
		if(ptr != nullptr)
			return ptr->addPattern(host, std::move(logic));
	}

	radix_tree<chain_generator_t, '/', false> tree;
	tree.addPattern(path, std::move(logic));
	chain_maker maker{std::move(tree)};
	host_trees[m]->addPattern(host.empty() ? "*" : host, std::move(maker));
}

}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX64M/RX71M グループ FLASH 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstring>
#include "common/delay.hpp"
#include "common/format.hpp"

namespace device {

/// F_FCLK は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_FCLK
#  error "flash_io.hpp requires F_FCLK to be defined"
#endif

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  FLASH 制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class flash_io {

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  データ・フラッシュ構成（全体６４Ｋバイト、ブロック６４バイト）
		*/
		//-----------------------------------------------------------------//
		static const uint32_t data_flash_block = 64;     ///< データ・フラッシュのブロックサイズ
		static const uint32_t data_flash_size  = 65536;  ///< データ・フラッシュの容量
		static const uint32_t data_flash_bank  = 1024;   ///< データ・フラッシュのバンク数

	private:
		bool	trans_farm_;

		/// FACIコマンド発行領域 007E 0000h 4バイト
		static rw8_t<0x007E0000> FACI_CMD_AREA;		///< byte 書き込み

		static rw16_t<0x007E0000> FACI_CMD_AREA16;	///< word(16) 書き込み

		// return 「true」正常、「false」ロック状態
		bool turn_break_() const
		{
			FACI_CMD_AREA = 0xB3;

			// break (4 bytes): FCLK 20MHz to 60MHz max 20us
			//                  FCLK 4MHz max 32us
			// * 1.1
			uint32_t cnt = 22;
			if(F_FCLK < 20000000) cnt = 36;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {
#ifndef NDEBUG
				utils::format("FACI 'turn_break_' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				return true;
			} else {
#ifndef NDEBUG
				utils::format("FACI 'turn_break_' fail\n");
#endif
				return false;
			}
		}

		void turn_rd_() const
		{
			uint32_t n = 5;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--n;
				if(n == 0) break;
			}
			if(n == 0 || device::FLASH::FASTAT.CMDLK() != 0) {
				turn_break_();
			}

			device::FLASH::FENTRYR = 0xAA00;

			if(device::FLASH::FENTRYR() != 0x0000) {
#ifndef NDEBUG
				utils::format("FACI 'turn_rd_' fail\n");
#endif
			}
		}

		void turn_pe_() const
		{
			device::FLASH::FENTRYR = 0xAA80;

			if(device::FLASH::FENTRYR() != 0x0080) {
#ifndef NDEBUG
				utils::format("FACI 'turn_pe_' fail\n");
#endif
			}
		}

		/// FCUファームウェア格納領域 FEFF F000h～FEFF FFFFh 4Kバイト
		/// FCURAM領域 007F 8000h～007F 8FFFh 4Kバイト
		/// コンフィギュレーション設定領域 0012 0040h～0012 007Fh 64バイト
		void init_fcu_()
		{
			if(trans_farm_) return;

			if(device::FLASH::FENTRYR() != 0) {
				device::FLASH::FENTRYR = 0xAA00;
			}

			device::FLASH::FCURAME = 0xC403;  // Write only

			const uint32_t* src = reinterpret_cast<const uint32_t*>(0xFEFFF000);  // Farm master
			uint32_t* dst = reinterpret_cast<uint32_t*>(0x007F8000);  // Farm section
			for(uint32_t i = 0; i < (4096 / 4); ++i) {
				*dst++ = *src++;
			}

			device::FLASH::FCURAME = 0xC400;

			turn_pe_();

			auto f = turn_break_();
			if(f) {
				turn_rd_();

				trans_farm_ = true;
			} else {
#ifndef NDEBUG
				utils::format("FACI Lock...\n");
#endif
			}
		}

		// 4 バイト書き込み
		// org: align 4 bytes
		bool write32_(const void* src, uint32_t org) const
		{
			device::FLASH::FPROTR = 0x5501;
			device::FLASH::FSADDR = org;

			FACI_CMD_AREA = 0xE8;
			FACI_CMD_AREA = 0x02;

			const uint8_t* p = static_cast<const uint8_t*>(src);
			FACI_CMD_AREA16 = (static_cast<uint16_t>(p[1]) << 8) | static_cast<uint16_t>(p[0]);

			while(device::FLASH::FSTATR.DBFULL() != 0) {
				asm("nop");
			}

			FACI_CMD_AREA16 = (static_cast<uint16_t>(p[3]) << 8) | static_cast<uint16_t>(p[2]);

			while(device::FLASH::FSTATR.DBFULL() != 0) {
				asm("nop");
			}

			FACI_CMD_AREA = 0xD0;

			// write (4 bytes): FCLK 20MHz to 60MHz max 1.7ms
			//                  FCLK 4MHz max 3.8ms
			// * 1.1
			uint32_t cnt = 1870;
			if(F_FCLK < 20000000) cnt = 4180;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'write32_' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() != 0) {
#ifndef NDEBUG
				utils::format("FACI 'write32_' CMD Lock fail\n");
#endif
				return false;
			}
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		flash_io() : trans_farm_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
		 */
		//-----------------------------------------------------------------//
		void start()
		{
			device::FLASH::FWEPROR.FLWE = 1;
			init_fcu_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み出し
			@param[in]	org	開始アドレス
			@return データ
		*/
		//-----------------------------------------------------------------//
		uint8_t read(uint32_t org) const
		{
			if(org >= data_flash_size) return 0;
			turn_rd_();
			return device::rd8_(0x00100000 + org);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み出し
			@param[in]	org	開始アドレス
			@param[in]	len	バイト数
			@param[out]	dst	先
		*/
		//-----------------------------------------------------------------//
		void read(uint32_t org, uint32_t len, void* dst) const
		{
			if(org >= data_flash_size) return;
			if((org + len) > data_flash_size) {
				len = data_flash_size - org;
			}
			turn_rd_();
			const void* src = reinterpret_cast<const void*>(0x00100000 + org);
			std::memcpy(dst, src, len);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  消去チェック
			@param[in]	bank	バンク
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool erase_check(uint32_t bank) const
		{
			if(bank >= data_flash_bank) return false;

			device::FLASH::FBCCNT = 0x00;  // address increment
			device::FLASH::FSADDR =  bank * data_flash_block;
			device::FLASH::FEADDR = ((bank + 1) * data_flash_block) - 1;

			FACI_CMD_AREA = 0x71;
			FACI_CMD_AREA = 0xD0;

			// erase cheak (4 bytes): FCLK 20MHz to 60MHz max 30us
			//                        FCLK 4MHz max 84us
			// * 1.1
			uint32_t cnt = 33 * 64 / 4;
			if(F_FCLK < 20000000) cnt = 93 * 64 / 4;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'erase_check' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				if(device::FLASH::FBCSTAT.BCST() != 0) {
					utils::format("FACI 'erase_check' blank check fail: %04X\n") % device::FLASH::FPSADDR();
					return false;
				}
			} else {
#ifndef NDEBUG
				utils::format("FACI 'erase_check' fail\n");
#endif
				return false;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  消去
			@param[in]	bank	バンク
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool erase(uint32_t bank) const
		{
			if(bank >= data_flash_bank) return false;

			turn_pe_();

			device::FLASH::FPROTR = 0x5501;
			device::FLASH::FCPSR  = 0x0000;  // サスペンド優先
			device::FLASH::FSADDR = bank * data_flash_block;

			FACI_CMD_AREA = 0x20;
			FACI_CMD_AREA = 0xD0;

			// 64 bytes erase: FCLK 20MHz to 60MHz max 10ms
			//                 FCLK 4MHz max 18ms
			// * 1.1
			uint32_t cnt = 1100;
			if(F_FCLK < 20000000) cnt = 1980;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(10);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'erase' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				return true;
			} else {
#ifndef NDEBUG
				utils::format("FACI 'erase' fail\n");
#endif
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	src ソース
			@param[in]	org	開始オフセット
			@param[in]	len	バイト数（４の倍数）
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool write(const void* src, uint32_t org, uint32_t len) const
		{
///			if((len & 3) != 0 || (org & 3) != 0) return false;

			if(org >= data_flash_size) return false;

			if((org + len) > data_flash_size) {
				len = data_flash_size - org;
			}

			turn_pe_();

			const uint8_t* p = static_cast<const uint8_t*>(src);
			bool f = false;
			int32_t l = static_cast<int32_t>(len);
			while(l > 0) {
				uint32_t mod = org & 3;
				if(mod != 0) {
					uint8_t tmp[4];
					tmp[0] = 0xFF;
					tmp[1] = 0xFF;
					tmp[2] = 0xFF;
					tmp[3] = 0xFF;
					l -= 4 - mod;
					while(mod < 3) {
						tmp[mod] = *p++;
						++mod;
					}
					org &= 0xFFFFFFFC;
					f = write32_(tmp, org);
				} else {
					f = write32_(p, org);
					p += 4;
					l -= 4;
				}
				if(!f) break;
				org += 4;
			}
			return f;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	org	開始オフセット
			@param[in]	data	書き込みデータ
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool write(uint32_t org, uint8_t data) const
		{
			uint8_t d = data;
			return write(&d, org, 1);
		}
	};
}
<commit_msg>cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX64M/RX71M グループ FLASH 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstring>
#include "common/delay.hpp"
#include "common/format.hpp"

namespace device {

/// F_FCLK は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_FCLK
#  error "flash_io.hpp requires F_FCLK to be defined"
#endif

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  FLASH 制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class flash_io {

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  データ・フラッシュ構成 @n
					（全体６４Ｋバイト、ブロック６４個、バンク１０２４個）
		*/
		//-----------------------------------------------------------------//
		static const uint32_t data_flash_block = 64;     ///< データ・フラッシュのブロックサイズ
		static const uint32_t data_flash_size  = 65536;  ///< データ・フラッシュの容量
		static const uint32_t data_flash_bank  = 1024;   ///< データ・フラッシュのバンク数

	private:
		bool	trans_farm_;

		/// FACIコマンド発行領域 007E 0000h 4バイト
		static rw8_t<0x007E0000> FACI_CMD_AREA;		///< byte 書き込み

		static rw16_t<0x007E0000> FACI_CMD_AREA16;	///< word(16) 書き込み

		// return 「true」正常、「false」ロック状態
		bool turn_break_() const
		{
			FACI_CMD_AREA = 0xB3;

			// break (4 bytes): FCLK 20MHz to 60MHz max 20us
			//                  FCLK 4MHz max 32us
			// * 1.1
			uint32_t cnt = 22;
			if(F_FCLK < 20000000) cnt = 36;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {
#ifndef NDEBUG
				utils::format("FACI 'turn_break_' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				return true;
			} else {
#ifndef NDEBUG
				utils::format("FACI 'turn_break_' fail\n");
#endif
				return false;
			}
		}

		void turn_rd_() const
		{
			uint32_t n = 5;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--n;
				if(n == 0) break;
			}
			if(n == 0 || device::FLASH::FASTAT.CMDLK() != 0) {
				turn_break_();
			}

			device::FLASH::FENTRYR = 0xAA00;

			if(device::FLASH::FENTRYR() != 0x0000) {
#ifndef NDEBUG
				utils::format("FACI 'turn_rd_' fail\n");
#endif
			}
		}

		void turn_pe_() const
		{
			device::FLASH::FENTRYR = 0xAA80;

			if(device::FLASH::FENTRYR() != 0x0080) {
#ifndef NDEBUG
				utils::format("FACI 'turn_pe_' fail\n");
#endif
			}
		}

		/// FCUファームウェア格納領域 FEFF F000h～FEFF FFFFh 4Kバイト
		/// FCURAM領域 007F 8000h～007F 8FFFh 4Kバイト
		/// コンフィギュレーション設定領域 0012 0040h～0012 007Fh 64バイト
		void init_fcu_()
		{
			if(trans_farm_) return;

			if(device::FLASH::FENTRYR() != 0) {
				device::FLASH::FENTRYR = 0xAA00;
			}

			device::FLASH::FCURAME = 0xC403;  // Write only

			const uint32_t* src = reinterpret_cast<const uint32_t*>(0xFEFFF000);  // Farm master
			uint32_t* dst = reinterpret_cast<uint32_t*>(0x007F8000);  // Farm section
			for(uint32_t i = 0; i < (4096 / 4); ++i) {
				*dst++ = *src++;
			}

			device::FLASH::FCURAME = 0xC400;

			turn_pe_();

			auto f = turn_break_();
			if(f) {
				turn_rd_();

				trans_farm_ = true;
			} else {
#ifndef NDEBUG
				utils::format("FACI Lock...\n");
#endif
			}
		}

		// 4 バイト書き込み
		// org: align 4 bytes
		bool write32_(const void* src, uint32_t org) const
		{
			device::FLASH::FPROTR = 0x5501;
			device::FLASH::FSADDR = org;

			FACI_CMD_AREA = 0xE8;
			FACI_CMD_AREA = 0x02;

			const uint8_t* p = static_cast<const uint8_t*>(src);
			FACI_CMD_AREA16 = (static_cast<uint16_t>(p[1]) << 8) | static_cast<uint16_t>(p[0]);

			while(device::FLASH::FSTATR.DBFULL() != 0) {
				asm("nop");
			}

			FACI_CMD_AREA16 = (static_cast<uint16_t>(p[3]) << 8) | static_cast<uint16_t>(p[2]);

			while(device::FLASH::FSTATR.DBFULL() != 0) {
				asm("nop");
			}

			FACI_CMD_AREA = 0xD0;

			// write (4 bytes): FCLK 20MHz to 60MHz max 1.7ms
			//                  FCLK 4MHz max 3.8ms
			// * 1.1
			uint32_t cnt = 1870;
			if(F_FCLK < 20000000) cnt = 4180;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'write32_' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() != 0) {
#ifndef NDEBUG
				utils::format("FACI 'write32_' CMD Lock fail\n");
#endif
				return false;
			}
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		 */
		//-----------------------------------------------------------------//
		flash_io() : trans_farm_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
		 */
		//-----------------------------------------------------------------//
		void start()
		{
			device::FLASH::FWEPROR.FLWE = 1;
			init_fcu_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み出し
			@param[in]	org	開始アドレス
			@return データ
		*/
		//-----------------------------------------------------------------//
		uint8_t read(uint32_t org) const
		{
			if(org >= data_flash_size) return 0;
			turn_rd_();
			return device::rd8_(0x00100000 + org);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み出し
			@param[in]	org	開始アドレス
			@param[in]	len	バイト数
			@param[out]	dst	先
		*/
		//-----------------------------------------------------------------//
		void read(uint32_t org, uint32_t len, void* dst) const
		{
			if(org >= data_flash_size) return;
			if((org + len) > data_flash_size) {
				len = data_flash_size - org;
			}
			turn_rd_();
			const void* src = reinterpret_cast<const void*>(0x00100000 + org);
			std::memcpy(dst, src, len);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  消去チェック
			@param[in]	bank	バンク
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool erase_check(uint32_t bank) const
		{
			if(bank >= data_flash_bank) return false;

			device::FLASH::FBCCNT = 0x00;  // address increment
			device::FLASH::FSADDR =  bank * data_flash_block;
			device::FLASH::FEADDR = ((bank + 1) * data_flash_block) - 1;

			FACI_CMD_AREA = 0x71;
			FACI_CMD_AREA = 0xD0;

			// erase cheak (4 bytes): FCLK 20MHz to 60MHz max 30us
			//                        FCLK 4MHz max 84us
			// * 1.1
			uint32_t cnt = 33 * 64 / 4;
			if(F_FCLK < 20000000) cnt = 93 * 64 / 4;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(1);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'erase_check' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				if(device::FLASH::FBCSTAT.BCST() != 0) {
					utils::format("FACI 'erase_check' blank check fail: %04X\n") % device::FLASH::FPSADDR();
					return false;
				}
			} else {
#ifndef NDEBUG
				utils::format("FACI 'erase_check' fail\n");
#endif
				return false;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  消去
			@param[in]	bank	バンク
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool erase(uint32_t bank) const
		{
			if(bank >= data_flash_bank) return false;

			turn_pe_();

			device::FLASH::FPROTR = 0x5501;
			device::FLASH::FCPSR  = 0x0000;  // サスペンド優先
			device::FLASH::FSADDR = bank * data_flash_block;

			FACI_CMD_AREA = 0x20;
			FACI_CMD_AREA = 0xD0;

			// 64 bytes erase: FCLK 20MHz to 60MHz max 10ms
			//                 FCLK 4MHz max 18ms
			// * 1.1
			uint32_t cnt = 1100;
			if(F_FCLK < 20000000) cnt = 1980;
			while(device::FLASH::FSTATR.FRDY() == 0) {
				utils::delay::micro_second(10);
				--cnt;
				if(cnt == 0) break;
			}
			if(cnt == 0) {  // time out
				turn_break_();
#ifndef NDEBUG
				utils::format("FACI 'erase' timeout\n");
#endif
				return false;
			}

			if(device::FLASH::FASTAT.CMDLK() == 0) {
				return true;
			} else {
#ifndef NDEBUG
				utils::format("FACI 'erase' fail\n");
#endif
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	src ソース
			@param[in]	org	開始オフセット
			@param[in]	len	バイト数（４の倍数）
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool write(const void* src, uint32_t org, uint32_t len) const
		{
///			if((len & 3) != 0 || (org & 3) != 0) return false;

			if(org >= data_flash_size) return false;

			if((org + len) > data_flash_size) {
				len = data_flash_size - org;
			}

			turn_pe_();

			const uint8_t* p = static_cast<const uint8_t*>(src);
			bool f = false;
			int32_t l = static_cast<int32_t>(len);
			while(l > 0) {
				uint32_t mod = org & 3;
				if(mod != 0) {
					uint8_t tmp[4];
					tmp[0] = 0xFF;
					tmp[1] = 0xFF;
					tmp[2] = 0xFF;
					tmp[3] = 0xFF;
					l -= 4 - mod;
					while(mod < 3) {
						tmp[mod] = *p++;
						++mod;
					}
					org &= 0xFFFFFFFC;
					f = write32_(tmp, org);
				} else {
					f = write32_(p, org);
					p += 4;
					l -= 4;
				}
				if(!f) break;
				org += 4;
			}
			return f;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	org	開始オフセット
			@param[in]	data	書き込みデータ
			@return エラーがあれば「false」
		*/
		//-----------------------------------------------------------------//
		bool write(uint32_t org, uint8_t data) const
		{
			uint8_t d = data;
			return write(&d, org, 1);
		}
	};
}
<|endoftext|>