<commit_before>#include <config.h>
#include <ostream>
#include <sstream>
#include <memory>
#include <logger/davix_logger_internal.h>
#include <httprequest.hpp>
#include <posix/davposix.hpp>
#include <posix/davix_stat.hpp>
#include <status/davixstatusrequest.hpp>
#include <fileops/fileutils.hpp>

static const std::string simple_listing("<propfind xmlns=\"DAV:\"><prop></prop></propfind>");

static const std::string stat_listing("<propfind xmlns=\"DAV:\"><prop><getlastmodified/><creationdate/><getcontentlength/><resourcetype><collection/></resourcetype><mode/></prop></propfind>");

struct Davix_dir_handle{

    Davix_dir_handle(Davix::HttpRequest* _req, Davix::DavPropXMLParser * _parser):
        request(_req),
        parser(_parser),
        dir_info((struct dirent*) calloc(1,sizeof(struct dirent) + NAME_MAX +1)),
        dir_offset(0){

    }

   ~Davix_dir_handle(){
        delete request;
        delete parser;
        free(dir_info);
    }

   Davix::HttpRequest* request;
   Davix::DavPropXMLParser * parser;
   struct dirent* dir_info;
   off_t dir_offset;

private:
   Davix_dir_handle(const Davix_dir_handle & );
   Davix_dir_handle & operator=(const Davix_dir_handle & );
};

namespace Davix{

typedef Davix_dir_handle DIR_handle;

static void fill_dirent_from_filestat(struct dirent * d, const FileProperties & f){
    strlcpy(d->d_name, f.filename.c_str(), NAME_MAX);
}

int incremental_propfind_listdir_parsing(HttpRequest* req, DavPropXMLParser * parser, size_t s_buff, const char* scope, DavixError** err){
  //  std::cout << "time 1 pre-fecth" << time(NULL) << std::endl;
    DavixError* tmp_err=NULL;

    char buffer[s_buff+1];
    const ssize_t ret_s_buff= req->readBlock(buffer, s_buff, &tmp_err);
    if(ret_s_buff >= 0){
        buffer[ret_s_buff]= '\0';
        DAVIX_DEBUG("chunk parse : result content : %s", buffer);
        if( parser->parseChuck(buffer, ret_s_buff) < 0){
            DavixError::propagateError(err, parser->getLastErr());
            return -1;
        }
    }

    //std::cout << "time 3 post-parse" << time(NULL) << std::endl;
    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return ret_s_buff;
}

void configure_req_for_listdir(HttpRequest* req){
    req->addHeaderField("Depth","1");
    req->setRequestMethod("PROPFIND");
}

DAVIX_DIR* DavPosix::internal_opendirpp(const RequestParams* _params, const char * scope, const std::string & body, const std::string & url, DavixError** err ){
    ssize_t s_resu;
    DAVIX_DIR* r = NULL;
    int ret =-1;
    DavixError* tmp_err=NULL;
    RequestParams params(_params);

    // create a new connexion + parser for this opendir
    HttpRequest* http_req = static_cast<HttpRequest*>(context->createRequest(url, &tmp_err));
    if(http_req){
        configure_req_for_listdir(http_req);
        std::auto_ptr<DIR_handle> res(  new DIR_handle(http_req, new DavPropXMLParser()));
        time_t timestamp_timeout = time(NULL) + _timeout;

        http_req->setParameters(params);
        DavPropXMLParser* parser = res->parser;
        // setup the handle for simple listing only
        http_req->setRequestBodyString(body);

        if( (ret = http_req->beginRequest(&tmp_err)) == 0){ // start req

            if( ( ret = davixRequestToFileStatus(http_req,davix_scope_directory_listing_str(), &tmp_err)) == 0){

                    size_t prop_size = 0;
                    do{ // parse the begining of the request until the first property -> directory property
                       if( (s_resu = incremental_propfind_listdir_parsing(http_req, parser, this->_s_buff, scope, &tmp_err)) <0)
                           break;

                       prop_size = parser->getProperties().size();
                       if(s_resu < _s_buff && prop_size <1){ // verify request status : if req done + no data -> error
                           DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::WebDavPropertiesParsingError, "request answer incorrect, not a valid webdav request");
                           break;
                       }
                       if(timestamp_timeout < time(NULL)){
                           DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::OperationTimeout, "operation timeout triggered while directory listing");
                           break;
                       }

                    }while( prop_size < 1); // leave is end of req & no data

                    if(!tmp_err){
                        if( S_ISDIR(parser->getProperties().at(0).mode) == false){
                             DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::IsNotADirectory, url + " is not a collection or a directory, impossible to list");
                        }else{
                            parser->getProperties().pop_front(); // suppress the parent directory infos...
                            r = res.release(); // success : take ownership of the pointer
                        }
                    }
            }
        }
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return (DAVIX_DIR*) r;
}

DAVIX_DIR* DavPosix::opendir(const RequestParams* params, const std::string &url, DavixError** err){

    DAVIX_DEBUG(" -> davix_opendir");
    DAVIX_DIR* r = internal_opendirpp(params, "Core::opendir",simple_listing, url, err);

    DAVIX_DEBUG(" <- davix_opendir");
    return (DAVIX_DIR*) r;
}

DAVIX_DIR* DavPosix::opendirpp(const RequestParams* params, const std::string &url, DavixError** err){

    DAVIX_DEBUG(" -> davix_opendirpp");
    DAVIX_DIR* r = internal_opendirpp(params, "Core::opendir",stat_listing, url, err);

    DAVIX_DEBUG(" <- davix_opendirpp");
    return (DAVIX_DIR*) r;
}

struct dirent* DavPosix::readdir(DAVIX_DIR * d, DavixError** err){
    DIR_handle* handle = static_cast<DIR_handle*>(d);
    DavixError* tmp_err=NULL;
    DAVIX_DEBUG(" -> davix_readdir");

    if( d==NULL){
        DavixError::setupError(err, davix_scope_directory_listing_str(), StatusCode::InvalidFileHandle,  "Invalid file descriptor for DAVIX_DIR*");
        return NULL;
    }

    HttpRequest *req = handle->request; // setup env again
    DavPropXMLParser* parser = handle->parser;
    off_t read_offset = handle->dir_offset+1;
    size_t prop_size = parser->getProperties().size();
    size_t s_resu = _s_buff;

    while( prop_size == 0
          && s_resu > 0){ // request not complete and current data too smalls
        // continue the parsing until one more result
       if( (s_resu = incremental_propfind_listdir_parsing(req, parser, this->_s_buff, "Davix::readdir", &tmp_err)) <0)
           break;

       prop_size = parser->getProperties().size();
    }
    if(!tmp_err){
        if(prop_size == 0) // end of the request, end of the story
            return NULL;
        fill_dirent_from_filestat(handle->dir_info, parser->getProperties().front());
        handle->dir_offset = read_offset;
        parser->getProperties().pop_front(); // clean the current element
        DAVIX_DEBUG(" <- davix_readdir");
        return handle->dir_info;
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return NULL;
}

struct dirent* DavPosix::readdirpp(DAVIX_DIR * d, struct stat *st, DavixError** err){
    DAVIX_DEBUG(" -> davix_readdirpp");

    if( d==NULL){
        DavixError::setupError(err, davix_scope_directory_listing_str(), StatusCode::InvalidFileHandle,  "Invalid file descriptor for DAVIX_DIR*");
        return NULL;
    }

    DIR_handle* handle = static_cast<DIR_handle*>(d);
    struct dirent* ret = NULL;
    DavixError* tmp_err=NULL;

    HttpRequest* req = handle->request; // setup env again
    DavPropXMLParser* parser = handle->parser;
    off_t read_offset = handle->dir_offset+1;
    size_t prop_size = parser->getProperties().size();
    size_t s_resu = _s_buff;

    while( prop_size == 0
          && s_resu > 0){ // request not complete and current data too smalls
        // continue the parsing until one more result
       if( (s_resu = incremental_propfind_listdir_parsing(req, parser, this->_s_buff, "Davix::readdirpp", &tmp_err)) <0)
           break;

       prop_size = parser->getProperties().size();
    }

    if(!tmp_err){
        if(prop_size == 0){
            ret= NULL; // end of the request, end of the story
        }else{
            fill_dirent_from_filestat(handle->dir_info, parser->getProperties().front());
            handle->dir_offset = read_offset;
            fill_stat_from_fileproperties(st, parser->getProperties().front());
            parser->getProperties().pop_front(); // clean the current element
            ret= handle->dir_info;
        }
        DAVIX_DEBUG(" <- davix_readdirpp");
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return ret;
}

int DavPosix::closedirpp(DAVIX_DIR * d, DavixError** err){
    int ret =-1;
    if( d==NULL){
        Davix::DavixError::setupError(err,davix_scope_directory_listing_str(),Davix::StatusCode::InvalidFileHandle, "Invalid file descriptor for DAVIX_DIR*");
   }else{
        delete (static_cast<DIR_handle*>(d));
        ret =0;
    }
    return ret;
}

int DavPosix::closedir(DAVIX_DIR * d, DavixError** err){
    return closedirpp(d,err);
}

} // namespace Davix

DAVIX_C_DECL_BEGIN

DAVIX_DIR* davix_posix_opendir(davix_sess_t sess, davix_params_t _params, const char* url,  davix_error_t* err){
    davix_return_val_if_fail(sess != NULL, NULL);
    DAVIX_DIR* ret = NULL;

    Davix::DavPosix p((Davix::Context*)(sess));
    Davix::RequestParams * params = (Davix::RequestParams*) (_params);
    ret= p.opendir(params,url, (Davix::DavixError**) err);

    return ret;
}

int davix_posix_closedir(davix_sess_t sess, DAVIX_DIR* d, davix_error_t* err){
    davix_return_val_if_fail(sess != NULL,-1);

    Davix::DavPosix p((Davix::Context*)(sess));

    return p.closedir(d,(Davix::DavixError**) err);

}

struct dirent* davix_posix_readdir(davix_sess_t sess, DAVIX_DIR* d, davix_error_t* err){
    davix_return_val_if_fail(sess != NULL,NULL);

    struct dirent* ret = NULL;
    Davix::DavPosix p((Davix::Context*)(sess));

    if(d){
        ret= p.readdir(d, (Davix::DavixError**) err);
    }

    return ret;
}

DAVIX_C_DECL_END

<commit_msg>- fix bad opendir request content<commit_after>#include <config.h>
#include <ostream>
#include <sstream>
#include <memory>
#include <logger/davix_logger_internal.h>
#include <httprequest.hpp>
#include <posix/davposix.hpp>
#include <posix/davix_stat.hpp>
#include <status/davixstatusrequest.hpp>
#include <fileops/fileutils.hpp>

static const std::string simple_listing("<propfind xmlns=\"DAV:\"><prop><resourcetype><collection/></resourcetype></prop></propfind>");

static const std::string stat_listing("<propfind xmlns=\"DAV:\"><prop><getlastmodified/><creationdate/><getcontentlength/><resourcetype><collection/></resourcetype><mode/></prop></propfind>");

struct Davix_dir_handle{

    Davix_dir_handle(Davix::HttpRequest* _req, Davix::DavPropXMLParser * _parser):
        request(_req),
        parser(_parser),
        dir_info((struct dirent*) calloc(1,sizeof(struct dirent) + NAME_MAX +1)),
        dir_offset(0){

    }

   ~Davix_dir_handle(){
        delete request;
        delete parser;
        free(dir_info);
    }

