#include #include #include #ifdef GMPZ_DEBUG static void prgmp(mpz_t m, unsigned b = 16) { unsigned l = mpz_sizeinbase(m, b) + 2; std::vector v; v.reserve( l ); mpz_get_str( &v[0], b, m ); printf("%s",&v[0]); } #endif CGmpZAioCtxt::CGmpZAioCtxt(GmpZValAdaptBase adapt, AsyncIO aio, mpz_t *mpz, unsigned nelms, ByteOrder byteOrder, bool doRead) : CAsyncIOCompletion( aio ), adapt_( adapt ), mpz_ ( mpz ), nelms_( nelms ), size_ ( adapt->getSizeBits()/8 ), ord_ ( BE == byteOrder ? 1 : -1 ), rNw_ ( doRead ) { buf_ = new uint8_t[ nelms_*size_ ]; } void CGmpZAioCtxt::complete() { unsigned i; uint8_t *p; bool isSigned = adapt_->isSigned(); MPZ pow2, tmp; mpz_setbit( pow2.m_, 8*size_ ); if ( rNw_ ) { for ( i=0, p=buf_; i size_ ) { throw InvalidArgError("MPZ too big to fit"); } } for ( i=0, p=buf_; igetNelms(); unsigned size = (getSizeBits() + 7)/8; if ( nelms == 0 ) goto bail; mpz_setbit( pow2.m_, 8*size ); MPZArray buf( nelms ); mpz_t *bufp = buf.getBufp(); unsigned got = val->getVal( bufp, nelms ); if ( nelms != got ) { throw ConfigurationError("CGmpZEntryImpl::dumpMyConfigToYaml -- unexpected number of elements read"); } YAML::Node n( YAML::NodeType::Sequence ); unsigned bas = (16 == getConfigBase() ? 16 : 10); std::vector chbuf; for ( i=0; igetNelms(); // A scalar means we will write all elements to same value if ( nelms < nelmsFromPath && !n.IsScalar() ) { std::string str("CGmpZEntryImpl::loadMyConfigFromYaml -- elements in YAML node("); str += p->toString(); str += ") < number expected from PATH"; throw InvalidArgError(str); } if ( nelms > nelmsFromPath ) { fprintf(stderr,"WARNING: CGmpZEntryImpl::loadMyConfigFromYaml -- excess elements in YAML Node (%s); IGNORED\n", p->toString().c_str()); nelms = nelmsFromPath; } MPZ pow2; unsigned size = (getSizeBits() + 7)/8; mpz_setbit( pow2.m_, 8*size ); if ( n.IsScalar() ) { MPZ v; v = n.as(); IndexRange r(0); nelms = nelmsFromPath; if ( isSigned() && mpz_tstbit( v.m_, 8*size_ - 1) ) { mpz_sub( v.m_, v.m_, pow2.m_ ); } for ( i = 0; i < nelms; i++ ) { r.setFromTo(i); val->setVal( &v.m_, 1, &r ); } } else { MPZ v; IndexRange r(0); for ( i = 0; i < nelms; i++ ) { r.setFromTo(i); // assigning an MPZ may be costly (copy); use // the swap operation which GMP advertises to be // efficient... n[i].as().swap( v ); if ( isSigned() && mpz_tstbit( v.m_, 8*size_ - 1) ) { mpz_sub( v.m_, v.m_, pow2.m_ ); } val->setVal( &v.m_, 1, &r ); } } return nelms; } EntryAdapt CGmpZEntryImpl::createAdapter(IEntryAdapterKey &k, Path p, const std::type_info &interfaceType) const { if ( isInterface(interfaceType) ) { if ( getMode() == IVal_Base::WO ) { throw InterfaceNotImplementedError("GmpZVal_RO interface not supported (write-only)"); } return _createAdapter(this, p); } else if ( isInterface(interfaceType) ) { return _createAdapter(this, p); } return CIntEntryImpl::createAdapter(k, p, interfaceType); } CGmpZValAdaptBase::CGmpZValAdaptBase(Key &k, Path p, shared_ptr e) : IEntryAdapt(k, p, e), e_(e) { } uint64_t CGmpZValAdaptBase::getSizeBits() const { // If the underlying IntField has 8 sizeBits and is an array then // we assume it represents a single MPZ. if ( isEncodedMPZ() ) return p_->getNelms() * 8; return e_->getSizeBits(); } unsigned CGmpZValAdaptBase::getNelms() { // If the underlying IntField has 8 sizeBits and is an array then // we assume it represents a single MPZ. if ( isEncodedMPZ() ) return 1; else return p_->getNelms(); } CGmpZVal_ROAdapt::CGmpZVal_ROAdapt(Key &k, Path p, shared_ptr e) : CGmpZValAdaptBase(k, p, e) { } unsigned CGmpZVal_ROAdapt::getVal(mpz_t *p, unsigned nelms, IndexRange *range) { SlicedPathIterator it(p_, range); return getVal( AsyncIO(), p, nelms, &it ); } unsigned CGmpZVal_ROAdapt::getVal(AsyncIO aio, mpz_t *p, unsigned nelms, IndexRange *range) { SlicedPathIterator it(p_, range); return getVal(aio, p, nelms, &it); } unsigned CGmpZVal_ROAdapt::getVal(AsyncIO aio, mpz_t *dst, unsigned nelms, SlicedPathIterator *it) { Address cl = (*it)->c_p_; unsigned nelmsOnPath = (*it).getNelmsLeft(); unsigned size = getSizeBits()/8; if ( nelms >= nelmsOnPath ) { nelms = nelmsOnPath; } else { throw InvalidArgError("CGmpZEntryImpl::getVal: buffer too small"); } shared_ptr ctxt = make_shared( getSelfAs(), aio, dst, nelms, cl->getByteOrder() ); CReadArgs args; args.cacheable_ = e_->getCacheable(); args.off_ = 0; args.dst_ = ctxt->getBufp(); args.nbytes_ = size; if ( aio ) { args.aio_ = ctxt; } cl->read(it, &args); if ( ! aio ) ctxt->callback( 0 ); return nelms; } CGmpZVal_WOAdapt::CGmpZVal_WOAdapt(Key &k, Path p, shared_ptr e) : CGmpZValAdaptBase(k, p, e) { } unsigned CGmpZVal_WOAdapt::setVal(mpz_t *src, unsigned nelms, IndexRange *range) { SlicedPathIterator it(p_, range); Address cl = it->c_p_; unsigned nelmsOnPath = it.getNelmsLeft(); unsigned size = getSizeBits()/8; if ( nelms >= nelmsOnPath ) { nelms = nelmsOnPath; } else { throw InvalidArgError("CGmpZEntryImpl::setVal: not enough elements supplied"); } shared_ptr ctxt = make_shared( getSelfAs(), AsyncIO(), src, nelms, cl->getByteOrder(), false ); CWriteArgs args; args.cacheable_ = e_->getCacheable(); args.src_ = ctxt->getBufp(); args.off_ = 0; args.nbytes_ = size; ctxt->callback( 0 ); cl->write( &it, &args ); return nelms; } CGmpZValAdapt::CGmpZValAdapt(Key &k, Path p, shared_ptr e) : CGmpZValAdaptBase(k, p, e), CGmpZVal_ROAdapt(k, p, e), CGmpZVal_WOAdapt(k, p, e) { } DECLARE_YAML_FIELD_FACTORY(GmpZEntryImpl);