<commit_before>/*! @file gradient_descent.cpp
    @brief Implementation of GradientDescent class
*/
#include "gradient_descent.hpp"
#include "genotype.hpp"
#include "util.hpp"

#include <sfmt.hpp>
#include <wtl/exception.hpp>
#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/zfstream.hpp>
#include <wtl/itertools.hpp>
#include <wtl/concurrent.hpp>
#include <wtl/scope.hpp>

#include <boost/filesystem.hpp>

namespace likeligrid {

namespace fs = boost::filesystem;

// std::unique_ptr needs to know GenotypeModel implementation
GradientDescent::~GradientDescent() = default;

GradientDescent::GradientDescent(
    std::istream& ist,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : model_(std::make_unique<GenotypeModel>(ist, max_sites)),
      concurrency_(concurrency)
    {HERE;
    model_->set_epistasis(epistasis_pair, pleiotropy);
}

GradientDescent::GradientDescent(
    const std::string& infile,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : concurrency_(concurrency)
    {HERE;

    std::string genotype_file = infile;
    if (wtl::endswith(infile, ".tsv.gz")) {// previous result
        std::string previous = fs::path(infile).filename().string();
        wtl::izfstream ist(infile);
        size_t prev_max_sites;
        std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);
        std::tie(std::ignore, std::ignore, starting_point_) = read_body(ist);
        std::ostringstream oss;
        oss << "grad-from-s" << prev_max_sites << "-" << previous;
        outfile_ = oss.str();
    } else {
        outfile_ = "grad-from-center.tsv.gz";
    }
    model_ = std::make_unique<GenotypeModel>(genotype_file, max_sites);
    model_->set_epistasis(epistasis_pair, pleiotropy);
}

void GradientDescent::run(std::ostream& ost) {HERE;
    auto at_exit = wtl::scope_exit([&ost,this](){
        std::cerr << "\n" << *const_max_iterator() << std::endl;
        write(ost);
    });

    std::valarray<double> new_start(1.0, model_->names().size());
    std::copy(std::begin(starting_point_), std::end(starting_point_), std::begin(new_start));
    history_.emplace(new_start, model_->calc_loglik(new_start));
    std::cerr << "start: " << *history_.begin() << std::endl;

    for (auto it = max_iterator();
         it != history_.end();
         it = find_better(it)) {
    }
}

struct less_loglik_or_tie_farther {
    bool operator()(const MapGrid::value_type& x, const MapGrid::value_type& y) const {
        if (wtl::approx(x.second, y.second)) {
            return d2_from_neutral(x.first) > d2_from_neutral(y.first);
        } else {
            return x.second < y.second;
        }
    }
};

MapGrid::iterator GradientDescent::find_better(const MapGrid::iterator& prev_it) {
    static wtl::ThreadPool pool(concurrency_);
    auto task = [](GenotypeModel model, const std::valarray<double> theta) {
        // arguments are copied for each thread
        return std::make_pair(theta, model.calc_loglik(theta));
    };
    std::vector<std::future<std::pair<std::valarray<double>, double>>> futures;
    futures.reserve(concurrency_);
    auto better_it = prev_it;
    const auto candidates = empty_neighbors_of(prev_it->first);
    for (const auto& theta: candidates) {
        futures.push_back(pool.submit(task, *model_, theta));
        if ((futures.size() == concurrency_) || (&theta == &candidates.back())) {
            for (auto& ftr: futures) {
                auto result_it = history_.insert(ftr.get()).first;
                std::cerr << "." << std::flush;
                if (less_loglik_or_tie_farther{}(*better_it, *result_it)) {
                    better_it = result_it;
                }
            }
            if (better_it != prev_it) {
                std::cerr << "*" << std::flush;
                return better_it;
            }
            futures.clear();
        }
    }
    return history_.end();
}

std::vector<std::valarray<double>> GradientDescent::empty_neighbors_of(const std::valarray<double>& center) {
    const auto axes = make_vicinity(center, 3, 0.01);
    auto iter = wtl::itertools::product(axes);
    std::vector<std::valarray<double>> empty_neighbors;
    empty_neighbors.reserve(iter.max_count());
    for (const auto& x: iter()) {
        if (history_.find(x) == history_.end()) {
            empty_neighbors.push_back(x);
        }
    }
    std::shuffle(std::begin(empty_neighbors), std::end(empty_neighbors), wtl::sfmt64());
    return empty_neighbors;
}

void GradientDescent::write(std::ostream& ost) {HERE;
    ost << "##genotype_file=" << model_->filename() << "\n";
    ost << "##max_sites=" << model_->max_sites() << "\n";
    ost << "##max_count=" << 0u << "\n";
    ost << "##step=" << 0.01 << "\n";
    ost << "loglik\t";
    wtl::join(model_->names(), ost, "\t") << "\n";
    for (const auto& p: history_) {
        ost << p.second << "\t";
        wtl::join(p.first, ost, "\t") << "\n";
    }
}

std::tuple<std::string, size_t, std::string> GradientDescent::read_results(const std::string& infile) {HERE;
    wtl::izfstream ist(infile);
    std::string genotype_file;
    size_t prev_max_sites;
    std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);

    std::string buffer;
    ist >> buffer; // loglik
    std::getline(ist, buffer); // header
    buffer.erase(0, 1); // \t
    const std::vector<std::string> colnames = wtl::split(buffer, "\t");
    std::string epistasis_name = colnames.back();
    if (epistasis_name.find(':') == std::string::npos) epistasis_name.clear();

    while (std::getline(ist, buffer)) {
        std::istringstream iss(buffer);
        std::istream_iterator<double> it(iss);
        double loglik = *it;
        std::vector<double> vec(++it, std::istream_iterator<double>());
        history_.emplace(std::valarray<double>(vec.data(), vec.size()), loglik);
    }
    return {genotype_file, prev_max_sites, epistasis_name};
}

MapGrid::iterator GradientDescent::max_iterator() {HERE;
    return std::max_element(std::begin(history_), std::end(history_), less_loglik_or_tie_farther());
}

MapGrid::const_iterator GradientDescent::const_max_iterator() const {HERE;
    return std::max_element(std::begin(history_), std::end(history_), less_loglik_or_tie_farther());
}

void GradientDescent::test() {HERE;
    std::stringstream sst;
    sst <<
R"({
  "pathway": ["A", "B"],
  "annotation": ["0011", "1100"],
  "sample": ["0011", "0101", "1001", "0110", "1010", "1100"]
})";
    GradientDescent searcher(sst, 4, {0, 1}, false);
    searcher.run(std::cout);
    std::cout << *searcher.max_iterator() << std::endl;
}

} // namespace likeligrid
<commit_msg>:art: Return explicitly constructed tuple for old compilers<commit_after>/*! @file gradient_descent.cpp
    @brief Implementation of GradientDescent class
*/
#include "gradient_descent.hpp"
#include "genotype.hpp"
#include "util.hpp"

#include <sfmt.hpp>
#include <wtl/exception.hpp>
#include <wtl/debug.hpp>
#include <wtl/iostr.hpp>
#include <wtl/zfstream.hpp>
#include <wtl/itertools.hpp>
#include <wtl/concurrent.hpp>
#include <wtl/scope.hpp>

#include <boost/filesystem.hpp>