   Davix::HttpRequest* request;
   Davix::DavPropXMLParser * parser;
   struct dirent* dir_info;
   off_t dir_offset;

private:
   Davix_dir_handle(const Davix_dir_handle & );
   Davix_dir_handle & operator=(const Davix_dir_handle & );
};

namespace Davix{

typedef Davix_dir_handle DIR_handle;

static void fill_dirent_from_filestat(struct dirent * d, const FileProperties & f){
    strlcpy(d->d_name, f.filename.c_str(), NAME_MAX);
}

int incremental_propfind_listdir_parsing(HttpRequest* req, DavPropXMLParser * parser, size_t s_buff, const char* scope, DavixError** err){
  //  std::cout << "time 1 pre-fecth" << time(NULL) << std::endl;
    DavixError* tmp_err=NULL;

    char buffer[s_buff+1];
    const ssize_t ret_s_buff= req->readBlock(buffer, s_buff, &tmp_err);
    if(ret_s_buff >= 0){
        buffer[ret_s_buff]= '\0';
        DAVIX_DEBUG("chunk parse : result content : %s", buffer);
        if( parser->parseChuck(buffer, ret_s_buff) < 0){
            DavixError::propagateError(err, parser->getLastErr());
            return -1;
        }
    }

    //std::cout << "time 3 post-parse" << time(NULL) << std::endl;
    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return ret_s_buff;
}

void configure_req_for_listdir(HttpRequest* req){
    req->addHeaderField("Depth","1");
    req->setRequestMethod("PROPFIND");
}

DAVIX_DIR* DavPosix::internal_opendirpp(const RequestParams* _params, const char * scope, const std::string & body, const std::string & url, DavixError** err ){
    ssize_t s_resu;
    DAVIX_DIR* r = NULL;
    int ret =-1;
    DavixError* tmp_err=NULL;
    RequestParams params(_params);

    // create a new connexion + parser for this opendir
    HttpRequest* http_req = static_cast<HttpRequest*>(context->createRequest(url, &tmp_err));
    if(http_req){
        configure_req_for_listdir(http_req);
        std::auto_ptr<DIR_handle> res(  new DIR_handle(http_req, new DavPropXMLParser()));
        time_t timestamp_timeout = time(NULL) + _timeout;

        http_req->setParameters(params);
        DavPropXMLParser* parser = res->parser;
        // setup the handle for simple listing only
        http_req->setRequestBodyString(body);

        if( (ret = http_req->beginRequest(&tmp_err)) == 0){ // start req

            if( ( ret = davixRequestToFileStatus(http_req,davix_scope_directory_listing_str(), &tmp_err)) == 0){

                    size_t prop_size = 0;
                    do{ // parse the begining of the request until the first property -> directory property
                       if( (s_resu = incremental_propfind_listdir_parsing(http_req, parser, this->_s_buff, scope, &tmp_err)) <0)
                           break;

                       prop_size = parser->getProperties().size();
                       if(s_resu < _s_buff && prop_size <1){ // verify request status : if req done + no data -> error
                           DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::WebDavPropertiesParsingError, "request answer incorrect, not a valid webdav request");
                           break;
                       }
                       if(timestamp_timeout < time(NULL)){
                           DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::OperationTimeout, "operation timeout triggered while directory listing");
                           break;
                       }

                    }while( prop_size < 1); // leave is end of req & no data

                    if(!tmp_err){
                        if( S_ISDIR(parser->getProperties().at(0).mode) == false){
                             DavixError::setupError(&tmp_err, davix_scope_directory_listing_str(), StatusCode::IsNotADirectory, url + " is not a collection or a directory, impossible to list");
                        }else{
                            parser->getProperties().pop_front(); // suppress the parent directory infos...
                            r = res.release(); // success : take ownership of the pointer
                        }
                    }
            }
        }
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return (DAVIX_DIR*) r;
}

DAVIX_DIR* DavPosix::opendir(const RequestParams* params, const std::string &url, DavixError** err){

    DAVIX_DEBUG(" -> davix_opendir");
    DAVIX_DIR* r = internal_opendirpp(params, "Core::opendir",simple_listing, url, err);

    DAVIX_DEBUG(" <- davix_opendir");
    return (DAVIX_DIR*) r;
}

DAVIX_DIR* DavPosix::opendirpp(const RequestParams* params, const std::string &url, DavixError** err){

    DAVIX_DEBUG(" -> davix_opendirpp");
    DAVIX_DIR* r = internal_opendirpp(params, "Core::opendir",stat_listing, url, err);

    DAVIX_DEBUG(" <- davix_opendirpp");
    return (DAVIX_DIR*) r;
}

struct dirent* DavPosix::readdir(DAVIX_DIR * d, DavixError** err){
    DIR_handle* handle = static_cast<DIR_handle*>(d);
    DavixError* tmp_err=NULL;
    DAVIX_DEBUG(" -> davix_readdir");

    if( d==NULL){
        DavixError::setupError(err, davix_scope_directory_listing_str(), StatusCode::InvalidFileHandle,  "Invalid file descriptor for DAVIX_DIR*");
        return NULL;
    }

    HttpRequest *req = handle->request; // setup env again
    DavPropXMLParser* parser = handle->parser;
    off_t read_offset = handle->dir_offset+1;
    size_t prop_size = parser->getProperties().size();
    size_t s_resu = _s_buff;

    while( prop_size == 0
          && s_resu > 0){ // request not complete and current data too smalls
        // continue the parsing until one more result
       if( (s_resu = incremental_propfind_listdir_parsing(req, parser, this->_s_buff, "Davix::readdir", &tmp_err)) <0)
           break;

       prop_size = parser->getProperties().size();
    }
    if(!tmp_err){
        if(prop_size == 0) // end of the request, end of the story
            return NULL;
        fill_dirent_from_filestat(handle->dir_info, parser->getProperties().front());
        handle->dir_offset = read_offset;
        parser->getProperties().pop_front(); // clean the current element
        DAVIX_DEBUG(" <- davix_readdir");
        return handle->dir_info;
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return NULL;
}

struct dirent* DavPosix::readdirpp(DAVIX_DIR * d, struct stat *st, DavixError** err){
    DAVIX_DEBUG(" -> davix_readdirpp");

    if( d==NULL){
        DavixError::setupError(err, davix_scope_directory_listing_str(), StatusCode::InvalidFileHandle,  "Invalid file descriptor for DAVIX_DIR*");
        return NULL;
    }

    DIR_handle* handle = static_cast<DIR_handle*>(d);
    struct dirent* ret = NULL;
    DavixError* tmp_err=NULL;

    HttpRequest* req = handle->request; // setup env again
    DavPropXMLParser* parser = handle->parser;
    off_t read_offset = handle->dir_offset+1;
    size_t prop_size = parser->getProperties().size();
    size_t s_resu = _s_buff;

    while( prop_size == 0
          && s_resu > 0){ // request not complete and current data too smalls
        // continue the parsing until one more result
       if( (s_resu = incremental_propfind_listdir_parsing(req, parser, this->_s_buff, "Davix::readdirpp", &tmp_err)) <0)
           break;

       prop_size = parser->getProperties().size();
    }

    if(!tmp_err){
        if(prop_size == 0){
            ret= NULL; // end of the request, end of the story
        }else{
            fill_dirent_from_filestat(handle->dir_info, parser->getProperties().front());
            handle->dir_offset = read_offset;
            fill_stat_from_fileproperties(st, parser->getProperties().front());
            parser->getProperties().pop_front(); // clean the current element
            ret= handle->dir_info;
        }
        DAVIX_DEBUG(" <- davix_readdirpp");
    }

    if(tmp_err)
        DavixError::propagateError(err, tmp_err);
    return ret;
}

int DavPosix::closedirpp(DAVIX_DIR * d, DavixError** err){
    int ret =-1;
    if( d==NULL){
        Davix::DavixError::setupError(err,davix_scope_directory_listing_str(),Davix::StatusCode::InvalidFileHandle, "Invalid file descriptor for DAVIX_DIR*");
   }else{
        delete (static_cast<DIR_handle*>(d));
        ret =0;
    }
    return ret;
}

int DavPosix::closedir(DAVIX_DIR * d, DavixError** err){
    return closedirpp(d,err);
}

} // namespace Davix

DAVIX_C_DECL_BEGIN

DAVIX_DIR* davix_posix_opendir(davix_sess_t sess, davix_params_t _params, const char* url,  davix_error_t* err){
    davix_return_val_if_fail(sess != NULL, NULL);
    DAVIX_DIR* ret = NULL;

    Davix::DavPosix p((Davix::Context*)(sess));
    Davix::RequestParams * params = (Davix::RequestParams*) (_params);
    ret= p.opendir(params,url, (Davix::DavixError**) err);

    return ret;
}

int davix_posix_closedir(davix_sess_t sess, DAVIX_DIR* d, davix_error_t* err){
    davix_return_val_if_fail(sess != NULL,-1);

    Davix::DavPosix p((Davix::Context*)(sess));

    return p.closedir(d,(Davix::DavixError**) err);

}

struct dirent* davix_posix_readdir(davix_sess_t sess, DAVIX_DIR* d, davix_error_t* err){
    davix_return_val_if_fail(sess != NULL,NULL);

    struct dirent* ret = NULL;
    Davix::DavPosix p((Davix::Context*)(sess));

    if(d){
        ret= p.readdir(d, (Davix::DavixError**) err);
    }

    return ret;
}

DAVIX_C_DECL_END

<|endoftext|>


<commit_before>///
/// @file  nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, n is too small");
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = (double) n;
  double logx = log(max(4.0, x));
  double pix = x / logx;
  return (int64_t) pix;
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = (double) (n - count);

  x = abs(x);
  x = max(x, 4.0);

  // rough pi(x) approximation
  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // correct start if sieving backwards to get
  // a more accurate approximation
  if (count >= n)
    start -= (uint64_t) pix;

  // approximate the nth prime using:
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = start + pix / loglogx;
  startPix = max(4.0, startPix);
  double logStartPix = log(startPix);
  double dist = max(pix, x * logStartPix);

  // ensure start + dist <= nth prime
  if (count < n)
    dist -= sqrt(dist) * log(logStartPix) * 2;
  // ensure start + dist >= nth prime
  if (count > n)
    dist += sqrt(dist) * log(logStartPix) * 2;

  // if n is very small:
  // ensure (start + dist) >= nth prime
  double maxPrimeGap = logStartPix * logStartPix;
  dist = max(dist, maxPrimeGap);

  return (uint64_t) dist;
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  auto t1 = chrono::system_clock::now();

  if (n == 0)
    n = 1; // like Mathematica
  else if (n > 0)
    start = checkedAdd(start, 1);
  else if (n < 0)
    start = checkedSub(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = checkedAdd(start, dist);

  int64_t count = 0;
  int64_t tinyN = 100000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = checkedAdd(start, dist);
      count += countPrimes(start, stop);
      start = checkedAdd(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = checkedSub(start, dist);
      count -= countPrimes(start, stop);
      stop = checkedSub(start, 1);
    }
  }

  if (n < 0)
    count -= 1;

  // here start < nth prime,
  // hence we can sieve forward the remaining
  // distance and find the nth prime
  assert(count < n);

  try
  {
    checkLimit(start);
    dist = nthPrimeDist(n, count, start) * 2;
    start = checkedSub(start, 1);
    stop = checkedAdd(start, dist);
    uint64_t prime = 0;
    for (primesieve::iterator it(start, stop); count < n; count++)
      prime = it.next_prime();

    auto t2 = chrono::system_clock::now();
    chrono::duration<double> seconds = t2 - t1;
    seconds_ = seconds.count();

    return prime;
  }
  catch (primesieve_error&) { }

  throw primesieve_error("nth prime > 2^64");
}

} // namespace
<commit_msg>Fix undefined-behavior<commit_after>///
/// @file  nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, n is too small");
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = (double) n;
  double logx = log(max(4.0, x));
  double pix = x / logx;
  return (int64_t) pix;
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = (double) (n - count);

  x = abs(x);
  x = max(x, 4.0);

  // rough pi(x) approximation
  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // correct start if sieving backwards to get
  // a more accurate approximation
  if (count >= n)
    start -= (uint64_t) pix;

  // approximate the nth prime using:
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = start + pix / loglogx;
  startPix = max(4.0, startPix);
  double logStartPix = log(startPix);
  double dist = max(pix, x * logStartPix);

  // ensure start + dist <= nth prime
  if (count < n)
    dist -= sqrt(dist) * log(logStartPix) * 2;
  // ensure start + dist >= nth prime
  if (count > n)
    dist += sqrt(dist) * log(logStartPix) * 2;

  // if n is very small:
  // ensure (start + dist) >= nth prime
  double maxPrimeGap = logStartPix * logStartPix;
  dist = max(dist, maxPrimeGap);

  return (uint64_t) dist;
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  auto t1 = chrono::system_clock::now();

  if (n == 0)
    n = 1; // like Mathematica
  else if (n > 0)
    start = checkedAdd(start, 1);
  else if (n < 0)
    start = checkedSub(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = checkedAdd(start, dist);

  int64_t count = 0;
  int64_t tinyN = 100000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = checkedAdd(start, dist);
      count += countPrimes(start, stop);
      start = checkedAdd(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = checkedSub(start, dist);
      count -= (int64_t) countPrimes(start, stop);
      stop = checkedSub(start, 1);
    }
  }

  if (n < 0)
    count -= 1;

  // here start < nth prime,
  // hence we can sieve forward the remaining
  // distance and find the nth prime
  assert(count < n);

  try
  {
    checkLimit(start);
    dist = nthPrimeDist(n, count, start) * 2;
    start = checkedSub(start, 1);
    stop = checkedAdd(start, dist);
    uint64_t prime = 0;
    for (primesieve::iterator it(start, stop); count < n; count++)
      prime = it.next_prime();

    auto t2 = chrono::system_clock::now();
    chrono::duration<double> seconds = t2 - t1;
    seconds_ = seconds.count();

    return prime;
  }
  catch (primesieve_error&) { }

  throw primesieve_error("nth prime > 2^64");
}

} // namespace
<|endoftext|>


<commit_before>//   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/framework/details/broadcast_op_handle.h"
#include "paddle/fluid/framework/details/container_cast.h"
#include "paddle/fluid/framework/details/variable_visitor.h"
#include "paddle/fluid/platform/profiler.h"

namespace paddle {
namespace framework {
namespace details {

void BroadcastOpHandle::RunImpl() {
  platform::RecordEvent record_event(Name(), dev_ctxes_.begin()->second);

  if (places_.size() == 1) return;

  // The input and output may have dummy vars.
  VarHandle *in_var_handle;
  {
    auto in_var_handles = DynamicCast<VarHandle>(inputs_);
    PADDLE_ENFORCE_EQ(in_var_handles.size(), 1,
                      "The number of input should be one.");
    in_var_handle = in_var_handles[0];
  }

  auto out_var_handles = DynamicCast<VarHandle>(outputs_);

  PADDLE_ENFORCE_EQ(
      out_var_handles.size(), places_.size(),
      "The number of output should equal to the number of places.");

  WaitInputVarGenerated();

  std::vector<const Scope *> var_scopes;
  for (auto *s : local_scopes_) {
    var_scopes.emplace_back(s->FindVar(kLocalExecScopeName)->Get<Scope *>());
  }

  BroadcastOneVar(*in_var_handle, out_var_handles, var_scopes);
}

void BroadcastOpHandle::BroadcastOneVar(
    const VarHandle &in_var_handle,
    const std::vector<VarHandle *> &out_var_handles,
    const std::vector<const Scope *> &var_scopes) {
  auto *in_var =
      var_scopes.at(in_var_handle.scope_idx_)->FindVar(in_var_handle.name_);
  PADDLE_ENFORCE_NOT_NULL(in_var);
  Tensor &in_tensor = VariableVisitor::GetMutableTensor(in_var);
  if (!in_tensor.IsInitialized()) {
    VLOG(3) << "in var " << in_var_handle->name_ << "not inited, return!";
    return;
  }

  InitOutputValue(in_var_handle, out_var_handles);

  if (platform::is_cpu_place(in_tensor.place())) {
    for (auto *out_var_handle : out_var_handles) {
      if (out_var_handle->IsTheSameVar(in_var_handle)) {
        continue;
      }
      auto &out_p = out_var_handle->place_;
      auto *out_var = var_scopes.at(out_var_handle->scope_idx_)
                          ->FindVar(out_var_handle->name_);

      RunAndRecordEvent(out_p, [in_tensor, out_var] {
        paddle::framework::TensorCopy(
            in_tensor, platform::CPUPlace(),
            &VariableVisitor::GetMutableTensor(out_var));
      });
    }
  } else {
#ifdef PADDLE_WITH_CUDA
    VarHandle *out_handle = nullptr;
    int root_id = boost::get<platform::CUDAPlace>(in_tensor.place()).device;
    std::vector<std::function<void()>> broadcast_calls;

    int type = platform::ToNCCLDataType(in_tensor.type());
    size_t numel = static_cast<size_t>(in_tensor.numel());

    for (auto out_var_handle : out_var_handles) {
      Variable *out_var = var_scopes.at(out_var_handle->scope_idx_)
                              ->FindVar(out_var_handle->name_);

      int dst_id =
          boost::get<platform::CUDAPlace>(out_var_handle->place_).device;

      auto &nccl_ctx = nccl_ctxs_->at(dst_id);

      void *send_recv_buffer = nullptr;
      if (root_id == dst_id) {
        send_recv_buffer = const_cast<void *>(in_tensor.data<void>());
        out_handle = out_var_handle;
      } else {
        send_recv_buffer = VariableVisitor::GetMutableTensor(out_var)
                               .Resize(in_tensor.dims())
                               .mutable_data(out_var_handle->place_);
      }

      broadcast_calls.emplace_back(
          [send_recv_buffer, numel, type, root_id, &nccl_ctx] {
            PADDLE_ENFORCE(platform::dynload::ncclBcast(
                send_recv_buffer, numel, static_cast<ncclDataType_t>(type),
                root_id, nccl_ctx.comm_, nccl_ctx.stream()));
          });
    }

    this->RunAndRecordEvent([&] {
      {
        platform::NCCLGroupGuard guard;
        for (auto &call : broadcast_calls) {
          call();
        }
      }

      if (!out_handle->IsTheSameVar(in_var_handle)) {
        auto out_var = var_scopes.at(in_var_handle.scope_idx_)
                           ->FindVar(out_var_handles[0]->name_);
        paddle::framework::TensorCopy(
            in_tensor, in_var_handle.place_,
            *(dev_ctxes_.at(in_var_handle.place_)),
            &VariableVisitor::GetMutableTensor(out_var));
      }
    });
#else
    PADDLE_THROW("CUDA is not enabled.");
#endif
  }
}

void BroadcastOpHandle::InitOutputValue(
    const VarHandle &in_var_handle,
    const std::vector<VarHandle *> &out_var_handles) const {
  std::vector<const Scope *> var_scopes;
  for (auto *s : local_scopes_) {
    var_scopes.emplace_back(s->FindVar(kLocalExecScopeName)->Get<Scope *>());
  }
  auto *in_var =
      var_scopes.at(in_var_handle.scope_idx_)->FindVar(in_var_handle.name_);

  Tensor &in_tensor = VariableVisitor::GetMutableTensor(in_var);

  // NOTE: The tensors' Place of input and output must be all on GPU or all on
  // CPU.
  for (auto *out_var_handle : out_var_handles) {
    if (out_var_handle->IsTheSameVar(in_var_handle)) {
      continue;
    }
    auto t_out_p = out_var_handle->place_;
    auto *out_var = var_scopes.at(out_var_handle->scope_idx_)
                        ->FindVar(out_var_handle->name_);
    PADDLE_ENFORCE_NOT_NULL(out_var);
    if (is_gpu_place(in_tensor.place())) {
      PADDLE_ENFORCE(platform::is_gpu_place(t_out_p),
                     "Places of input and output must be all on GPU.");
    } else {
      t_out_p = platform::CPUPlace();
    }
    VariableVisitor::ShareDimsAndLoD(*in_var, out_var);
    VariableVisitor::GetMutableTensor(out_var).mutable_data(t_out_p,
                                                            in_tensor.type());
  }
}

std::string BroadcastOpHandle::Name() const { return "broadcast"; }
}  // namespace details
}  // namespace framework
}  // namespace paddle
<commit_msg>fix compile, optimize code test=develop<commit_after>//   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/framework/details/broadcast_op_handle.h"
#include "paddle/fluid/framework/details/container_cast.h"
#include "paddle/fluid/framework/details/variable_visitor.h"
#include "paddle/fluid/platform/profiler.h"