namespace likeligrid {

namespace fs = boost::filesystem;

// std::unique_ptr needs to know GenotypeModel implementation
GradientDescent::~GradientDescent() = default;

GradientDescent::GradientDescent(
    std::istream& ist,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : model_(std::make_unique<GenotypeModel>(ist, max_sites)),
      concurrency_(concurrency)
    {HERE;
    model_->set_epistasis(epistasis_pair, pleiotropy);
}

GradientDescent::GradientDescent(
    const std::string& infile,
    const size_t max_sites,
    const std::pair<size_t, size_t>& epistasis_pair,
    const bool pleiotropy,
    const unsigned int concurrency)
    : concurrency_(concurrency)
    {HERE;

    std::string genotype_file = infile;
    if (wtl::endswith(infile, ".tsv.gz")) {// previous result
        std::string previous = fs::path(infile).filename().string();
        wtl::izfstream ist(infile);
        size_t prev_max_sites;
        std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);
        std::tie(std::ignore, std::ignore, starting_point_) = read_body(ist);
        std::ostringstream oss;
        oss << "grad-from-s" << prev_max_sites << "-" << previous;
        outfile_ = oss.str();
    } else {
        outfile_ = "grad-from-center.tsv.gz";
    }
    model_ = std::make_unique<GenotypeModel>(genotype_file, max_sites);
    model_->set_epistasis(epistasis_pair, pleiotropy);
}

void GradientDescent::run(std::ostream& ost) {HERE;
    auto at_exit = wtl::scope_exit([&ost,this](){
        std::cerr << "\n" << *const_max_iterator() << std::endl;
        write(ost);
    });

    std::valarray<double> new_start(1.0, model_->names().size());
    std::copy(std::begin(starting_point_), std::end(starting_point_), std::begin(new_start));
    history_.emplace(new_start, model_->calc_loglik(new_start));
    std::cerr << "start: " << *history_.begin() << std::endl;

    for (auto it = max_iterator();
         it != history_.end();
         it = find_better(it)) {
    }
}

struct less_loglik_or_tie_farther {
    bool operator()(const MapGrid::value_type& x, const MapGrid::value_type& y) const {
        if (wtl::approx(x.second, y.second)) {
            return d2_from_neutral(x.first) > d2_from_neutral(y.first);
        } else {
            return x.second < y.second;
        }
    }
};

MapGrid::iterator GradientDescent::find_better(const MapGrid::iterator& prev_it) {
    static wtl::ThreadPool pool(concurrency_);
    auto task = [](GenotypeModel model, const std::valarray<double> theta) {
        // arguments are copied for each thread
        return std::make_pair(theta, model.calc_loglik(theta));
    };
    std::vector<std::future<std::pair<std::valarray<double>, double>>> futures;
    futures.reserve(concurrency_);
    auto better_it = prev_it;
    const auto candidates = empty_neighbors_of(prev_it->first);
    for (const auto& theta: candidates) {
        futures.push_back(pool.submit(task, *model_, theta));
        if ((futures.size() == concurrency_) || (&theta == &candidates.back())) {
            for (auto& ftr: futures) {
                auto result_it = history_.insert(ftr.get()).first;
                std::cerr << "." << std::flush;
                if (less_loglik_or_tie_farther{}(*better_it, *result_it)) {
                    better_it = result_it;
                }
            }
            if (better_it != prev_it) {
                std::cerr << "*" << std::flush;
                return better_it;
            }
            futures.clear();
        }
    }
    return history_.end();
}

std::vector<std::valarray<double>> GradientDescent::empty_neighbors_of(const std::valarray<double>& center) {
    const auto axes = make_vicinity(center, 3, 0.01);
    auto iter = wtl::itertools::product(axes);
    std::vector<std::valarray<double>> empty_neighbors;
    empty_neighbors.reserve(iter.max_count());
    for (const auto& x: iter()) {
        if (history_.find(x) == history_.end()) {
            empty_neighbors.push_back(x);
        }
    }
    std::shuffle(std::begin(empty_neighbors), std::end(empty_neighbors), wtl::sfmt64());
    return empty_neighbors;
}

void GradientDescent::write(std::ostream& ost) {HERE;
    ost << "##genotype_file=" << model_->filename() << "\n";
    ost << "##max_sites=" << model_->max_sites() << "\n";
    ost << "##max_count=" << 0u << "\n";
    ost << "##step=" << 0.01 << "\n";
    ost << "loglik\t";
    wtl::join(model_->names(), ost, "\t") << "\n";
    for (const auto& p: history_) {
        ost << p.second << "\t";
        wtl::join(p.first, ost, "\t") << "\n";
    }
}

std::tuple<std::string, size_t, std::string> GradientDescent::read_results(const std::string& infile) {HERE;
    wtl::izfstream ist(infile);
    std::string genotype_file;
    size_t prev_max_sites;
    std::tie(genotype_file, prev_max_sites, std::ignore, std::ignore) = read_metadata(ist);

    std::string buffer;
    ist >> buffer; // loglik
    std::getline(ist, buffer); // header
    buffer.erase(0, 1); // \t
    const std::vector<std::string> colnames = wtl::split(buffer, "\t");
    std::string epistasis_name = colnames.back();
    if (epistasis_name.find(':') == std::string::npos) epistasis_name.clear();

    while (std::getline(ist, buffer)) {
        std::istringstream iss(buffer);
        std::istream_iterator<double> it(iss);
        double loglik = *it;
        std::vector<double> vec(++it, std::istream_iterator<double>());
        history_.emplace(std::valarray<double>(vec.data(), vec.size()), loglik);
    }
    return std::tuple<std::string, size_t, std::string>{genotype_file, prev_max_sites, epistasis_name};
}

MapGrid::iterator GradientDescent::max_iterator() {HERE;
    return std::max_element(std::begin(history_), std::end(history_), less_loglik_or_tie_farther());
}

MapGrid::const_iterator GradientDescent::const_max_iterator() const {HERE;
    return std::max_element(std::begin(history_), std::end(history_), less_loglik_or_tie_farther());
}

void GradientDescent::test() {HERE;
    std::stringstream sst;
    sst <<
R"({
  "pathway": ["A", "B"],
  "annotation": ["0011", "1100"],
  "sample": ["0011", "0101", "1001", "0110", "1010", "1100"]
})";
    GradientDescent searcher(sst, 4, {0, 1}, false);
    searcher.run(std::cout);
    std::cout << *searcher.max_iterator() << std::endl;
}

} // namespace likeligrid
<|endoftext|>


<commit_before>#include "texture.hpp"
#include "dummytexture.hpp"
#include "SDL_opengl.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>

Texture::Texture()
    : buf_(0), bufsz_(0),
      width_(0), height_(0), twidth_(0), theight_(0),
      iscolor_(false), hasalpha_(false),
      refcount_(0), tex_(0), loaded_(false), registered_(false)
{ }

Texture::~Texture()
{
    free(buf_);
}

static std::vector<Texture *> textures;

void Texture::updateAll()
{
    std::vector<Texture *>::iterator
        b = textures.begin(), i = b, e = textures.end();
    try {
        while (i != e) {
            Texture *t = *i;
            if (t->refcount_ > 0) {
                if (!t->loaded_)
                    t->loadTex();
                ++i;
            } else {
                t->unloadTex();
                delete t;
                --e;
                if (i != e)
                    *i = *e;
            }
        }
    } catch (...) {
        textures.resize(e - b);
        throw;
    }
    textures.resize(e - b);
}

void Texture::registerTexture()
{
    if (registered_)
        return;
    textures.push_back(this);
    registered_ = true;
}

void Texture::loadTex()
{
    if (loaded_)
        return;
    if (tex_)
        fprintf(stderr, "Reloading texture %s\n", name().c_str());
    else
        fprintf(stderr, "Loading texture %s\n", name().c_str());
    bool success = false;
    success = load();
    if (success) {
        GLuint tex = 0;
        if (tex_ && !isnull_)
            tex = tex_;
        else
            glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GLint fmt;
        if (iscolor_)
            fmt = hasalpha_ ? GL_RGBA : GL_RGB;
        else
            fmt = hasalpha_ ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
        glTexImage2D(GL_TEXTURE_2D, 0, fmt, twidth_, theight_, 0,
                     fmt, GL_UNSIGNED_BYTE, buf_);
        tex_ = tex;
        loaded_ = true;
        isnull_ = false;
    } else {
        fprintf(stderr, "    failed\n");
        unloadTex();
        // Make sure to set loaded_ true before checking if the dummy
        // texture is loaded, because this might be the dummy texture.
        loaded_ = true;
        isnull_ = true;
        Texture &t = DummyTexture::nullTexture;
        if (!t.loaded_)
            t.loadTex();
        tex_ = t.tex_;
    }
}