namespace paddle {
namespace framework {
namespace details {

void BroadcastOpHandle::RunImpl() {
  platform::RecordEvent record_event(Name(), dev_ctxes_.begin()->second);

  if (places_.size() == 1) return;

  // The input and output may have dummy vars.
  VarHandle *in_var_handle;
  {
    auto in_var_handles = DynamicCast<VarHandle>(inputs_);
    PADDLE_ENFORCE_EQ(in_var_handles.size(), 1,
                      "The number of input should be one.");
    in_var_handle = in_var_handles[0];
  }

  auto out_var_handles = DynamicCast<VarHandle>(outputs_);

  PADDLE_ENFORCE_EQ(
      out_var_handles.size(), places_.size(),
      "The number of output should equal to the number of places.");

  WaitInputVarGenerated();

  std::vector<const Scope *> var_scopes;
  for (auto *s : local_scopes_) {
    var_scopes.emplace_back(s->FindVar(kLocalExecScopeName)->Get<Scope *>());
  }

  BroadcastOneVar(*in_var_handle, out_var_handles, var_scopes);
}

void BroadcastOpHandle::BroadcastOneVar(
    const VarHandle &in_var_handle,
    const std::vector<VarHandle *> &out_var_handles,
    const std::vector<const Scope *> &var_scopes) {
  auto *in_var =
      var_scopes.at(in_var_handle.scope_idx_)->FindVar(in_var_handle.name_);
  PADDLE_ENFORCE_NOT_NULL(in_var);
  Tensor &in_tensor = VariableVisitor::GetMutableTensor(in_var);
  if (UNLIKELY(!in_tensor.IsInitialized())) {
    VLOG(3) << "in var " << in_var_handle.name_ << "not inited, return!";
    return;
  }

  InitOutputValue(in_var_handle, out_var_handles);

  if (platform::is_cpu_place(in_tensor.place())) {
    for (auto *out_var_handle : out_var_handles) {
      if (out_var_handle->IsTheSameVar(in_var_handle)) {
        continue;
      }
      auto &out_p = out_var_handle->place_;
      auto *out_var = var_scopes.at(out_var_handle->scope_idx_)
                          ->FindVar(out_var_handle->name_);

      RunAndRecordEvent(out_p, [in_tensor, out_var] {
        paddle::framework::TensorCopy(
            in_tensor, platform::CPUPlace(),
            &VariableVisitor::GetMutableTensor(out_var));
      });
    }
  } else {
#ifdef PADDLE_WITH_CUDA
    VarHandle *out_handle = nullptr;
    int root_id = boost::get<platform::CUDAPlace>(in_tensor.place()).device;
    std::vector<std::function<void()>> broadcast_calls;

    int type = platform::ToNCCLDataType(in_tensor.type());
    size_t numel = static_cast<size_t>(in_tensor.numel());

    for (auto out_var_handle : out_var_handles) {
      Variable *out_var = var_scopes.at(out_var_handle->scope_idx_)
                              ->FindVar(out_var_handle->name_);

      int dst_id =
          boost::get<platform::CUDAPlace>(out_var_handle->place_).device;

      auto &nccl_ctx = nccl_ctxs_->at(dst_id);

      void *send_recv_buffer = nullptr;
      if (root_id == dst_id) {
        send_recv_buffer = const_cast<void *>(in_tensor.data<void>());
        out_handle = out_var_handle;
      } else {
        send_recv_buffer = VariableVisitor::GetMutableTensor(out_var)
                               .Resize(in_tensor.dims())
                               .mutable_data(out_var_handle->place_);
      }

      broadcast_calls.emplace_back(
          [send_recv_buffer, numel, type, root_id, &nccl_ctx] {
            PADDLE_ENFORCE(platform::dynload::ncclBcast(
                send_recv_buffer, numel, static_cast<ncclDataType_t>(type),
                root_id, nccl_ctx.comm_, nccl_ctx.stream()));
          });
    }

    this->RunAndRecordEvent([&] {
      {
        platform::NCCLGroupGuard guard;
        for (auto &call : broadcast_calls) {
          call();
        }
      }

      if (!out_handle->IsTheSameVar(in_var_handle)) {
        auto out_var = var_scopes.at(in_var_handle.scope_idx_)
                           ->FindVar(out_var_handles[0]->name_);
        paddle::framework::TensorCopy(
            in_tensor, in_var_handle.place_,
            *(dev_ctxes_.at(in_var_handle.place_)),
            &VariableVisitor::GetMutableTensor(out_var));
      }
    });
#else
    PADDLE_THROW("CUDA is not enabled.");
#endif
  }
}

void BroadcastOpHandle::InitOutputValue(
    const VarHandle &in_var_handle,
    const std::vector<VarHandle *> &out_var_handles) const {
  std::vector<const Scope *> var_scopes;
  for (auto *s : local_scopes_) {
    var_scopes.emplace_back(s->FindVar(kLocalExecScopeName)->Get<Scope *>());
  }
  auto *in_var =
      var_scopes.at(in_var_handle.scope_idx_)->FindVar(in_var_handle.name_);

  Tensor &in_tensor = VariableVisitor::GetMutableTensor(in_var);

  // NOTE: The tensors' Place of input and output must be all on GPU or all on
  // CPU.
  for (auto *out_var_handle : out_var_handles) {
    if (out_var_handle->IsTheSameVar(in_var_handle)) {
      continue;
    }
    auto t_out_p = out_var_handle->place_;
    auto *out_var = var_scopes.at(out_var_handle->scope_idx_)
                        ->FindVar(out_var_handle->name_);
    PADDLE_ENFORCE_NOT_NULL(out_var);
    if (is_gpu_place(in_tensor.place())) {
      PADDLE_ENFORCE(platform::is_gpu_place(t_out_p),
                     "Places of input and output must be all on GPU.");
    } else {
      t_out_p = platform::CPUPlace();
    }
    VariableVisitor::ShareDimsAndLoD(*in_var, out_var);
    VariableVisitor::GetMutableTensor(out_var).mutable_data(t_out_p,
                                                            in_tensor.type());
  }
}

std::string BroadcastOpHandle::Name() const { return "broadcast"; }
}  // namespace details
}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>#include "naoqi_planner.h"

namespace naoqi_planner {
  using namespace naoqi_sensor_utils;

  NAOqiPlanner::NAOqiPlanner(qi::SessionPtr session){
    _session = session;
    if (! _session)
      throw std::runtime_error("Error: No memory service provided");

    _use_gui = false;
    _what_to_show = Map;

    _restart = true;

    _have_goal = false;
    _goal = Eigen::Vector2i(0,0);
    _robot_pose = Eigen::Vector3f(0.,0.,0.);

    _prev_v = 0.0; _prev_w = 0.0;
  }

  void NAOqiPlanner::initGUI(){
    _use_gui=true;
    cv::namedWindow( "pepper_planner", 0 );
    cv::setMouseCallback( "pepper_planner", &NAOqiPlanner::onMouse, this );
    std::cerr << "GUI initialized" << std::endl;
  }

  void NAOqiPlanner::onMouse( int event, int x, int y, int, void* v)
  {
    NAOqiPlanner* n=reinterpret_cast<NAOqiPlanner*>(v);

    if( event == cv::EVENT_LBUTTONDOWN ) {
      std::cerr << "Left Click!" << std::endl;
      n->_goal = Eigen::Vector2i(y,x);
      n->_have_goal = true;
      std::cerr << "Setting goal: " << n->_goal.transpose() << std::endl;
    }

  }

  void NAOqiPlanner::handleGUIInput(){
    if (! _use_gui)
      return;

    char key=cv::waitKey(10);
    switch(key) {
    case 'm':
      if (_what_to_show == Map)
	break;
      std::cerr << "Switching view to map" << std::endl;
      _what_to_show = Map;
      break;
    case 'd':
      if (_what_to_show == Distance)
	break;
      std::cerr << "Switching view to distance map" << std::endl;
      _what_to_show = Distance;
      break;
    case 'c':
      if (_what_to_show == Cost)
	break;
      std::cerr << "Switching view to cost map" << std::endl;
      _what_to_show = Cost;
      break;
    case 'r':
      std::cerr << "Resetting" << std::endl;
      _restart = true;
      _have_goal = false;
      //Removing obstacles
      {
	int occ_threshold = (1.0 - _occ_threshold) * 255;
	int free_threshold = (1.0 - _free_threshold) * 255;
	grayMap2indices(_indices_image, _map_image, occ_threshold, free_threshold);
      }
    default:;
    }
  }

  void NAOqiPlanner::handleGUIDisplay() {
    if (_use_gui) {
      FloatImage shown_image;
      switch(_what_to_show){
      case Map:
	shown_image.create(_indices_image.rows, _indices_image.cols);
	for (int r=0; r<_indices_image.rows; ++r) {
	  int* src_ptr=_indices_image.ptr<int>(r);
	  float* dest_ptr=shown_image.ptr<float>(r);
	  for (int c=0; c<_indices_image.cols; ++c, ++src_ptr, ++dest_ptr){
	    if (*src_ptr<-1)
	      *dest_ptr = .5f;
	    else if (*src_ptr == -1)
	      *dest_ptr = 1.f;
	    else
	      *dest_ptr=0.f;
	  }
	}
	break;

      case Distance:
	shown_image=_distance_image*(1./_safety_region);
	break;
      case Cost:
	shown_image=_cost_image*(1.f/_max_cost);
	break;
      }

      //cv::namedWindow("indices_img", 0);
      //cv::imshow("indices_img", _indices_image);

      // Drawing goal
      if (_have_goal)
	cv::circle(shown_image, cv::Point(_goal.y(), _goal.x()), 3, cv::Scalar(0.0f));

      // Drawing current pose
      cv::rectangle(shown_image,
		    cv::Point(_robot_pose_image.y()+2, _robot_pose_image.x()-2),
		    cv::Point(_robot_pose_image.y()-2, _robot_pose_image.x()+2),
		    cv::Scalar(0.0f));

      //Draw path
      if (_robot_pose_image.x()>=0 && _have_goal){
	PathMapCell* current=&_path_map(_robot_pose_image.x(), _robot_pose_image.y());
	while (current&& current->parent && current->parent!=current) {
	  PathMapCell* parent=current->parent;
	  cv::line(shown_image,
		   cv::Point(current->c, current->r),
		   cv::Point(parent->c, parent->r),
		   cv::Scalar(0.0f));
	  current = current->parent;
	}
      }

      cv::imshow("pepper_planner", shown_image);
    }

  }

  void NAOqiPlanner::readMap(const std::string mapname){
    std::cerr << "Reading map" << mapname << std::endl;

    // reading map info
    SimpleYAMLParser parser;
    parser.load(mapname);
    std::cerr << "Dirname: " << dirname(strdup(mapname.c_str())) << std::endl;

    std::string map_image_name = parser.getValue("image");
    _map_resolution = parser.getValueAsFloat("resolution");
    _map_inverse_resolution = 1./_map_resolution;
    _occ_threshold = parser.getValueAsFloat("occupied_thresh");
    _free_threshold = parser.getValueAsFloat("free_thresh");
    _map_origin = parser.getValueAsVector3f("origin");
    _map_origin_transform_inverse = v2t(_map_origin).inverse();

    std::cerr << "MAP NAME: " << map_image_name << std::endl;
    std::cerr << "RESOLUTION: " << _map_resolution << std::endl;
    std::cerr << "ORIGIN: " << _map_origin.transpose() << std::endl;
    std::cerr << "OCC THRESHOLD: " << _occ_threshold << std::endl;
    std::cerr << "FREE THRESHOLD: " << _free_threshold << std::endl;

    std::string full_path_map_image = std::string(dirname(strdup(mapname.c_str())))+"/"+map_image_name;
    std::cerr << "Opening image" << full_path_map_image << std::endl;

    _map_image = cv::imread(full_path_map_image, CV_LOAD_IMAGE_GRAYSCALE);
    std::cerr << "Image read: (" << _map_image.rows << "x" << _map_image.cols << ")" << std::endl;

    int occ_threshold = (1.0 - _occ_threshold) * 255;
    int free_threshold = (1.0 - _free_threshold) * 255;
    grayMap2indices(_indices_image, _map_image, occ_threshold, free_threshold);
  }

  void NAOqiPlanner::subscribeServices(){
    qi::AnyObject memory_service = _session->service("ALMemory");
    qi::AnyObject motion_service = _session->service("ALMotion");

    _stop_thread=false;
    _servicesMonitorThread = std::thread(&NAOqiPlanner::servicesMonitorThread, this, memory_service, motion_service);
    std::cerr << "Planner Services Monitor Thread launched." << std::endl;
  }

  void NAOqiPlanner::unsubscribeServices(){
    _stop_thread=true;
    _servicesMonitorThread.join();
  }

  void NAOqiPlanner::servicesMonitorThread(qi::AnyObject memory_service, qi::AnyObject motion_service) {
    while (!_stop_thread){
      qi::SteadyClock::time_point time_start = qi::SteadyClock::now();

      //get robot localization
      qi::AnyValue value = memory_service.call<qi::AnyValue>("getData", "NAOqiLocalizer/RobotPose");
      srrg_core::FloatVector robot_pose_floatvector = value.toList<float>();
      _robot_pose = srrg_core::fromFloatVector3f(robot_pose_floatvector);
      std::cerr << "Robot pose map: " << _robot_pose.transpose() << std::endl;

      Eigen::Isometry2f robot_pose_transform=_map_origin_transform_inverse*v2t(_robot_pose);
      Eigen::Vector3f robot_pose_vector=t2v(robot_pose_transform);

      _robot_pose_image = world2grid(Eigen::Vector2f(robot_pose_vector.x(), robot_pose_vector.y()));

      //get laser
      Vector2fVector laserpoints = getLaser(memory_service);
      Vector2iVector obstacle_points;
      for (size_t i=0; i<laserpoints.size(); i++){
	Eigen::Vector2f lp=robot_pose_transform* laserpoints[i];
	int r = lp.x()*_map_inverse_resolution;
	int c = lp.y()*_map_inverse_resolution;
	if (! _distance_map.inside(r,c))
	  continue;
	obstacle_points.push_back(Eigen::Vector2i(r,c));
      }

      //here I'll do something map + loc + laser + goal -> path

      if (_restart){
	_dmap_calculator.setMaxDistance(_safety_region/_map_resolution);
	_dmap_calculator.setIndicesImage(_indices_image);
	_dmap_calculator.setOutputPathMap(_distance_map);
	_dmap_calculator.init();
	_restart = false;
      }
      _dmap_calculator.setPoints(obstacle_points);

      _dmap_calculator.compute();
      _distance_image = _dmap_calculator.distanceImage()*_map_resolution;

      distances2cost(_cost_image, _distance_image, _robot_radius, _safety_region, _min_cost, _max_cost);

      if (_have_goal){
	_path_calculator.setMaxCost(_max_cost-1);
	_path_calculator.setCostMap(_cost_image);
	_path_calculator.setOutputPathMap(_path_map);
	Vector2iVector goals;
	goals.push_back(_goal);
	_path_calculator.goals() = goals;
	_path_calculator.compute();

	_path.clear();

	// Filling path
	std::ofstream ofs ("path.dat", std::ofstream::out);
	PathMapCell* current=&_path_map(_robot_pose_image.x(), _robot_pose_image.y());
	while (current&& current->parent && current->parent!=current) {
	  PathMapCell* parent=current->parent;
	  _path.push_back(Eigen::Vector2i(current->r, current->c));
	  ofs << current->r << current->c << std::endl;

	  current = current->parent;
	}

	float linear_vel, angular_vel;
	computeControlToWaypoint(linear_vel, angular_vel);
	//apply vels
	std::cerr << "Applying vels: " << linear_vel  << " " << angular_vel << std::endl;
	motion_service.call<void>("move", linear_vel,0,angular_vel);

      } //else nothing to compute

      handleGUIDisplay();

      handleGUIInput();

      qi::SteadyClock::time_point time_end = qi::SteadyClock::now();
      qi::MilliSeconds ms = boost::chrono::duration_cast<qi::MilliSeconds>(time_end - time_start);
      std::cerr << "Cycle " << qi::to_string(ms) << std::endl;

      usleep(200000);
    }
    std::cout << "Planner Monitor Thread finished." << std::endl;

  }

  void NAOqiPlanner::computeControlToWaypoint(float& v, float& w) {
    if (!_path.size()){
      v = 0.0;
      w = 0.0;

      _prev_v = v;
      _prev_w = w;
      return;
    }

    // Next waypoint naive computation.
    float nextwp_distance = 1.0; //meters
    int num_cells = nextwp_distance * _map_inverse_resolution;

    Eigen::Vector2i nextwp;
    bool isLastWp = false;
    if (_path.size() > num_cells)
      nextwp = _path[num_cells];
    else{
      nextwp = _path[_path.size()-1];
      isLastWp = true;
    }

    Eigen::Vector2f nextwp_world = grid2world(nextwp);
    Eigen::Vector2f robot_pose_xy(_robot_pose.x(), _robot_pose.y());
    Eigen::Vector2f distance_goal = nextwp_world - robot_pose_xy;
    float angle_goal = normalize(atan2(distance_goal.y(),distance_goal.x()) - _robot_pose.z());
    float goal_distance_threshold = 0.3;
    if (distance_goal.norm() < goal_distance_threshold){
      std::cerr << ">>>>>>>>>>Arrived to goal: " << nextwp.transpose() << std::endl;
      if (isLastWp){
	std::cerr << ">>>>>>>>>>Arrived to last goal" << std::endl;
	v = 0.0;
	w = 0.0;

	_prev_v = v;
	_prev_w = w;
	_have_goal = false;
	return;
      }
    }else {
      std::cerr << "Distance to goal: " << distance_goal.norm() << std::endl;
      std::cerr << "Angle to goal: " << angle_goal << std::endl;
    }

    float force = 1.5;
    Eigen::Vector2f F(force*cos(angle_goal), force*sin(angle_goal));

    //Constants definition
    float f = 1.0;
    float b = 1.975;
    float k_i = 0.95;
    float h = 2.05;
    float T = 0.2;

    //limiting force
    if (F.norm() > f){
      float angleF = atan2(F.y(), F.x());
      F.x() = cos(angleF)*f;
      F.y() = sin(angleF)*f;
    }

    v = (F.x() * T + _prev_v) / (1 + 2*b*T);
    if (v < 0)
      v = 0;
    w = (k_i *h * F.y() * T + _prev_w) / (1 + 2*b*k_i*T);
    if (w < 1e-4)
      w = 0;

    _prev_v = v;
    _prev_w = w;

  }

}
<commit_msg>rotation-only behaviour<commit_after>#include "naoqi_planner.h"

namespace naoqi_planner {
  using namespace naoqi_sensor_utils;

  NAOqiPlanner::NAOqiPlanner(qi::SessionPtr session){
    _session = session;
    if (! _session)
      throw std::runtime_error("Error: No memory service provided");

    _use_gui = false;
    _what_to_show = Map;

    _restart = true;

    _have_goal = false;
    _goal = Eigen::Vector2i(0,0);
    _robot_pose = Eigen::Vector3f(0.,0.,0.);

    _prev_v = 0.0; _prev_w = 0.0;
  }

  void NAOqiPlanner::initGUI(){
    _use_gui=true;
    cv::namedWindow( "pepper_planner", 0 );
    cv::setMouseCallback( "pepper_planner", &NAOqiPlanner::onMouse, this );
    std::cerr << "GUI initialized" << std::endl;
  }

  void NAOqiPlanner::onMouse( int event, int x, int y, int, void* v)
  {
    NAOqiPlanner* n=reinterpret_cast<NAOqiPlanner*>(v);

    if( event == cv::EVENT_LBUTTONDOWN ) {
      std::cerr << "Left Click!" << std::endl;
      n->_goal = Eigen::Vector2i(y,x);
      n->_have_goal = true;
      std::cerr << "Setting goal: " << n->_goal.transpose() << std::endl;
    }

  }

  void NAOqiPlanner::handleGUIInput(){
    if (! _use_gui)
      return;

    char key=cv::waitKey(10);
    switch(key) {
    case 'm':
      if (_what_to_show == Map)
	break;
      std::cerr << "Switching view to map" << std::endl;
      _what_to_show = Map;
      break;
    case 'd':
      if (_what_to_show == Distance)
	break;
      std::cerr << "Switching view to distance map" << std::endl;
      _what_to_show = Distance;
      break;
    case 'c':
      if (_what_to_show == Cost)
	break;
      std::cerr << "Switching view to cost map" << std::endl;
      _what_to_show = Cost;
      break;
    case 'r':
      std::cerr << "Resetting" << std::endl;
      _restart = true;
      _have_goal = false;
      //Removing obstacles
      {
	int occ_threshold = (1.0 - _occ_threshold) * 255;
	int free_threshold = (1.0 - _free_threshold) * 255;
	grayMap2indices(_indices_image, _map_image, occ_threshold, free_threshold);
      }
    default:;
    }
  }

  void NAOqiPlanner::handleGUIDisplay() {
    if (_use_gui) {
      FloatImage shown_image;
      switch(_what_to_show){
      case Map:
	shown_image.create(_indices_image.rows, _indices_image.cols);
	for (int r=0; r<_indices_image.rows; ++r) {
	  int* src_ptr=_indices_image.ptr<int>(r);
	  float* dest_ptr=shown_image.ptr<float>(r);
	  for (int c=0; c<_indices_image.cols; ++c, ++src_ptr, ++dest_ptr){
	    if (*src_ptr<-1)
	      *dest_ptr = .5f;
	    else if (*src_ptr == -1)
	      *dest_ptr = 1.f;
	    else
	      *dest_ptr=0.f;
	  }
	}
	break;

      case Distance:
	shown_image=_distance_image*(1./_safety_region);
	break;
      case Cost:
	shown_image=_cost_image*(1.f/_max_cost);
	break;
      }

      //cv::namedWindow("indices_img", 0);
      //cv::imshow("indices_img", _indices_image);

      // Drawing goal
      if (_have_goal)
	cv::circle(shown_image, cv::Point(_goal.y(), _goal.x()), 3, cv::Scalar(0.0f));

      // Drawing current pose
      cv::rectangle(shown_image,
		    cv::Point(_robot_pose_image.y()+2, _robot_pose_image.x()-2),
		    cv::Point(_robot_pose_image.y()-2, _robot_pose_image.x()+2),
		    cv::Scalar(0.0f));

      //Draw path
      if (_robot_pose_image.x()>=0 && _have_goal){
	PathMapCell* current=&_path_map(_robot_pose_image.x(), _robot_pose_image.y());
	while (current&& current->parent && current->parent!=current) {
	  PathMapCell* parent=current->parent;
	  cv::line(shown_image,
		   cv::Point(current->c, current->r),
		   cv::Point(parent->c, parent->r),
		   cv::Scalar(0.0f));
	  current = current->parent;
	}
      }

      cv::imshow("pepper_planner", shown_image);
    }

  }

  void NAOqiPlanner::readMap(const std::string mapname){
    std::cerr << "Reading map" << mapname << std::endl;

    // reading map info
    SimpleYAMLParser parser;
    parser.load(mapname);
    std::cerr << "Dirname: " << dirname(strdup(mapname.c_str())) << std::endl;

    std::string map_image_name = parser.getValue("image");
    _map_resolution = parser.getValueAsFloat("resolution");
    _map_inverse_resolution = 1./_map_resolution;
    _occ_threshold = parser.getValueAsFloat("occupied_thresh");
    _free_threshold = parser.getValueAsFloat("free_thresh");
    _map_origin = parser.getValueAsVector3f("origin");
    _map_origin_transform_inverse = v2t(_map_origin).inverse();

    std::cerr << "MAP NAME: " << map_image_name << std::endl;
    std::cerr << "RESOLUTION: " << _map_resolution << std::endl;
    std::cerr << "ORIGIN: " << _map_origin.transpose() << std::endl;
    std::cerr << "OCC THRESHOLD: " << _occ_threshold << std::endl;
    std::cerr << "FREE THRESHOLD: " << _free_threshold << std::endl;

    std::string full_path_map_image = std::string(dirname(strdup(mapname.c_str())))+"/"+map_image_name;
    std::cerr << "Opening image" << full_path_map_image << std::endl;

    _map_image = cv::imread(full_path_map_image, CV_LOAD_IMAGE_GRAYSCALE);
    std::cerr << "Image read: (" << _map_image.rows << "x" << _map_image.cols << ")" << std::endl;

    int occ_threshold = (1.0 - _occ_threshold) * 255;
    int free_threshold = (1.0 - _free_threshold) * 255;
    grayMap2indices(_indices_image, _map_image, occ_threshold, free_threshold);
  }

  void NAOqiPlanner::subscribeServices(){
    qi::AnyObject memory_service = _session->service("ALMemory");
    qi::AnyObject motion_service = _session->service("ALMotion");

    _stop_thread=false;
    _servicesMonitorThread = std::thread(&NAOqiPlanner::servicesMonitorThread, this, memory_service, motion_service);
    std::cerr << "Planner Services Monitor Thread launched." << std::endl;
  }

  void NAOqiPlanner::unsubscribeServices(){
    _stop_thread=true;
    _servicesMonitorThread.join();
  }