void Texture::unloadTex()
{
    if (tex_ != 0 && !isnull_) {
        fprintf(stderr, "Unloading texture %s\n", name().c_str());
        GLuint tex = tex_;
        glDeleteTextures(1, &tex);
    }
    tex_ = 0;
    loaded_ = false;
    isnull_ = false;
}

unsigned int
round_up_pow2(unsigned int x)
{
    x -= 1;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x += 1;
    return x;
}

void Texture::alloc(unsigned int width, unsigned int height,
                    bool iscolor, bool hasalpha)
{
    // FIXME overflow, error handling
    unsigned int
        twidth = round_up_pow2(width), theight = round_up_pow2(height),
        chan = (iscolor ? 3 : 1) + (hasalpha ? 1 : 0),
        rb = (twidth * chan + 3) & ~3;
    size_t sz = (size_t)rb * height;
    if (bufsz_ != sz) {
        void *buf = malloc(sz);
        if (!buf) throw std::bad_alloc();
        if (buf_) free(buf);
        buf_ = buf;
        bufsz_ = sz;
    }
    width_ = width;
    height_ = height;
    twidth_ = twidth;
    theight_ = theight;
    iscolor_ = iscolor;
    hasalpha_ = hasalpha;
}
<commit_msg>Fixed memory error / dangling pointer.<commit_after>#include "texture.hpp"
#include "dummytexture.hpp"
#include "SDL_opengl.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>

Texture::Texture()
    : buf_(0), bufsz_(0),
      width_(0), height_(0), twidth_(0), theight_(0),
      iscolor_(false), hasalpha_(false),
      refcount_(0), tex_(0), loaded_(false), registered_(false)
{ }

Texture::~Texture()
{
    free(buf_);
}

static std::vector<Texture *> textures;

void Texture::updateAll()
{
    std::vector<Texture *>::iterator
        b = textures.begin(), i = b, e = textures.end();
    try {
        while (i != e) {
            Texture *t = *i;
            if (t->refcount_ > 0) {
                if (!t->loaded_)
                    t->loadTex();
                ++i;
            } else {
                t->unloadTex();
                delete t;
                --e;
                if (i != e)
                    *i = *e;
            }
        }
    } catch (...) {
        textures.resize(e - b);
        throw;
    }
    textures.resize(e - b);
}

void Texture::registerTexture()
{
    if (registered_)
        return;
    textures.push_back(this);
    registered_ = true;
}

void Texture::loadTex()
{
    if (loaded_)
        return;
    if (tex_)
        fprintf(stderr, "Reloading texture %s\n", name().c_str());
    else
        fprintf(stderr, "Loading texture %s\n", name().c_str());
    bool success = false;
    success = load();
    if (success) {
        GLuint tex = 0;
        if (tex_ && !isnull_)
            tex = tex_;
        else
            glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        GLint fmt;
        if (iscolor_)
            fmt = hasalpha_ ? GL_RGBA : GL_RGB;
        else
            fmt = hasalpha_ ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
        glTexImage2D(GL_TEXTURE_2D, 0, fmt, twidth_, theight_, 0,
                     fmt, GL_UNSIGNED_BYTE, buf_);
        tex_ = tex;
        loaded_ = true;
        isnull_ = false;
    } else {
        fprintf(stderr, "    failed\n");
        unloadTex();
        // Make sure to set loaded_ true before checking if the dummy
        // texture is loaded, because this might be the dummy texture.
        loaded_ = true;
        isnull_ = true;
        Texture &t = DummyTexture::nullTexture;
        if (!t.loaded_)
            t.loadTex();
        tex_ = t.tex_;
    }
}

void Texture::unloadTex()
{
    if (tex_ != 0 && !isnull_) {
        fprintf(stderr, "Unloading texture %s\n", name().c_str());
        GLuint tex = tex_;
        glDeleteTextures(1, &tex);
    }
    tex_ = 0;
    loaded_ = false;
    isnull_ = false;
}

unsigned int
round_up_pow2(unsigned int x)
{
    x -= 1;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x += 1;
    return x;
}

void Texture::alloc(unsigned int width, unsigned int height,
                    bool iscolor, bool hasalpha)
{
    // FIXME overflow, error handling
    unsigned int
        twidth = round_up_pow2(width), theight = round_up_pow2(height),
        chan = (iscolor ? 3 : 1) + (hasalpha ? 1 : 0),
        rb = (twidth * chan + 3) & ~3;
    size_t sz = (size_t)rb * height;
    if (bufsz_ != sz) {
        void *buf = malloc(sz);
        if (!buf) throw std::bad_alloc();
        if (buf_) free(buf_);
        buf_ = buf;
        bufsz_ = sz;
    }
    width_ = width;
    height_ = height;
    twidth_ = twidth;
    theight_ = theight;
    iscolor_ = iscolor;
    hasalpha_ = hasalpha;
}
<|endoftext|>


<commit_before>#include <gsCore/gsTemplateTools.h>

#include <gsUtils/gsNorms.h>
#include <gsUtils/gsNorms.hpp>

#define T real_t
#define uZ unsigned
#define Z int

namespace gismo
{

///////////////////////////////////////////////////////////////////
////// Norm & distance computation
///////////////////////////////////////////////////////////////////

TEMPLATE_INST
T computeL2Norm<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, int numEvals);

TEMPLATE_INST
T computeL2Norm<T>(const gsField<T>& u, int numSamples);

TEMPLATE_INST
T computeL2Distance<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, const gsFunction<T>& v, bool isParametrized_v, int numEvals);

TEMPLATE_INST
T computeL2Distance<T>(const gsField<T>& u, const gsFunction<T>& v, bool isParametrized_v, int numEvals);

TEMPLATE_INST
T computeL2Distance<T>(const gsField<T>& u, const gsField<T>& v, int numEvals);

TEMPLATE_INST
T igaFieldL2Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
                     bool v_isParam);

TEMPLATE_INST
T igaFieldL2Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
		     const gsMultiBasis<T>& B,
                     bool v_isParam);

TEMPLATE_INST
T igaL2Distance(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
T igaL2Distance(const gsGeometry<T>& patch,
                const gsFunction<T>& func,
                const gsFunction<T>& v,
		const gsBasis<T>& B,
                bool v_isParam);

TEMPLATE_INST
gsVector< gsMatrix<T> > igaFieldL2DistanceEltWiseSq(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

TEMPLATE_INST
gsMatrix<T> igaL2DistanceEltWiseSq(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
T igaL2DistanceOnElt( const std::auto_ptr< gsGeometryEvaluator<T> > & geoEval ,
                      const std::auto_ptr< gsGeometryEvaluator<T> > & funcEval,
                      const gsFunction<T>& v,
                      const bool & v_isParam,
                      const gsBasis<T>::domainIter & domIt);

TEMPLATE_INST
T igaH1Distance(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
gsMatrix<T> igaH1DistanceEltWiseSq(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam );

TEMPLATE_INST
T igaFieldH1Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
                     bool v_isParam);

TEMPLATE_INST
T igaH1DistanceOnElt( const std::auto_ptr< gsGeometryEvaluator<T> > & geoEval ,
                      const std::auto_ptr< gsGeometryEvaluator<T> > & funcEval,
                      const gsFunction<T>& v,
                      const bool & v_isParam,
                      const gsBasis<T>::domainIter & domIt,
                      const int d);

TEMPLATE_INST
gsVector< gsMatrix<T> > igaFieldH1DistanceEltWiseSq(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsFunction<T>& f, const gsVector<T>& lower, const gsVector<T>& upper, int numSamples);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, int numSamples);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsField<T>& u, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsFunction<T>& f1, const gsFunction<T>& f2, const gsVector<T>& lower, const gsVector<T>& upper, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, const gsFunction<T>& v, bool isParametrized_v, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsField<T>& u, const gsFunction<T>& v, bool isParametrized_v, int numSamples);

TEMPLATE_INST
T igaDGDistanceJump(const gsGeometry<T>& patch1, const gsGeometry<T>& patch2, const gsGeometry<T>& func1,  const gsGeometry<T>& func2,
                    const gsFunction<T>& v1, const gsFunction<T>& v2, const boundaryInterface & bi, const T mu, bool v_isParam);

TEMPLATE_INST
T igaFieldDGDistance(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

} // namespace gismo

#undef T
#undef uZ
#undef Z
<commit_msg>add some norm features, small updates<commit_after>#include <gsCore/gsTemplateTools.h>

#include <gsUtils/gsNorms.h>
#include <gsUtils/gsNorms.hpp>

#define T real_t
#define uZ unsigned
#define Z int

namespace gismo
{

///////////////////////////////////////////////////////////////////
////// Norm & distance computation
///////////////////////////////////////////////////////////////////

TEMPLATE_INST
T computeL2Norm<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, int numEvals);

TEMPLATE_INST
T computeL2Norm<T>(const gsField<T>& u, int numSamples);

TEMPLATE_INST
T computeL2Distance<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, const gsFunction<T>& v, bool isParametrized_v, int numEvals);