  void NAOqiPlanner::servicesMonitorThread(qi::AnyObject memory_service, qi::AnyObject motion_service) {
    while (!_stop_thread){
      qi::SteadyClock::time_point time_start = qi::SteadyClock::now();

      //get robot localization
      qi::AnyValue value = memory_service.call<qi::AnyValue>("getData", "NAOqiLocalizer/RobotPose");
      srrg_core::FloatVector robot_pose_floatvector = value.toList<float>();
      _robot_pose = srrg_core::fromFloatVector3f(robot_pose_floatvector);
      std::cerr << "Robot pose map: " << _robot_pose.transpose() << std::endl;

      Eigen::Isometry2f robot_pose_transform=_map_origin_transform_inverse*v2t(_robot_pose);
      Eigen::Vector3f robot_pose_vector=t2v(robot_pose_transform);

      _robot_pose_image = world2grid(Eigen::Vector2f(robot_pose_vector.x(), robot_pose_vector.y()));

      //get laser
      Vector2fVector laserpoints = getLaser(memory_service);
      Vector2iVector obstacle_points;
      for (size_t i=0; i<laserpoints.size(); i++){
	Eigen::Vector2f lp=robot_pose_transform* laserpoints[i];
	int r = lp.x()*_map_inverse_resolution;
	int c = lp.y()*_map_inverse_resolution;
	if (! _distance_map.inside(r,c))
	  continue;
	obstacle_points.push_back(Eigen::Vector2i(r,c));
      }

      //here I'll do something map + loc + laser + goal -> path

      if (_restart){
	_dmap_calculator.setMaxDistance(_safety_region/_map_resolution);
	_dmap_calculator.setIndicesImage(_indices_image);
	_dmap_calculator.setOutputPathMap(_distance_map);
	_dmap_calculator.init();
	_restart = false;
      }
      _dmap_calculator.setPoints(obstacle_points);

      _dmap_calculator.compute();
      _distance_image = _dmap_calculator.distanceImage()*_map_resolution;

      distances2cost(_cost_image, _distance_image, _robot_radius, _safety_region, _min_cost, _max_cost);

      if (_have_goal){
	_path_calculator.setMaxCost(_max_cost-1);
	_path_calculator.setCostMap(_cost_image);
	_path_calculator.setOutputPathMap(_path_map);
	Vector2iVector goals;
	goals.push_back(_goal);
	_path_calculator.goals() = goals;
	_path_calculator.compute();

	_path.clear();

	// Filling path
	std::ofstream ofs ("path.dat", std::ofstream::out);
	PathMapCell* current=&_path_map(_robot_pose_image.x(), _robot_pose_image.y());
	while (current&& current->parent && current->parent!=current) {
	  PathMapCell* parent=current->parent;
	  _path.push_back(Eigen::Vector2i(current->r, current->c));
	  ofs << current->r << current->c << std::endl;

	  current = current->parent;
	}

	float linear_vel, angular_vel;
	computeControlToWaypoint(linear_vel, angular_vel);
	//apply vels
	std::cerr << "Applying vels: " << linear_vel  << " " << angular_vel << std::endl;
	motion_service.call<void>("move", linear_vel,0,angular_vel);

      } //else nothing to compute

      handleGUIDisplay();

      handleGUIInput();

      qi::SteadyClock::time_point time_end = qi::SteadyClock::now();
      qi::MilliSeconds ms = boost::chrono::duration_cast<qi::MilliSeconds>(time_end - time_start);
      std::cerr << "Cycle " << qi::to_string(ms) << std::endl;

      usleep(200000);
    }
    std::cout << "Planner Monitor Thread finished." << std::endl;

  }

  void NAOqiPlanner::computeControlToWaypoint(float& v, float& w) {
    if (!_path.size()){
      v = 0.0;
      w = 0.0;

      _prev_v = v;
      _prev_w = w;
      return;
    }

    // Next waypoint naive computation.
    float nextwp_distance = 1.0; //meters
    int num_cells = nextwp_distance * _map_inverse_resolution;

    Eigen::Vector2i nextwp;
    bool isLastWp = false;
    if (_path.size() > num_cells)
      nextwp = _path[num_cells];
    else{
      nextwp = _path[_path.size()-1];
      isLastWp = true;
    }

    Eigen::Vector2f nextwp_world = grid2world(nextwp);
    Eigen::Vector2f robot_pose_xy(_robot_pose.x(), _robot_pose.y());
    Eigen::Vector2f distance_goal = nextwp_world - robot_pose_xy;
    float angle_goal = normalize(atan2(distance_goal.y(),distance_goal.x()) - _robot_pose.z());
    float goal_distance_threshold = 0.3;
    if (distance_goal.norm() < goal_distance_threshold){
      std::cerr << ">>>>>>>>>>Arrived to goal: " << nextwp.transpose() << std::endl;
      if (isLastWp){
	std::cerr << ">>>>>>>>>>Arrived to last goal" << std::endl;
	v = 0.0;
	w = 0.0;

	_prev_v = v;
	_prev_w = w;
	_have_goal = false;
	return;
      }
    }else {
      std::cerr << "Distance to goal: " << distance_goal.norm() << std::endl;
      std::cerr << "Angle to goal: " << angle_goal << std::endl;
    }

    float force = 1.5;
    Eigen::Vector2f F(force*cos(angle_goal), force*sin(angle_goal));

    //Constants definition
    float f = 1.0;
    float b = 1.975;
    float k_i = 0.95;
    float h = 2.05;
    float T = 0.2;

    //limiting force
    if (F.norm() > f){
      float angleF = atan2(F.y(), F.x());
      F.x() = cos(angleF)*f;
      F.y() = sin(angleF)*f;
    }

    v = (F.x() * T + _prev_v) / (1 + 2*b*T);
    if (v < 0)
      v = 0;
    w = (k_i *h * F.y() * T + _prev_w) / (1 + 2*b*k_i*T);
    if (w < 1e-4)
      w = 0;

    // Switch to rotation-only behaviour
    float max_angle_goal = 0.3;
    if (fabs(angle_goal) > max_angle_goal)
      v = 0;

    _prev_v = v;
    _prev_w = w;

  }

}
<|endoftext|>


<commit_before>#include "wallettests.h"

#include "qt/bitcoinamountfield.h"
#include "qt/callback.h"
#include "qt/optionsmodel.h"
#include "qt/platformstyle.h"
#include "qt/qvalidatedlineedit.h"
#include "qt/sendcoinsdialog.h"
#include "qt/sendcoinsentry.h"
#include "qt/transactiontablemodel.h"
#include "qt/transactionview.h"
#include "qt/walletmodel.h"
#include "test/test_bitcoin.h"
#include "validation.h"
#include "wallet/wallet.h"

#include <QAbstractButton>
#include <QAction>
#include <QApplication>
#include <QCheckBox>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>

namespace
{
//! Press "Ok" button in message box dialog.
void ConfirmMessage(QString* text = nullptr)
{
    QTimer::singleShot(0, makeCallback([text](Callback* callback) {
        for (QWidget* widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("QMessageBox")) {
                QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
                if (text) *text = messageBox->text();
                messageBox->defaultButton()->click();
            }
        }
        delete callback;
    }), SLOT(call()));
}

//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString* text = nullptr, bool cancel = false)
{
    QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
        for (QWidget* widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("SendConfirmationDialog")) {
                SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
                if (text) *text = dialog->text();
                QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
                button->setEnabled(true);
                button->click();
            }
        }
        delete callback;
    }), SLOT(call()));
}

//! Send coins to address and return txid.
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
{
    QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
    SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
    entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
    entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
    sendCoinsDialog.findChild<QFrame*>("frameFee")
        ->findChild<QFrame*>("frameFeeSelection")
        ->findChild<QCheckBox*>("optInRBF")
        ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
    uint256 txid;
    boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
        if (status == CT_NEW) txid = hash;
    }));
    ConfirmSend();
    QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
    return txid;
}

//! Find index of txid in transaction list.
QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
{
    QString hash = QString::fromStdString(txid.ToString());
    int rows = model.rowCount({});
    for (int row = 0; row < rows; ++row) {
        QModelIndex index = model.index(row, 0, {});
        if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
            return index;
        }
    }
    return {};
}

//! Invoke bumpfee on txid and check results.
void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
{
    QTableView* table = view.findChild<QTableView*>("transactionView");
    QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
    QVERIFY2(index.isValid(), "Could not find BumpFee txid");

    // Select row in table, invoke context menu, and make sure bumpfee action is
    // enabled or disabled as expected.
    QAction* action = view.findChild<QAction*>("bumpFeeAction");
    table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
    action->setEnabled(expectDisabled);
    table->customContextMenuRequested({});
    QCOMPARE(action->isEnabled(), !expectDisabled);

    action->setEnabled(true);
    QString text;
    if (expectError.empty()) {
        ConfirmSend(&text, cancel);
    } else {
        ConfirmMessage(&text);
    }
    action->trigger();
    QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
}

//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
// manually running the event loop, e.g.:
//
//     sendCoinsDialog.show();
//     QEventLoop().exec();
//
// This also requires overriding the default minimal Qt platform:
//
//     src/qt/test/test_bitcoin-qt -platform xcb      # Linux
//     src/qt/test/test_bitcoin-qt -platform windows  # Windows
//     src/qt/test/test_bitcoin-qt -platform cocoa    # macOS
void TestSendCoins()
{
    // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
    TestChain100Setup test;
    for (int i = 0; i < 5; ++i) {
        test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
    }
    bitdb.MakeMock();
    std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
    CWallet wallet(std::move(dbw));
    bool firstRun;
    wallet.LoadWallet(firstRun);
    {
        LOCK(wallet.cs_wallet);
        wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
        wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
    }
    wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
    wallet.SetBroadcastTransactions(true);

    // Create widgets for sending coins and listing transactions.
    std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
    SendCoinsDialog sendCoinsDialog(platformStyle.get());
    TransactionView transactionView(platformStyle.get());
    OptionsModel optionsModel;
    WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
    sendCoinsDialog.setModel(&walletModel);
    transactionView.setModel(&walletModel);

    // Send two transactions, and verify they are added to transaction list.
    TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
    QCOMPARE(transactionTableModel->rowCount({}), 105);
    uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
    uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
    QCOMPARE(transactionTableModel->rowCount({}), 107);
    QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
    QVERIFY(FindTx(*transactionTableModel, txid2).isValid());

    // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
    BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);

    bitdb.Flush(true);
    bitdb.Reset();
}

}

void WalletTests::walletTests()
{
    TestSendCoins();
}
<commit_msg>Fix broken q4 test build<commit_after>#include "wallettests.h"

#include "qt/bitcoinamountfield.h"
#include "qt/callback.h"
#include "qt/optionsmodel.h"
#include "qt/platformstyle.h"
#include "qt/qvalidatedlineedit.h"
#include "qt/sendcoinsdialog.h"
#include "qt/sendcoinsentry.h"
#include "qt/transactiontablemodel.h"
#include "qt/transactionview.h"
#include "qt/walletmodel.h"
#include "test/test_bitcoin.h"
#include "validation.h"
#include "wallet/wallet.h"

#include <QAbstractButton>
#include <QAction>
#include <QApplication>
#include <QCheckBox>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>

namespace
{
//! Press "Ok" button in message box dialog.
void ConfirmMessage(QString* text = nullptr)
{
    QTimer::singleShot(0, makeCallback([text](Callback* callback) {
        for (QWidget* widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("QMessageBox")) {
                QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
                if (text) *text = messageBox->text();
                messageBox->defaultButton()->click();
            }
        }
        delete callback;
    }), SLOT(call()));
}