TEMPLATE_INST
T computeL2Distance<T>(const gsField<T>& u, const gsFunction<T>& v, bool isParametrized_v, int numEvals);

TEMPLATE_INST
T computeL2Distance<T>(const gsField<T>& u, const gsField<T>& v, int numEvals);

TEMPLATE_INST
T igaFieldL2Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
                     bool v_isParam);

TEMPLATE_INST
T igaFieldL2Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
		     const gsMultiBasis<T>& B,
                     bool v_isParam);

TEMPLATE_INST
T igaL2Distance(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
T igaL2Distance(const gsGeometry<T>& patch,
                const gsFunction<T>& func,
                const gsFunction<T>& v,
		const gsBasis<T>& B,
                bool v_isParam);

TEMPLATE_INST
gsVector< gsMatrix<T> > igaFieldL2DistanceEltWiseSq(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

TEMPLATE_INST
gsMatrix<T> igaL2DistanceEltWiseSq(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
T igaL2DistanceOnElt( const std::auto_ptr< gsGeometryEvaluator<T> > & geoEval ,
                      const std::auto_ptr< gsGeometryEvaluator<T> > & funcEval,
                      const gsFunction<T>& v,
                      const bool & v_isParam,
                      const gsBasis<T>::domainIter & domIt);

TEMPLATE_INST
T igaH1Distance(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam);

TEMPLATE_INST
T igaFieldH1Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
                     const gsMultiBasis<T>& B,
                     bool v_isParam);
TEMPLATE_INST
T igaH1Distance(const gsGeometry<T>& patch,
                const gsFunction<T>& func,
                const gsFunction<T>& v,
                const gsBasis<T>& B,
                bool v_isParam);
TEMPLATE_INST
T igaH1DistanceOnElt( const std::auto_ptr< gsGeometryEvaluator<T> > & geoEval ,
                      const gsFunction<T> & func,
                      const gsFunction<T>& v,
                      const bool & v_isParam,
                      const typename gsBasis<T>::domainIter & domIt);

TEMPLATE_INST
gsMatrix<T> igaH1DistanceEltWiseSq(const gsGeometry<T>& patch,
                const gsGeometry<T>& func,
                const gsFunction<T>& v,
                bool v_isParam );

TEMPLATE_INST
T igaFieldH1Distance(const gsField<T>& u,
                     const gsFunction<T>& v,
                     bool v_isParam);

TEMPLATE_INST
T igaH1DistanceOnElt( const std::auto_ptr< gsGeometryEvaluator<T> > & geoEval ,
                      const std::auto_ptr< gsGeometryEvaluator<T> > & funcEval,
                      const gsFunction<T>& v,
                      const bool & v_isParam,
                      const gsBasis<T>::domainIter & domIt,
                      const int d);

TEMPLATE_INST
gsVector< gsMatrix<T> > igaFieldH1DistanceEltWiseSq(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsFunction<T>& f, const gsVector<T>& lower, const gsVector<T>& upper, int numSamples);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, int numSamples);

TEMPLATE_INST
T computeMaximumNorm<T>(const gsField<T>& u, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsFunction<T>& f1, const gsFunction<T>& f2, const gsVector<T>& lower, const gsVector<T>& upper, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsGeometry<T>& geo, const gsFunction<T>& u, bool isParametrized_u, const gsFunction<T>& v, bool isParametrized_v, int numSamples);

TEMPLATE_INST
T computeMaximumDistance<T>(const gsField<T>& u, const gsFunction<T>& v, bool isParametrized_v, int numSamples);

TEMPLATE_INST
T igaDGDistanceJump(const gsGeometry<T>& patch1, const gsGeometry<T>& patch2, const gsGeometry<T>& func1,  const gsGeometry<T>& func2,
                    const gsFunction<T>& v1, const gsFunction<T>& v2, const boundaryInterface & bi, const T mu, bool v_isParam);

TEMPLATE_INST
T igaFieldDGDistance(const gsField<T>& u, const gsFunction<T>& v, bool v_isParam);

} // namespace gismo

#undef T
#undef uZ
#undef Z
<|endoftext|>


<commit_before>#ifndef DEDICATED_ONLY

#include "CViewport.h"

#include "gusgame.h"
#include "sound/sfx.h"
#include "gfx.h"
#include "gusanos/allegro.h"
#include "game/CWorm.h"
#include "game/WormInputHandler.h"
#include "CWormHuman.h"
#include "LuaCallbacks.h"
#include "lua/bindings-gfx.h"
#include "blitters/blitters.h"
#include "culling.h"
#include "game/CMap.h"
#include "game/Game.h"
#include "FlagInfo.h"
#include <list>

#include "sprite_set.h" // TEMP
#include "sprite.h" // TEMP
#include "CGameScript.h"

#include <iostream>

LuaReference CViewport::metaTable;

using namespace std;

void CViewport::gusInit()
{
	dest = 0;
	fadeBuffer = 0;
}

void CViewport::gusReset()
{
	destroy_bitmap(dest); dest = 0;
	destroy_bitmap(fadeBuffer); fadeBuffer = 0;
}

struct TestCuller : public Culler<TestCuller>
{
	TestCuller(ALLEGRO_BITMAP* dest_, ALLEGRO_BITMAP* src_, int scrOffX_, int scrOffY_, int destOffX_, int destOffY_, Rect const& rect)
			: Culler<TestCuller>(rect), dest(dest_), src(src_),
			scrOffX(scrOffX_), scrOffY(scrOffY_), destOffX(destOffX_), destOffY(destOffY_)
	{
	}

	bool block(int x, int y)
	{
		return !game.gameMap()->unsafeGetMaterial(x, y).worm_pass;
	}

	void line(int y, int x1, int x2)
	{
		//hline_add(dest, x1 + scrOffX, y + scrOffY, x2 + scrOffX + 1, makecol(50, 50, 50), 255);

		drawSpriteLine_add(
		    dest,
		    src,
		    x1 + scrOffX,
		    y + scrOffY,
		    x1 + destOffX,
		    y + destOffY,
		    x2 + destOffX + 1,
		    255);
	}

	ALLEGRO_BITMAP* dest;
	ALLEGRO_BITMAP* src;

	int scrOffX;
	int scrOffY;
	int destOffX;
	int destOffY;
};

static ALLEGRO_BITMAP* testLight = 0;

void CViewport::setDestination(int width, int height)
{
	destroy_bitmap(dest);
	dest = create_bitmap(width, height);

	destroy_bitmap(fadeBuffer);
	fadeBuffer = create_bitmap_ex(8, width, height);

	if(!testLight) {
		static const int s = 500;
		destroy_bitmap(testLight);
		testLight = create_bitmap_ex(8, s, s);

		for(int y = 0; y < s; ++y)
			for(int x = 0; x < s; ++x) {
				double v = 1.0*(double(s)/2 - (IVec(x, y) - IVec(s/2, s/2)).length());
				if(v < 0.0)
					v = 0.0;
				int iv = int(v);
				putpixel_solid(testLight, x, y, iv);
			}
	}
}

void CViewport::drawLight(IVec const& v)
{
	IVec off(Left,Top);
	IVec loff(v - IVec(testLight->w/2, testLight->h/2));

	Rect r(0, 0, game.gameMap()->GetWidth()*2 - 1, game.gameMap()->GetHeight()*2 - 1);
	r &= Rect(testLight) + loff;

	TestCuller testCuller(fadeBuffer, testLight, -off.x, -off.y, -loff.x, -loff.y, r);

	testCuller.cullOmni(v.x, v.y);
}

void CViewport::gusRender(SDL_Surface* bmpDest)
{
	{
		int destw = Width*2;
		int desth = Height*2;
		bool needDestReset = false;
		if(!dest || !fadeBuffer || !testLight)
			needDestReset = true;
		else if(dest->w != destw || dest->h != desth )
			needDestReset = true;

		if(needDestReset)
			setDestination(destw, desth);
	}

	int offX = static_cast<int>(WorldX);
	int offY = static_cast<int>(WorldY);

	game.gameMap()->gusDraw(dest, offX, offY);

	if ( game.isLevelDarkMode() && game.gameMap()->lightmap )
		blit( game.gameMap()->lightmap, fadeBuffer, offX*2,offY*2, 0, 0, fadeBuffer->w, fadeBuffer->h );

	if (game.state == Game::S_Playing)  {
		// for this scope as a small hack ...
		SDL_Surface* bmpDest = dest->surf.get();
		CViewport _v;
		_v.Height = this->Height;
		_v.Width = this->Width;
		_v.VirtHeight = this->VirtHeight;
		_v.VirtWidth = this->VirtWidth;
		_v.WorldX = this->WorldX;
		_v.WorldY = this->WorldY;
		CViewport* v = &_v;

		// update the drawing position
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->UpdateDrawPos();

		if( tLXOptions->bShadows ) {
			// Draw the projectile shadows
			cClient->DrawProjectileShadows(bmpDest, v);

			// Draw the worm shadows
			for_each_iterator(CWorm*, w, game.aliveWorms())
				w->get()->DrawShadow(bmpDest, v);
		}

		// Draw the entities
		DrawEntities(bmpDest, v);

		// Draw the projectiles
		cClient->DrawProjectiles(bmpDest, v);

		// Draw the bonuses
		cClient->DrawBonuses(bmpDest, v);

		// draw unattached flags and flag spawnpoints
		cClient->flagInfo()->draw(bmpDest, v);

		// draw worms
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->Draw(bmpDest, v);

		for ( Grid::iterator iter = game.objects.beginAll(); iter; ++iter)
			iter->draw(this);
	}

	if(game.isLevelDarkMode())
		drawSprite_mult_8(dest, fadeBuffer, 0, 0);

	// only use the player/worm specific drawings in gus mods
	if(game.gameScript()->gusEngineUsed()) {
		CWormInputHandler* player = pcTargetWorm ? pcTargetWorm->inputHandler() : NULL;

		// Note that we only process worms in the Lua callbacks which have a player set.
		// Most Lua code depends on this assumption so it would break otherwise.

		for(vector<CWormInputHandler*>::iterator playerIter = game.players.begin(); playerIter != game.players.end(); ++playerIter) {
			CWorm* worm = (*playerIter)->getWorm();
			if( worm && worm->isActive() && worm->inputHandler() ) {
				IVec renderPos( worm->getRenderPos() );
				int x = renderPos.x - offX;
				int y = renderPos.y - offY;
				LuaReferenceLazy ownerRef;

				if ( player )
					ownerRef = player->getLuaReference();

				LUACALLBACK(wormRender).call()((lua_Number)x)((lua_Number)y)(worm->getLuaReference())(getLuaReference())(ownerRef)();
			}
		}

		// draw viewport specific stuff only for human worms
		if(pcTargetWorm && dynamic_cast<CWormHumanInputHandler*>(pcTargetWorm->inputHandler()) != NULL) {
			LUACALLBACK(viewportRender).call()(getLuaReference())(pcTargetWorm->getLuaReference())();
		}
	}

	DrawImage(bmpDest, dest->surf, this->GetLeft()/2, this->GetTop()/2);
}

#endif
<commit_msg>let the gus objects decides themself wether they want to be drawn or not<commit_after>#ifndef DEDICATED_ONLY

#include "CViewport.h"

#include "gusgame.h"
#include "sound/sfx.h"
#include "gfx.h"
#include "gusanos/allegro.h"
#include "game/CWorm.h"
#include "game/WormInputHandler.h"
#include "CWormHuman.h"
#include "LuaCallbacks.h"
#include "lua/bindings-gfx.h"
#include "blitters/blitters.h"
#include "culling.h"
#include "game/CMap.h"
#include "game/Game.h"
#include "FlagInfo.h"
#include <list>

#include "sprite_set.h" // TEMP
#include "sprite.h" // TEMP
#include "CGameScript.h"

#include <iostream>

LuaReference CViewport::metaTable;

using namespace std;

void CViewport::gusInit()
{
	dest = 0;
	fadeBuffer = 0;
}

void CViewport::gusReset()
{
	destroy_bitmap(dest); dest = 0;
	destroy_bitmap(fadeBuffer); fadeBuffer = 0;
}

struct TestCuller : public Culler<TestCuller>
{
	TestCuller(ALLEGRO_BITMAP* dest_, ALLEGRO_BITMAP* src_, int scrOffX_, int scrOffY_, int destOffX_, int destOffY_, Rect const& rect)
			: Culler<TestCuller>(rect), dest(dest_), src(src_),
			scrOffX(scrOffX_), scrOffY(scrOffY_), destOffX(destOffX_), destOffY(destOffY_)
	{
	}

	bool block(int x, int y)
	{
		return !game.gameMap()->unsafeGetMaterial(x, y).worm_pass;
	}

	void line(int y, int x1, int x2)
	{
		//hline_add(dest, x1 + scrOffX, y + scrOffY, x2 + scrOffX + 1, makecol(50, 50, 50), 255);

		drawSpriteLine_add(
		    dest,
		    src,
		    x1 + scrOffX,
		    y + scrOffY,
		    x1 + destOffX,
		    y + destOffY,
		    x2 + destOffX + 1,
		    255);
	}

	ALLEGRO_BITMAP* dest;
	ALLEGRO_BITMAP* src;

	int scrOffX;
	int scrOffY;
	int destOffX;
	int destOffY;
};

static ALLEGRO_BITMAP* testLight = 0;

void CViewport::setDestination(int width, int height)
{
	destroy_bitmap(dest);
	dest = create_bitmap(width, height);

	destroy_bitmap(fadeBuffer);
	fadeBuffer = create_bitmap_ex(8, width, height);

	if(!testLight) {
		static const int s = 500;
		destroy_bitmap(testLight);
		testLight = create_bitmap_ex(8, s, s);

		for(int y = 0; y < s; ++y)
			for(int x = 0; x < s; ++x) {
				double v = 1.0*(double(s)/2 - (IVec(x, y) - IVec(s/2, s/2)).length());
				if(v < 0.0)
					v = 0.0;
				int iv = int(v);
				putpixel_solid(testLight, x, y, iv);
			}
	}
}

void CViewport::drawLight(IVec const& v)
{
	IVec off(Left,Top);
	IVec loff(v - IVec(testLight->w/2, testLight->h/2));

	Rect r(0, 0, game.gameMap()->GetWidth()*2 - 1, game.gameMap()->GetHeight()*2 - 1);
	r &= Rect(testLight) + loff;

	TestCuller testCuller(fadeBuffer, testLight, -off.x, -off.y, -loff.x, -loff.y, r);

	testCuller.cullOmni(v.x, v.y);
}