//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString* text = nullptr, bool cancel = false)
{
    QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
        for (QWidget* widget : QApplication::topLevelWidgets()) {
            if (widget->inherits("SendConfirmationDialog")) {
                SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
                if (text) *text = dialog->text();
                QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
                button->setEnabled(true);
                button->click();
            }
        }
        delete callback;
    }), SLOT(call()));
}

//! Send coins to address and return txid.
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
{
    QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
    SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
    entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
    entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
    sendCoinsDialog.findChild<QFrame*>("frameFee")
        ->findChild<QFrame*>("frameFeeSelection")
        ->findChild<QCheckBox*>("optInRBF")
        ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
    uint256 txid;
    boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
        if (status == CT_NEW) txid = hash;
    }));
    ConfirmSend();
    QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
    return txid;
}

//! Find index of txid in transaction list.
QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
{
    QString hash = QString::fromStdString(txid.ToString());
    int rows = model.rowCount({});
    for (int row = 0; row < rows; ++row) {
        QModelIndex index = model.index(row, 0, {});
        if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
            return index;
        }
    }
    return {};
}

//! Request context menu (call method that is public in qt5, but protected in qt4).
void RequestContextMenu(QWidget* widget)
{
    class Qt4Hack : public QWidget
    {
    public:
        using QWidget::customContextMenuRequested;
    };
    static_cast<Qt4Hack*>(widget)->customContextMenuRequested({});
}

//! Invoke bumpfee on txid and check results.
void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
{
    QTableView* table = view.findChild<QTableView*>("transactionView");
    QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
    QVERIFY2(index.isValid(), "Could not find BumpFee txid");

    // Select row in table, invoke context menu, and make sure bumpfee action is
    // enabled or disabled as expected.
    QAction* action = view.findChild<QAction*>("bumpFeeAction");
    table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
    action->setEnabled(expectDisabled);
    RequestContextMenu(table);
    QCOMPARE(action->isEnabled(), !expectDisabled);

    action->setEnabled(true);
    QString text;
    if (expectError.empty()) {
        ConfirmSend(&text, cancel);
    } else {
        ConfirmMessage(&text);
    }
    action->trigger();
    QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
}

//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
// manually running the event loop, e.g.:
//
//     sendCoinsDialog.show();
//     QEventLoop().exec();
//
// This also requires overriding the default minimal Qt platform:
//
//     src/qt/test/test_bitcoin-qt -platform xcb      # Linux
//     src/qt/test/test_bitcoin-qt -platform windows  # Windows
//     src/qt/test/test_bitcoin-qt -platform cocoa    # macOS
void TestSendCoins()
{
    // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
    TestChain100Setup test;
    for (int i = 0; i < 5; ++i) {
        test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
    }
    bitdb.MakeMock();
    std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
    CWallet wallet(std::move(dbw));
    bool firstRun;
    wallet.LoadWallet(firstRun);
    {
        LOCK(wallet.cs_wallet);
        wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
        wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
    }
    wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
    wallet.SetBroadcastTransactions(true);

    // Create widgets for sending coins and listing transactions.
    std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
    SendCoinsDialog sendCoinsDialog(platformStyle.get());
    TransactionView transactionView(platformStyle.get());
    OptionsModel optionsModel;
    WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
    sendCoinsDialog.setModel(&walletModel);
    transactionView.setModel(&walletModel);

    // Send two transactions, and verify they are added to transaction list.
    TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
    QCOMPARE(transactionTableModel->rowCount({}), 105);
    uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
    uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
    QCOMPARE(transactionTableModel->rowCount({}), 107);
    QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
    QVERIFY(FindTx(*transactionTableModel, txid2).isValid());

    // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
    BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
    BumpFee(transactionView, txid2, false /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);

    bitdb.Flush(true);
    bitdb.Reset();
}

}

void WalletTests::walletTests()
{
    TestSendCoins();
}
<|endoftext|>


<commit_before>#include <vector>

#include <realm/array_integer.hpp>
#include <realm/column.hpp>
#include <realm/impl/destroy_guard.hpp>

using namespace realm;

// Find max and min value, but break search if difference exceeds 'maxdiff' (in which case *min and *max is set to 0)
// Useful for counting-sort functions
template<size_t w>
bool ArrayInteger::minmax(size_t from, size_t to, uint64_t maxdiff, int64_t *min, int64_t *max) const
{
    int64_t min2;
    int64_t max2;
    size_t t;

    max2 = Array::get<w>(from);
    min2 = max2;

    for (t = from + 1; t < to; t++) {
        int64_t v = Array::get<w>(t);
        // Utilizes that range test is only needed if max2 or min2 were changed
        if (v < min2) {
            min2 = v;
            if (uint64_t(max2 - min2) > maxdiff)
                break;
        }
        else if (v > max2) {
            max2 = v;
            if (uint64_t(max2 - min2) > maxdiff)
                break;
        }
    }

    if (t < to) {
        *max = 0;
        *min = 0;
        return false;
    }
    else {
        *max = max2;
        *min = min2;
        return true;
    }
}

std::vector<int64_t> ArrayInteger::to_vector() const
{
    std::vector<int64_t> v;
    const size_t count = size();
    for (size_t t = 0; t < count; ++t)
        v.push_back(Array::get(t));
    return v;
}

MemRef ArrayIntNull::create_array(Type type, bool context_flag, size_t size, value_type value, Allocator& alloc)
{
    int64_t val = value.value_or(0);
    MemRef r = Array::create(type, context_flag, wtype_Bits, size + 1, val, alloc); // Throws
    ArrayIntNull arr(alloc);
    _impl::DestroyGuard<ArrayIntNull> dg(&arr);
    arr.Array::init_from_mem(r);
    if (value) {
        if (arr.m_width == 64) {
            int_fast64_t null_value = val ^ 1; // Just anything different from value.
            arr.Array::set(0, null_value); // Throws
        }
        else {
            arr.Array::set(0, arr.m_ubound); // Throws
        }
    }
    dg.release();
    return r;
}

void ArrayIntNull::init_from_ref(ref_type ref) noexcept
{
    REALM_ASSERT_DEBUG(ref);
    char* header = m_alloc.translate(ref);
    init_from_mem(MemRef{header, ref});
}

void ArrayIntNull::init_from_mem(MemRef mem) noexcept
{
    Array::init_from_mem(mem);

    if (m_size == 0) {
        // This can only happen when mem is being reused from another
        // array (which happens when shrinking the B+tree), so we need
        // to add the "magic" null value to the beginning.

        // Since init_* functions are noexcept, but insert() isn't, we
        // need to ensure that insert() will not allocate.
        REALM_ASSERT(m_capacity != 0);
        Array::insert(0, m_ubound);
    }
}

void ArrayIntNull::init_from_parent() noexcept
{
    init_from_ref(get_ref_from_parent());
}

namespace {
    int64_t next_null_candidate(int64_t previous_candidate) {
        uint64_t x = static_cast<uint64_t>(previous_candidate);
        // Increment by a prime number. This guarantees that we will
        // eventually hit every possible integer in the 2^64 range.
        x += 0xfffffffbULL;
        return util::from_twos_compl<int64_t>(x);
    }
}

int_fast64_t ArrayIntNull::choose_random_null(int64_t incoming)
{
    // We just need any number -- it could have been `rand()`, but
    // random numbers are hard, and we don't want to risk locking mutices
    // or saving state. The top of the stack should be "random enough".
    int64_t candidate = reinterpret_cast<int64_t>(&candidate);

    while (true) {
        candidate = next_null_candidate(candidate);
        if (candidate == incoming) {
            continue;
        }
        if (can_use_as_null(candidate)) {
            return candidate;
        }
    }
}

bool ArrayIntNull::can_use_as_null(int64_t candidate)
{
    return find_first(candidate) == npos;
}

void ArrayIntNull::replace_nulls_with(int64_t new_null)
{
    int64_t old_null = Array::get(0);
    Array::set(0, new_null);
    size_t i = 1;
    while (true) {
        size_t found = Array::find_first(old_null, i);
        if (found < Array::size()) {
            Array::set(found, new_null);
            i = found + 1;
        }
        else {
            break;
        }
    }
}

void ArrayIntNull::avoid_null_collision(int64_t value)
{
    if (m_width == 64) {
        if (value == null_value()) {
            int_fast64_t new_null = choose_random_null(value);
            replace_nulls_with(new_null);
        }
    }
    else {
        if (value < m_lbound || value >= m_ubound) {
            size_t new_width = bit_width(value);
            int64_t new_upper_bound = Array::ubound_for_width(new_width);

            // We're using upper bound as magic NULL value, so we have to check
            // explicitly that the incoming value doesn't happen to be the new
            // NULL value. If it is, we upgrade one step further.
            if (new_width < 64 && value == new_upper_bound) {
                new_width = (new_width == 0 ? 1 : new_width * 2);
                new_upper_bound = Array::ubound_for_width(new_width);
            }

            int64_t new_null;
            if (new_width == 64) {
                // Width will be upgraded to 64, so we need to pick a random NULL.
                new_null = choose_random_null(value);
            }
            else {
                new_null = new_upper_bound;
            }

            replace_nulls_with(new_null); // Expands array
        }
    }
}

void ArrayIntNull::find_all(IntegerColumn* result, value_type value, size_t col_offset, size_t begin, size_t end) const
{
    // FIXME: We can't use the fast Array::find_all here, because it would put the wrong indices
    // in the result column. Since find_all may be invoked many times for different leaves in the
    // B+tree with the same result column, we also can't simply adjust indices after finding them
    // (because then the first indices would be adjusted multiple times for each subsequent leaf)

    if (end == npos) {
        end = size();
    }

    for (size_t i = begin; i < end; ++i) {
        if (get(i) == value) {
            result->add(col_offset + i);
        }
    }
}

void ArrayIntNull::get_chunk(size_t ndx, value_type res[8]) const noexcept
{
    int64_t tmp[8];
    Array::get_chunk(ndx + 1, tmp);
    int64_t null = null_value();
    for (size_t i = 0; i < 8; ++i) {
        res[i] = tmp[i] == null ? util::Optional<int64_t>() : tmp[i];
    }
}

namespace {

// FIXME: Move this logic to BpTree.
struct ArrayIntNullLeafInserter {
    static ref_type leaf_insert(Allocator& alloc, ArrayIntNull& self, size_t ndx, util::Optional<int64_t> value, Array::TreeInsertBase& state)
    {
        size_t leaf_size = self.size();
        REALM_ASSERT_DEBUG(leaf_size <= REALM_MAX_BPNODE_SIZE);
        if (leaf_size < ndx)
            ndx = leaf_size;
        if (REALM_LIKELY(leaf_size < REALM_MAX_BPNODE_SIZE)) {
            self.insert(ndx, value); // Throws
            return 0; // Leaf was not split
        }

        // Split leaf node
        ArrayIntNull new_leaf(alloc);
        new_leaf.create(Array::type_Normal); // Throws
        if (ndx == leaf_size) {
            new_leaf.add(value); // Throws
            state.m_split_offset = ndx;
        }
        else {
            for (size_t i = ndx; i < leaf_size; ++i) {
                new_leaf.add(self.get(i)); // Throws
            }
            self.truncate(ndx); // Throws
            self.add(value); // Throws
            state.m_split_offset = ndx + 1;
        }
        state.m_split_size = leaf_size + 1;
        return new_leaf.get_ref();
    }
};

} // anonymous namespace

ref_type ArrayIntNull::bptree_leaf_insert(size_t ndx, value_type value, Array::TreeInsertBase& state)
{
    return ArrayIntNullLeafInserter::leaf_insert(get_alloc(), *this, ndx, value, state);
}