void CViewport::gusRender(SDL_Surface* bmpDest)
{
	{
		int destw = Width*2;
		int desth = Height*2;
		bool needDestReset = false;
		if(!dest || !fadeBuffer || !testLight)
			needDestReset = true;
		else if(dest->w != destw || dest->h != desth )
			needDestReset = true;

		if(needDestReset)
			setDestination(destw, desth);
	}

	int offX = static_cast<int>(WorldX);
	int offY = static_cast<int>(WorldY);

	game.gameMap()->gusDraw(dest, offX, offY);

	if ( game.isLevelDarkMode() && game.gameMap()->lightmap )
		blit( game.gameMap()->lightmap, fadeBuffer, offX*2,offY*2, 0, 0, fadeBuffer->w, fadeBuffer->h );

	if (game.state == Game::S_Playing)  {
		// for this scope as a small hack ...
		SDL_Surface* bmpDest = dest->surf.get();
		CViewport _v;
		_v.Height = this->Height;
		_v.Width = this->Width;
		_v.VirtHeight = this->VirtHeight;
		_v.VirtWidth = this->VirtWidth;
		_v.WorldX = this->WorldX;
		_v.WorldY = this->WorldY;
		CViewport* v = &_v;

		// update the drawing position
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->UpdateDrawPos();

		if( tLXOptions->bShadows ) {
			// Draw the projectile shadows
			cClient->DrawProjectileShadows(bmpDest, v);

			// Draw the worm shadows
			for_each_iterator(CWorm*, w, game.aliveWorms())
				w->get()->DrawShadow(bmpDest, v);
		}

		// Draw the entities
		DrawEntities(bmpDest, v);

		// Draw the projectiles
		cClient->DrawProjectiles(bmpDest, v);

		// Draw the bonuses
		cClient->DrawBonuses(bmpDest, v);

		// draw unattached flags and flag spawnpoints
		cClient->flagInfo()->draw(bmpDest, v);

		// draw worms
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->Draw(bmpDest, v);
	}

	for ( Grid::iterator iter = game.objects.beginAll(); iter; ++iter)
		iter->draw(this);

	if(game.isLevelDarkMode())
		drawSprite_mult_8(dest, fadeBuffer, 0, 0);

	// only use the player/worm specific drawings in gus mods
	if(game.gameScript()->gusEngineUsed()) {
		CWormInputHandler* player = pcTargetWorm ? pcTargetWorm->inputHandler() : NULL;

		// Note that we only process worms in the Lua callbacks which have a player set.
		// Most Lua code depends on this assumption so it would break otherwise.

		for(vector<CWormInputHandler*>::iterator playerIter = game.players.begin(); playerIter != game.players.end(); ++playerIter) {
			CWorm* worm = (*playerIter)->getWorm();
			if( worm && worm->isActive() && worm->inputHandler() ) {
				IVec renderPos( worm->getRenderPos() );
				int x = renderPos.x - offX;
				int y = renderPos.y - offY;
				LuaReferenceLazy ownerRef;

				if ( player )
					ownerRef = player->getLuaReference();

				LUACALLBACK(wormRender).call()((lua_Number)x)((lua_Number)y)(worm->getLuaReference())(getLuaReference())(ownerRef)();
			}
		}

		// draw viewport specific stuff only for human worms
		if(pcTargetWorm && dynamic_cast<CWormHumanInputHandler*>(pcTargetWorm->inputHandler()) != NULL) {
			LUACALLBACK(viewportRender).call()(getLuaReference())(pcTargetWorm->getLuaReference())();
		}
	}

	DrawImage(bmpDest, dest->surf, this->GetLeft()/2, this->GetTop()/2);
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// Google Log
#include <glog/logging.h>

// HyperDex
#include <hyperdex/searches.h>

hyperdex :: searches :: searches(datalayer* data, logical* comm)
    : m_data(data)
    , m_comm(comm)
    , m_searches(16)
{
}

hyperdex :: searches :: ~searches() throw ()
{
}

void
hyperdex :: searches :: start(const entityid& client,
                              uint32_t nonce,
                              const regionid& r,
                              const search& s)
{
    std::pair<entityid, uint32_t> key(client, nonce);

    if (m_searches.contains(key))
    {
        return;
    }

    e::intrusive_ptr<region::snapshot> snap = m_data->make_snapshot(r);
    e::intrusive_ptr<search_state> state = new search_state(r, s, snap);
    m_searches.insert(key, state);
    next(client, nonce);
}

void
hyperdex :: searches :: next(const entityid& client,
                             uint32_t nonce)
{
    e::intrusive_ptr<search_state> state;

    if (!m_searches.lookup(std::make_pair(client, nonce), &state))
    {
        return;
    }

    po6::threads::mutex::hold hold(&state->lock);

    while (state->snap->valid())
    {
        if ((state->point & state->mask) == (state->snap->secondary_point() & state->mask))
        {
            e::buffer key(state->snap->key());
            std::vector<e::buffer> value(state->snap->value());

            if (state->terms.matches(key, value))
            {
                e::buffer msg;
                msg.pack() << nonce << state-> count << key << value;
                m_comm->send(state->region, client, stream_no::SEARCH_ITEM, msg);
                ++state->count;
                return;
            }
        }

        state->snap->next();
    }

    e::buffer msg;
    m_comm->send(state->region, client, stream_no::SEARCH_DONE, msg);
    ++state->count;
    stop(client, nonce);
}

void
hyperdex :: searches :: stop(const entityid& client,
                             uint32_t nonce)
{
    m_searches.remove(std::make_pair(client, nonce));
}

uint64_t
hyperdex :: searches :: hash(const std::pair<entityid, uint32_t>& key)
{
    return key.first.hash() + key.second;
}

hyperdex :: searches :: search_state :: search_state(const regionid& r,
                                                     const search& t,
                                                     e::intrusive_ptr<region::snapshot> s)
    : lock()
    , region(r)
    , point(t.secondary_point())
    , mask(t.secondary_mask())
    , terms(t)
    , snap(s)
    , count(0)
    , m_ref(0)
{
}

hyperdex :: searches :: search_state :: ~search_state() throw ()
{
}
<commit_msg>Use the search object from 063fe8ff...<commit_after>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// Google Log
#include <glog/logging.h>

// HyperDex
#include <hyperdex/searches.h>

hyperdex :: searches :: searches(datalayer* data, logical* comm)
    : m_data(data)
    , m_comm(comm)
    , m_searches(16)
{
}

hyperdex :: searches :: ~searches() throw ()
{
}

void
hyperdex :: searches :: start(const entityid& client,
                              uint32_t nonce,
                              const regionid& r,
                              const search& s)
{
    std::pair<entityid, uint32_t> key(client, nonce);

    if (m_searches.contains(key))
    {
        return;
    }

    e::intrusive_ptr<region::snapshot> snap = m_data->make_snapshot(r);
    e::intrusive_ptr<search_state> state = new search_state(r, s, snap);
    m_searches.insert(key, state);
    next(client, nonce);
}

void
hyperdex :: searches :: next(const entityid& client,
                             uint32_t nonce)
{
    e::intrusive_ptr<search_state> state;

    if (!m_searches.lookup(std::make_pair(client, nonce), &state))
    {
        return;
    }

    po6::threads::mutex::hold hold(&state->lock);

    while (state->snap->valid())
    {
        if ((state->point & state->mask) == (state->snap->secondary_point() & state->mask))
        {
            e::buffer key(state->snap->key());
            std::vector<e::buffer> value(state->snap->value());

            if (state->terms.matches(value))
            {
                e::buffer msg;
                msg.pack() << nonce << state-> count << key << value;
                m_comm->send(state->region, client, stream_no::SEARCH_ITEM, msg);
                ++state->count;
                return;
            }
        }

        state->snap->next();
    }

    e::buffer msg;
    m_comm->send(state->region, client, stream_no::SEARCH_DONE, msg);
    ++state->count;
    stop(client, nonce);
}

void
hyperdex :: searches :: stop(const entityid& client,
                             uint32_t nonce)
{
    m_searches.remove(std::make_pair(client, nonce));
}

uint64_t
hyperdex :: searches :: hash(const std::pair<entityid, uint32_t>& key)
{
    return key.first.hash() + key.second;
}

hyperdex :: searches :: search_state :: search_state(const regionid& r,
                                                     const search& t,
                                                     e::intrusive_ptr<region::snapshot> s)
    : lock()
    , region(r)
    , point(t.secondary_point())
    , mask(t.secondary_mask())
    , terms(t)
    , snap(s)
    , count(0)
    , m_ref(0)
{
}

hyperdex :: searches :: search_state :: ~search_state() throw ()
{
}
<|endoftext|>


<commit_before>#include "Controller.h"
using Hydra::Logger;

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
		for (auto profile = profiles.begin(); profile != profiles.end(); profile++) //Delete cooldown timers
		{
			for (auto control = profile->second.begin(); control != profile->second.end(); control++)
				delete control->second.btn.cooldownTimer;
		}
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels" id="5">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load_file(filename.c_str());
		Logger::log(string("XML Load Result: ") + result.description(), "sysLog");

		for (pugi::xml_node profile: doc.child("ControlConfig").children("profile"))
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;
			Logger::log(string("Found profile ") + profile.attribute("name").as_string(), "sysLog");

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				Logger::log(string("Found control ") + control.attribute("name").as_string(), "sysLog");

				if (control.attribute("type").as_string() == string("button"))
				{
					Logger::log("Control is of type button", "sysLog");
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("cooldown").as_double();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
				}
				else
				{
					Logger::log("Control is of type joystick", "sysLog");
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
			{
				Logger::log(string("Switching to active profile ") + profile.attribute("name").as_string(), "sysLog");
				switchProfile(profile.attribute("name").as_string());
			}

		}
		Logger::log("Finished parsing config file", "sysLog");
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
		else
			Logger::log("Couldn't switch to profile - it doesn't exist!", "sysLog", Hydra::error);
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 */
	double Controller::operator[](const string& name)
	{
		if (profiles[currentProfile].count(name) == 0)
			return 0; //There IS no control by this name!

		ctrlCfg control = profiles[currentProfile][name];
		if (control.type == ctrlCfg::BUTTON)
		{
			if (!control.btn.toggle)
				return control.inverse ? !joystick->GetRawButton(control.id) : joystick->GetRawButton(control.id);
			else if (joystick->GetRawButton(control.id) || (!joystick->GetRawButton(control.id) && control.inverse))
			{
				if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
				{ //The cooldown expired
					control.btn.cooldownTimer->Reset();
					control.btn.cooldownTimer->Start();
					return !control.inverse;
				}
				return control.inverse;
			}
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double temp = value;
			value = control.jys.equ.evaluate(fabs(value));
			value = std::copysign(temp, value); //Copysign from temp to value?

			//scale values... should work
			temp = value;
			value = fabs(value) * ((control.jys.maxVal - control.jys.minVal) * 0.5f);
			return std::copysign(temp, value) + control.jys.minVal; //TODO: Verify

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<commit_msg>Fixed joystick output scaling<commit_after>#include "Controller.h"
using Hydra::Logger;

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
		for (auto profile = profiles.begin(); profile != profiles.end(); profile++) //Delete cooldown timers
		{
			for (auto control = profile->second.begin(); control != profile->second.end(); control++)
				delete control->second.btn.cooldownTimer;
		}
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels" id="5">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load_file(filename.c_str());
		Logger::log(string("XML Load Result: ") + result.description(), "sysLog");

		for (pugi::xml_node profile: doc.child("ControlConfig").children("profile"))
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;
			Logger::log(string("Found profile ") + profile.attribute("name").as_string(), "sysLog");

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				Logger::log(string("Found control ") + control.attribute("name").as_string(), "sysLog");

				if (control.attribute("type").as_string() == string("button"))
				{
					Logger::log("Control is of type button", "sysLog");
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("cooldown").as_double();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
				}
				else
				{
					Logger::log("Control is of type joystick", "sysLog");
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
			{
				Logger::log(string("Switching to active profile ") + profile.attribute("name").as_string(), "sysLog");
				switchProfile(profile.attribute("name").as_string());
			}

		}
		Logger::log("Finished parsing config file", "sysLog");
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
		else
			Logger::log("Couldn't switch to profile - it doesn't exist!", "sysLog", Hydra::error);
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 */
	double Controller::operator[](const string& name)
	{
		if (profiles[currentProfile].count(name) == 0)
			return 0; //There IS no control by this name!

		ctrlCfg control = profiles[currentProfile][name];
		if (control.type == ctrlCfg::BUTTON)
		{
			if (!control.btn.toggle)
				return control.inverse ? !joystick->GetRawButton(control.id) : joystick->GetRawButton(control.id);
			else if (joystick->GetRawButton(control.id) || (!joystick->GetRawButton(control.id) && control.inverse))
			{
				if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
				{ //The cooldown expired
					control.btn.cooldownTimer->Reset();
					control.btn.cooldownTimer->Start();
					return !control.inverse;
				}
				return control.inverse;
			}
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double slope = (control.jys.maxVal - control.jys.minVal) / 2.0;
			return (slope * value) - slope + control.jys.maxVal;

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <interfaces/chain.h>

#include <chain.h>
#include <chainparams.h>
#include <primitives/block.h>
#include <primitives/blockhash.h>
#include <sync.h>
#include <threadsafety.h>
#include <util/system.h>
#include <validation.h>

#include <memory>
#include <utility>

namespace interfaces {
namespace {

    class LockImpl : public Chain::Lock {
        Optional<int> getHeight() override {
            int height = ::ChainActive().Height();
            if (height >= 0) {
                return height;
            }
            return nullopt;
        }
        Optional<int> getBlockHeight(const BlockHash &hash) override {
            CBlockIndex *block = LookupBlockIndex(hash);
            if (block && ::ChainActive().Contains(block)) {
                return block->nHeight;
            }
            return nullopt;
        }
        int getBlockDepth(const BlockHash &hash) override {
            const Optional<int> tip_height = getHeight();
            const Optional<int> height = getBlockHeight(hash);
            return tip_height && height ? *tip_height - *height + 1 : 0;
        }
        BlockHash getBlockHash(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetBlockHash();
        }
        int64_t getBlockTime(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetBlockTime();
        }
        int64_t getBlockMedianTimePast(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetMedianTimePast();
        }
        bool haveBlockOnDisk(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            return block && (block->nStatus.hasData() != 0) && block->nTx > 0;
        }
        Optional<int> findFirstBlockWithTime(int64_t time,
                                             BlockHash *hash) override {
            CBlockIndex *block = ::ChainActive().FindEarliestAtLeast(time);
            if (block) {
                if (hash) {
                    *hash = block->GetBlockHash();
                }
                return block->nHeight;
            }
            return nullopt;
        }
        Optional<int> findFirstBlockWithTimeAndHeight(int64_t time,
                                                      int height) override {
            // TODO: Could update CChain::FindEarliestAtLeast() to take a height
            // parameter and use it with std::lower_bound() to make this
            // implementation more efficient and allow combining
            // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into
            // one method.
            for (CBlockIndex *block = ::ChainActive()[height]; block;
                 block = ::ChainActive().Next(block)) {
                if (block->GetBlockTime() >= time) {
                    return block->nHeight;
                }
            }
            return nullopt;
        }
        Optional<int> findPruned(int start_height,
                                 Optional<int> stop_height) override {
            if (::fPruneMode) {
                CBlockIndex *block = stop_height ? ::ChainActive()[*stop_height]
                                                 : ::ChainActive().Tip();
                while (block && block->nHeight >= start_height) {
                    if (block->nStatus.hasData() == 0) {
                        return block->nHeight;
                    }
                    block = block->pprev;
                }
            }
            return nullopt;
        }
        Optional<int> findFork(const BlockHash &hash,
                               Optional<int> *height) override {
            const CBlockIndex *block = LookupBlockIndex(hash);
            const CBlockIndex *fork =
                block ? ::ChainActive().FindFork(block) : nullptr;
            if (height) {
                if (block) {
                    *height = block->nHeight;
                } else {
                    height->reset();
                }
            }
            if (fork) {
                return fork->nHeight;
            }
            return nullopt;
        }
        bool isPotentialTip(const BlockHash &hash) override {
            if (::ChainActive().Tip()->GetBlockHash() == hash) {
                return true;
            }
            CBlockIndex *block = LookupBlockIndex(hash);
            return block && block->GetAncestor(::ChainActive().Height()) ==
                                ::ChainActive().Tip();
        }
        CBlockLocator getLocator() override {
            return ::ChainActive().GetLocator();
        }
        Optional<int> findLocatorFork(const CBlockLocator &locator) override {
            LockAnnotation lock(::cs_main);
            if (CBlockIndex *fork =
                    FindForkInGlobalIndex(::ChainActive(), locator)) {
                return fork->nHeight;
            }
            return nullopt;
        }
        bool contextualCheckTransactionForCurrentBlock(
            const Consensus::Params &params, const CTransaction &tx,
            CValidationState &state) override {
            LockAnnotation lock(::cs_main);
            return ContextualCheckTransactionForCurrentBlock(params, tx, state);
        }
    };

    class LockingStateImpl : public LockImpl,
                             public UniqueLock<CCriticalSection> {
        using UniqueLock::UniqueLock;
    };

    class ChainImpl : public Chain {
    public:
        std::unique_ptr<Chain::Lock> lock(bool try_lock) override {
            auto result = std::make_unique<LockingStateImpl>(
                ::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
            if (try_lock && result && !*result) {
                return {};
            }
            return result;
        }
        std::unique_ptr<Chain::Lock> assumeLocked() override {
            return std::make_unique<LockImpl>();
        }
        bool findBlock(const BlockHash &hash, CBlock *block, int64_t *time,
                       int64_t *time_max) override {
            CBlockIndex *index;
            {
                LOCK(cs_main);
                index = LookupBlockIndex(hash);
                if (!index) {
                    return false;
                }
                if (time) {
                    *time = index->GetBlockTime();
                }
                if (time_max) {
                    *time_max = index->GetBlockTimeMax();
                }
            }
            if (block &&
                !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
                block->SetNull();
            }
            return true;
        }
        double guessVerificationProgress(const BlockHash &block_hash) override {
            LOCK(cs_main);
            return GuessVerificationProgress(Params().TxData(),
                                             LookupBlockIndex(block_hash));
        }
    };

} // namespace

std::unique_ptr<Chain> MakeChain() {
    return std::make_unique<ChainImpl>();
}

} // namespace interfaces
<commit_msg>[backport#15288] Remove use of IsRBFOptIn in wallet code<commit_after>// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <interfaces/chain.h>

#include <chain.h>
#include <chainparams.h>
#include <primitives/block.h>
#include <primitives/blockhash.h>
#include <sync.h>
#include <threadsafety.h>
#include <txmempool.h>
#include <util/system.h>
#include <validation.h>

#include <memory>
#include <utility>

namespace interfaces {
namespace {

    class LockImpl : public Chain::Lock {
        Optional<int> getHeight() override {
            int height = ::ChainActive().Height();
            if (height >= 0) {
                return height;
            }
            return nullopt;
        }
        Optional<int> getBlockHeight(const BlockHash &hash) override {
            CBlockIndex *block = LookupBlockIndex(hash);
            if (block && ::ChainActive().Contains(block)) {
                return block->nHeight;
            }
            return nullopt;
        }
        int getBlockDepth(const BlockHash &hash) override {
            const Optional<int> tip_height = getHeight();
            const Optional<int> height = getBlockHeight(hash);
            return tip_height && height ? *tip_height - *height + 1 : 0;
        }
        BlockHash getBlockHash(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetBlockHash();
        }
        int64_t getBlockTime(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetBlockTime();
        }
        int64_t getBlockMedianTimePast(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            assert(block != nullptr);
            return block->GetMedianTimePast();
        }
        bool haveBlockOnDisk(int height) override {
            CBlockIndex *block = ::ChainActive()[height];
            return block && (block->nStatus.hasData() != 0) && block->nTx > 0;
        }
        Optional<int> findFirstBlockWithTime(int64_t time,
                                             BlockHash *hash) override {
            CBlockIndex *block = ::ChainActive().FindEarliestAtLeast(time);
            if (block) {
                if (hash) {
                    *hash = block->GetBlockHash();
                }
                return block->nHeight;
            }
            return nullopt;
        }
        Optional<int> findFirstBlockWithTimeAndHeight(int64_t time,
                                                      int height) override {
            // TODO: Could update CChain::FindEarliestAtLeast() to take a height
            // parameter and use it with std::lower_bound() to make this
            // implementation more efficient and allow combining
            // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into
            // one method.
            for (CBlockIndex *block = ::ChainActive()[height]; block;
                 block = ::ChainActive().Next(block)) {
                if (block->GetBlockTime() >= time) {
                    return block->nHeight;
                }
            }
            return nullopt;
        }
        Optional<int> findPruned(int start_height,
                                 Optional<int> stop_height) override {
            if (::fPruneMode) {
                CBlockIndex *block = stop_height ? ::ChainActive()[*stop_height]
                                                 : ::ChainActive().Tip();
                while (block && block->nHeight >= start_height) {
                    if (block->nStatus.hasData() == 0) {
                        return block->nHeight;
                    }
                    block = block->pprev;
                }
            }
            return nullopt;
        }
        Optional<int> findFork(const BlockHash &hash,
                               Optional<int> *height) override {
            const CBlockIndex *block = LookupBlockIndex(hash);
            const CBlockIndex *fork =
                block ? ::ChainActive().FindFork(block) : nullptr;
            if (height) {
                if (block) {
                    *height = block->nHeight;
                } else {
                    height->reset();
                }
            }
            if (fork) {
                return fork->nHeight;
            }
            return nullopt;
        }
        bool isPotentialTip(const BlockHash &hash) override {
            if (::ChainActive().Tip()->GetBlockHash() == hash) {
                return true;
            }
            CBlockIndex *block = LookupBlockIndex(hash);
            return block && block->GetAncestor(::ChainActive().Height()) ==
                                ::ChainActive().Tip();
        }
        CBlockLocator getLocator() override {
            return ::ChainActive().GetLocator();
        }
        Optional<int> findLocatorFork(const CBlockLocator &locator) override {
            LockAnnotation lock(::cs_main);
            if (CBlockIndex *fork =
                    FindForkInGlobalIndex(::ChainActive(), locator)) {
                return fork->nHeight;
            }
            return nullopt;
        }
        bool contextualCheckTransactionForCurrentBlock(
            const Consensus::Params &params, const CTransaction &tx,
            CValidationState &state) override {
            LockAnnotation lock(::cs_main);
            return ContextualCheckTransactionForCurrentBlock(params, tx, state);
        }
    };

    class LockingStateImpl : public LockImpl,
                             public UniqueLock<CCriticalSection> {
        using UniqueLock::UniqueLock;
    };

    class ChainImpl : public Chain {
    public:
        std::unique_ptr<Chain::Lock> lock(bool try_lock) override {
            auto result = std::make_unique<LockingStateImpl>(
                ::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
            if (try_lock && result && !*result) {
                return {};
            }
            return result;
        }
        std::unique_ptr<Chain::Lock> assumeLocked() override {
            return std::make_unique<LockImpl>();
        }
        bool findBlock(const BlockHash &hash, CBlock *block, int64_t *time,
                       int64_t *time_max) override {
            CBlockIndex *index;
            {
                LOCK(cs_main);
                index = LookupBlockIndex(hash);
                if (!index) {
                    return false;
                }
                if (time) {
                    *time = index->GetBlockTime();
                }
                if (time_max) {
                    *time_max = index->GetBlockTimeMax();
                }
            }
            if (block &&
                !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
                block->SetNull();
            }
            return true;
        }
        double guessVerificationProgress(const BlockHash &block_hash) override {
            LOCK(cs_main);
            return GuessVerificationProgress(Params().TxData(),
                                             LookupBlockIndex(block_hash));
        }
    };

} // namespace

std::unique_ptr<Chain> MakeChain() {
    return std::make_unique<ChainImpl>();
}

} // namespace interfaces
<|endoftext|>