MemRef ArrayIntNull::slice(size_t offset, size_t size, Allocator& target_alloc) const
{
    // NOTE: It would be nice to consolidate this with Array::slice somehow.

    REALM_ASSERT(is_attached());

    Array slice(target_alloc);
    _impl::DeepArrayDestroyGuard dg(&slice);
    Type type = get_type();
    slice.create(type, m_context_flag); // Throws
    slice.add(null_value());

    size_t begin = offset + 1;
    size_t end   = offset + size + 1;
    for (size_t i = begin; i != end; ++i) {
        int_fast64_t value = Array::get(i);
        slice.add(value); // Throws
    }
    dg.release();
    return slice.get_mem();
}

MemRef ArrayIntNull::slice_and_clone_children(size_t offset, size_t size, Allocator& target_alloc) const
{
    // NOTE: It would be nice to consolidate this with Array::slice_and_clone_children somehow.

    REALM_ASSERT(is_attached());
    REALM_ASSERT(!has_refs());
    return slice(offset, size, target_alloc);
}
<commit_msg>Added FIXME<commit_after>#include <vector>

#include <realm/array_integer.hpp>
#include <realm/column.hpp>
#include <realm/impl/destroy_guard.hpp>

using namespace realm;

// Find max and min value, but break search if difference exceeds 'maxdiff' (in which case *min and *max is set to 0)
// Useful for counting-sort functions
template<size_t w>
bool ArrayInteger::minmax(size_t from, size_t to, uint64_t maxdiff, int64_t *min, int64_t *max) const
{
    int64_t min2;
    int64_t max2;
    size_t t;

    max2 = Array::get<w>(from);
    min2 = max2;

    for (t = from + 1; t < to; t++) {
        int64_t v = Array::get<w>(t);
        // Utilizes that range test is only needed if max2 or min2 were changed
        if (v < min2) {
            min2 = v;
            if (uint64_t(max2 - min2) > maxdiff)
                break;
        }
        else if (v > max2) {
            max2 = v;
            if (uint64_t(max2 - min2) > maxdiff)
                break;
        }
    }

    if (t < to) {
        *max = 0;
        *min = 0;
        return false;
    }
    else {
        *max = max2;
        *min = min2;
        return true;
    }
}

std::vector<int64_t> ArrayInteger::to_vector() const
{
    std::vector<int64_t> v;
    const size_t count = size();
    for (size_t t = 0; t < count; ++t)
        v.push_back(Array::get(t));
    return v;
}

MemRef ArrayIntNull::create_array(Type type, bool context_flag, size_t size, value_type value, Allocator& alloc)
{
    int64_t val = value.value_or(0);
    MemRef r = Array::create(type, context_flag, wtype_Bits, size + 1, val, alloc); // Throws
    ArrayIntNull arr(alloc);
    _impl::DestroyGuard<ArrayIntNull> dg(&arr);
    arr.Array::init_from_mem(r);
    if (value) {
        if (arr.m_width == 64) {
            int_fast64_t null_value = val ^ 1; // Just anything different from value.
            arr.Array::set(0, null_value); // Throws
        }
        else {
            arr.Array::set(0, arr.m_ubound); // Throws
        }
    }
    dg.release();
    return r;
}

void ArrayIntNull::init_from_ref(ref_type ref) noexcept
{
    REALM_ASSERT_DEBUG(ref);
    char* header = m_alloc.translate(ref);
    init_from_mem(MemRef{header, ref});
}

void ArrayIntNull::init_from_mem(MemRef mem) noexcept
{
    Array::init_from_mem(mem);

    if (m_size == 0) {
        // This can only happen when mem is being reused from another
        // array (which happens when shrinking the B+tree), so we need
        // to add the "magic" null value to the beginning.

        // Since init_* functions are noexcept, but insert() isn't, we
        // need to ensure that insert() will not allocate.
        REALM_ASSERT(m_capacity != 0);
        Array::insert(0, m_ubound);
    }
}

void ArrayIntNull::init_from_parent() noexcept
{
    init_from_ref(get_ref_from_parent());
}

namespace {
    int64_t next_null_candidate(int64_t previous_candidate) {
        uint64_t x = static_cast<uint64_t>(previous_candidate);
        // Increment by a prime number. This guarantees that we will
        // eventually hit every possible integer in the 2^64 range.
        x += 0xfffffffbULL;
        return util::from_twos_compl<int64_t>(x);
    }
}

int_fast64_t ArrayIntNull::choose_random_null(int64_t incoming)
{
    // We just need any number -- it could have been `rand()`, but
    // random numbers are hard, and we don't want to risk locking mutices
    // or saving state. The top of the stack should be "random enough".
    int64_t candidate = reinterpret_cast<int64_t>(&candidate);

    while (true) {
        candidate = next_null_candidate(candidate);
        if (candidate == incoming) {
            continue;
        }
        if (can_use_as_null(candidate)) {
            return candidate;
        }
    }
}

bool ArrayIntNull::can_use_as_null(int64_t candidate)
{
    return find_first(candidate) == npos;
}

void ArrayIntNull::replace_nulls_with(int64_t new_null)
{
    int64_t old_null = Array::get(0);
    Array::set(0, new_null);
    size_t i = 1;
    while (true) {
        size_t found = Array::find_first(old_null, i);
        if (found < Array::size()) {
            Array::set(found, new_null);
            i = found + 1;
        }
        else {
            break;
        }
    }
}

void ArrayIntNull::avoid_null_collision(int64_t value)
{
    if (m_width == 64) {
        if (value == null_value()) {
            int_fast64_t new_null = choose_random_null(value);
            replace_nulls_with(new_null);
        }
    }
    else {
        if (value < m_lbound || value >= m_ubound) {
            size_t new_width = bit_width(value);
            int64_t new_upper_bound = Array::ubound_for_width(new_width);

            // We're using upper bound as magic NULL value, so we have to check
            // explicitly that the incoming value doesn't happen to be the new
            // NULL value. If it is, we upgrade one step further.
            if (new_width < 64 && value == new_upper_bound) {
                new_width = (new_width == 0 ? 1 : new_width * 2);
                new_upper_bound = Array::ubound_for_width(new_width);
            }

            int64_t new_null;
            if (new_width == 64) {
                // Width will be upgraded to 64, so we need to pick a random NULL.
                new_null = choose_random_null(value);
            }
            else {
                new_null = new_upper_bound;
            }

            replace_nulls_with(new_null); // Expands array
        }
    }
}

void ArrayIntNull::find_all(IntegerColumn* result, value_type value, size_t col_offset, size_t begin, size_t end) const
{
    // FIXME: We can't use the fast Array::find_all here, because it would put the wrong indices
    // in the result column. Since find_all may be invoked many times for different leaves in the
    // B+tree with the same result column, we also can't simply adjust indices after finding them
    // (because then the first indices would be adjusted multiple times for each subsequent leaf)

    if (end == npos) {
        end = size();
    }

    for (size_t i = begin; i < end; ++i) {
        if (get(i) == value) {
            result->add(col_offset + i);
        }
    }
}

void ArrayIntNull::get_chunk(size_t ndx, value_type res[8]) const noexcept
{
    // FIXME: Optimize this
    int64_t tmp[8];
    Array::get_chunk(ndx + 1, tmp);
    int64_t null = null_value();
    for (size_t i = 0; i < 8; ++i) {
        res[i] = tmp[i] == null ? util::Optional<int64_t>() : tmp[i];
    }
}

namespace {

// FIXME: Move this logic to BpTree.
struct ArrayIntNullLeafInserter {
    static ref_type leaf_insert(Allocator& alloc, ArrayIntNull& self, size_t ndx, util::Optional<int64_t> value, Array::TreeInsertBase& state)
    {
        size_t leaf_size = self.size();
        REALM_ASSERT_DEBUG(leaf_size <= REALM_MAX_BPNODE_SIZE);
        if (leaf_size < ndx)
            ndx = leaf_size;
        if (REALM_LIKELY(leaf_size < REALM_MAX_BPNODE_SIZE)) {
            self.insert(ndx, value); // Throws
            return 0; // Leaf was not split
        }

        // Split leaf node
        ArrayIntNull new_leaf(alloc);
        new_leaf.create(Array::type_Normal); // Throws
        if (ndx == leaf_size) {
            new_leaf.add(value); // Throws
            state.m_split_offset = ndx;
        }
        else {
            for (size_t i = ndx; i < leaf_size; ++i) {
                new_leaf.add(self.get(i)); // Throws
            }
            self.truncate(ndx); // Throws
            self.add(value); // Throws
            state.m_split_offset = ndx + 1;
        }
        state.m_split_size = leaf_size + 1;
        return new_leaf.get_ref();
    }
};

} // anonymous namespace

ref_type ArrayIntNull::bptree_leaf_insert(size_t ndx, value_type value, Array::TreeInsertBase& state)
{
    return ArrayIntNullLeafInserter::leaf_insert(get_alloc(), *this, ndx, value, state);
}

MemRef ArrayIntNull::slice(size_t offset, size_t size, Allocator& target_alloc) const
{
    // NOTE: It would be nice to consolidate this with Array::slice somehow.

    REALM_ASSERT(is_attached());

    Array slice(target_alloc);
    _impl::DeepArrayDestroyGuard dg(&slice);
    Type type = get_type();
    slice.create(type, m_context_flag); // Throws
    slice.add(null_value());

    size_t begin = offset + 1;
    size_t end   = offset + size + 1;
    for (size_t i = begin; i != end; ++i) {
        int_fast64_t value = Array::get(i);
        slice.add(value); // Throws
    }
    dg.release();
    return slice.get_mem();
}

MemRef ArrayIntNull::slice_and_clone_children(size_t offset, size_t size, Allocator& target_alloc) const
{
    // NOTE: It would be nice to consolidate this with Array::slice_and_clone_children somehow.

    REALM_ASSERT(is_attached());
    REALM_ASSERT(!has_refs());
    return slice(offset, size, target_alloc);
}
<|endoftext|>


<commit_before>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */
#include <mtp/ByteArray.h>
#include <mtp/log.h>
#include <sstream>

namespace mtp
{

	void HexDump(const std::string &prefix, const ByteArray &data, bool force)
	{
		if (!g_debug && !force)
			return;

		std::stringstream ss;
		ss << prefix << "[" << data.size() << "]:\n";
		size_t i;
		for(i = 0; i < data.size(); ++i)
		{
			bool first = ((i & 0xf) == 0);
			bool last = ((i & 0xf) == 0x0f);
			if (first)
				ss << hex(i, 8) << ": ";

			ss << hex(data[i], 2);
			if (last)
				ss << "\n";
			else
				ss << " ";
		}
		if (i & 0xf)
			ss << "\n";

		debug(ss.str());
	}
}
<commit_msg>fixed non-working force flag in hexdump<commit_after>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */
#include <mtp/ByteArray.h>
#include <mtp/log.h>
#include <sstream>

namespace mtp
{

	void HexDump(const std::string &prefix, const ByteArray &data, bool force)
	{
		if (!g_debug && !force)
			return;

		std::stringstream ss;
		ss << prefix << "[" << data.size() << "]:\n";
		size_t i;
		for(i = 0; i < data.size(); ++i)
		{
			bool first = ((i & 0xf) == 0);
			bool last = ((i & 0xf) == 0x0f);
			if (first)
				ss << hex(i, 8) << ": ";

			ss << hex(data[i], 2);
			if (last)
				ss << "\n";
			else
				ss << " ";
		}
		if (i & 0xf)
			ss << "\n";

		error(ss.str());
	}
}
<|endoftext|>