<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <boost/compute.hpp>
#include <algorithm>
#include <QtGui>
#include <QtOpenGL>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/kernel.hpp>
#include <boost/compute/program.hpp>
#include <boost/compute/source.hpp>
#include <boost/compute/system.hpp>
#include <boost/compute/interop/opengl.hpp>
using namespace std;
namespace compute = boost::compute;

int main (int argc, char* argv[])
{
    // get the default compute device
    compute::device gpu = compute::system::default_device();

    // create a compute context and command queue
    compute::context ctx(gpu);
    compute::command_queue queue(ctx, gpu);

	//set some default values for when no commandline arguments are given
        //create accuracy variable
            int accuracy = 90;

            // create vector on device
            compute::vector<int> device_accuracy(1);

            // copy from host to device
            compute::copy(accuracy,
                accuracy,
                device_accuracy.begin());

        //create polygons variable
            int polygons = 50;

            // create vector on device
            compute::vector<int> device_polygons(1);

            // copy from host to device
            compute::copy(host_data,
                host_data + 5,
                device_vector.begin());

        //create vertices variable
            int vertices = 6;

            // create vector on device
            compute::vector<int> device_vertices(1);

            // copy from host to device
            compute::copy(host_data,
                host_data + 5,
                device_vector.begin());

    //read input commandline arguments
    for (int i = 1; i < argc; ++i)
    {
        if (std::string(argv[i]) == "-a")
            {
                //initialise desired accuracy variable according to commandline argument -a
                accuracy = ;
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());

            }
        if (std::string(argv[i]) == "-p")
            {
                //initialise maximum polygons variable according to commandline argument -p
                polygons = ;
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());

            }
        if (std::string(argv[i]) == "-v")
            {
                //initialise maximum verices per polygon variable according to commandline argument -v
                vertices = ;
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());
            }
    }

    //create leaderDNA variable
        // generate random dna vector on the host
        std::vector<float> leaderDNA(1000000);
        std::generate(leaderDNA.begin(), leaderDNA.end(), rand);

        // create vector on the device
        compute::vector<float> device_leaderDNA(1000000, ctx);

        // copy data to the device
        compute::copy(
            leaderDNA.begin(),
            leaderDNA.end(),
            device_leaderDNA.begin(),
            queue
        );

    //create mutatedDNA variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create leaderDNArender variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create mutatedDNArender variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create original image variable + load image into gpu memory
    if (std::string(argv[i]) == "")
            {
                //load file according to commandline argument into gpu vector

                //get x(max), y(max). (image dimensions)

                //make image vector on device
                compute::vector<float> originalimage(ctx, n);
                // copy data to the device
                compute::copy(
                    host_vector.begin(),
                    host_vector.end(),
                    device_vector.begin(),
                    queue
                );
            }

    //run render loop until desired accuracy is reached
    while (leaderaccuracy<accuracy)
        {

            //render leader DNA to a raster image in opengl texture
            boost::compute::function<int (int)> renderDNA =
            boost::compute::make_function_from_source<int (int)>(
                "renderDNA",
                "int renderDNA(int x)
                    { //for each shape in dna
                        {
                        glEnable(GL_TEXTURE_2D);
                        glBindTexture(GL_TEXTURE_2D, gl_texture_);
                        glBegin(GL_QUADS);
                        glTexCoord2f(0, 0); glVertex2f(0, 0);
                        glTexCoord2f(0, 1); glVertex2f(0, h);
                        glTexCoord2f(1, 1); glVertex2f(w, h);
                        glTexCoord2f(1, 0); glVertex2f(w, 0);
                        glEnd();
                        } }"
            );

    //compute fitness of leader dna image
    //compute what % match DNAimage is to original image
    boost::compute::function<int (int)> computefitnesspercent =
    boost::compute::make_function_from_source<int (int)>(
        "computefitnesspercent",
        "int computefitnesspercent(int x) { }"
    );
            while ()
                {
                //mutate from the leaderDNA
                boost::compute::function<int (int)> mutateDNA =
                boost::compute::make_function_from_source<int (int)>(
                    "mutateDNA",
                    "int mutateDNA(int DNA)
                        {
                        //mutate input DNA randomly
                        mutated_shape = RANDINT(NUM_SHAPES);
                        double roulette = RANDDOUBLE(3);

                        //mutate color
                            //randomly change mutated_shape colour
                                //change red
                                    //up
                                    //down
                                //change green
                                    //up
                                    //down
                                //change blue
                                    //up
                                    //down
                                //change alpha
                                    //up
                                    //down
                        //mutate shape
                            //randomly move one vertex in mutated_shape
                                //randomly pick vertex
                                    //move up
                                    //move down
                                    //move left
                                    //move right
                        //mutate stacking
                            //randomly move one shape up or down stack
                                //randomly select shape
                                    //move shape up stack
                                    //move shape down stack
                        //100% mutation (create new random dna)
                );

    //render mutated DNA to a raster image in opengl texture
    boost::compute::function<int (int)> renderDNA =
    boost::compute::make_function_from_source<int (int)>(
        "renderDNA",
        "int renderDNA(int x)
        {
        //for each shape in dna
            {
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, gl_texture_);
            glBegin(GL_QUADS);
            glTexCoord2f(0, 0); glVertex2f(0, 0);
            glTexCoord2f(0, 1); glVertex2f(0, h);
            glTexCoord2f(1, 1); glVertex2f(w, h);
            glTexCoord2f(1, 0); glVertex2f(w, 0);
            glEnd();
            } }"
    );

    //compute what % match mutated dna image is to original image
    boost::compute::function<int (int)> computefitnesspercent =
    boost::compute::make_function_from_source<int (int)>(
        "computefitnesspercent",
        "int computefitnesspercent(int x) {
        //get x, y size of images to be compared

        //for each x,y value
            //give % match between leaderDNAimage(x,y) and mutatedDNAimage(x,y)

        //calculate average % value and store to mutatedDNAfitness

         }"
    );

    //check if mutated dna image is fitter, if so overwrite leaderDNA
    if (mutatedDNAfitness > leaderDNAfitness)
        {
            //overwrite leaderDNA
            leaderDNA = mutatedDNA;

            //save dna to disk as filename.dna
            pFile = fopen ("%filename.dna","w");
            fprintf (pFile, DNA);
            fclose (pFile);
        }

    //perform final render, output svg and raster image
        //render final DNA to a raster image in opengl texture
        boost::compute::function<int (int)> renderDNA =
        boost::compute::make_function_from_source<int (int)>(
            "renderDNA",
            "int renderDNA(int x)
            {
                //for each shape in dna
                {
                    glEnable(GL_TEXTURE_2D);
                    glBindTexture(GL_TEXTURE_2D, gl_texture_);
                    glBegin(GL_QUADS);
                    glTexCoord2f(0, 0); glVertex2f(0, 0);
                    glTexCoord2f(0, 1); glVertex2f(0, h);
                    glTexCoord2f(1, 1); glVertex2f(w, h);
                    glTexCoord2f(1, 0); glVertex2f(w, 0);
                    glEnd();
                }
            }"
        );

        //copy raster image from gpu to main memory

        //save raster image to disk as filename.render.png
        pFile = fopen ("%filename.render.png","w");
                    fprintf (pFile, leaderDNAimage);
                    fclose (pFile);

        //render mutated DNA to a vector image
        boost::compute::function<int (int)> renderDNA =
        boost::compute::make_function_from_source<int (int)>(
            "renderDNAvector",
            "int renderDNAvector(DNA)
            {
            //initialise svg string
            //for each shape in dna
                {
                    //add shape to svg
                }
            }"
            //close svg string
        );

        //copy vector image from gpu to main memory

        //save vector image to disk as filename.render.svg
        pFile = fopen ("%filename.render.svg","w");
                    fprintf (pFile, leaderDNAvector);
                    fclose (pFile);
}<commit_msg>commandline argument handling<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <boost/compute.hpp>
#include <algorithm>
#include <QtGui>
#include <QtOpenGL>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/kernel.hpp>
#include <boost/compute/program.hpp>
#include <boost/compute/source.hpp>
#include <boost/compute/system.hpp>
#include <boost/compute/interop/opengl.hpp>
using namespace std;
namespace compute = boost::compute;

int main (int argc, char* argv[])
{
    // get the default compute device
    compute::device gpu = compute::system::default_device();

    // create a compute context and command queue
    compute::context ctx(gpu);
    compute::command_queue queue(ctx, gpu);

	//set some default values for when no commandline arguments are given
        //create accuracy variable
            int accuracy = 90;

            // create vector on device
            compute::vector<int> device_accuracy(1);

            // copy from host to device
            compute::copy(accuracy,
                accuracy,
                device_accuracy.begin());

        //create polygons variable
            int polygons = 50;

            // create vector on device
            compute::vector<int> device_polygons(1);

            // copy from host to device
            compute::copy(host_data,
                host_data + 5,
                device_vector.begin());

        //create vertices variable
            int vertices = 6;

            // create vector on device
            compute::vector<int> device_vertices(1);

            // copy from host to device
            compute::copy(host_data,
                host_data + 5,
                device_vector.begin());

    //read input commandline arguments
    for (int i = 1; i < argc; ++i)
    {
        if (std::string(argv[i]) == "-a")
            {
                //initialise desired accuracy variable according to commandline argument -a
                accuracy = argv[i + 1];
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());

            }
        if (std::string(argv[i]) == "-p")
            {
                //initialise maximum polygons variable according to commandline argument -p
                polygons = argv[i + 1];
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());

            }
        if (std::string(argv[i]) == "-v")
            {
                //initialise maximum verices per polygon variable according to commandline argument -v
                vertices = argv[i + 1];
                // copy from host to device
                compute::copy(accuracy,
                    accuracy,
                    device_accuracy.begin());
            }
    }

    //create leaderDNA variable
        // generate random dna vector on the host
        std::vector<int> leaderDNA(1000000);
        std::generate(leaderDNA.begin(), leaderDNA.end(), rand);

        // create vector on the device
        compute::vector<int> device_leaderDNA(1000000, ctx);

        // copy data to the device
        compute::copy(
            leaderDNA.begin(),
            leaderDNA.end(),
            device_leaderDNA.begin(),
            queue
        );

    //create mutatedDNA variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create leaderDNArender variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create mutatedDNArender variable
        // create data array on host
        int host_data[] = { 1, 3, 5, 7, 9 };

        // create vector on device
        compute::vector<int> device_vector(5);

        // copy from host to device
        compute::copy(host_data,
            host_data + 5,
            device_vector.begin());

    //create original image variable + load image into gpu memory
    if (std::string(argv[i]) == "")
            {
                //load file according to commandline argument into gpu vector

                //get x(max), y(max). (image dimensions)

                //make image vector on device
                compute::vector<int> originalimage(ctx, n);
                // copy data to the device
                compute::copy(
                    host_vector.begin(),
                    host_vector.end(),
                    device_vector.begin(),
                    queue
                );
            }

    //run render loop until desired accuracy is reached
    while (leaderaccuracy<accuracy)
        {

            //render leader DNA to a raster image in opengl texture
            boost::compute::function<int (int)> renderDNA =
            boost::compute::make_function_from_source<int (int)>(
                "renderDNA",
                "int renderDNA(int x)
                    { //for each shape in dna
                        {
                        glEnable(GL_TEXTURE_2D);
                        glBindTexture(GL_TEXTURE_2D, gl_texture_);
                        glBegin(GL_QUADS);
                        glTexCoord2f(0, 0); glVertex2f(0, 0);
                        glTexCoord2f(0, 1); glVertex2f(0, h);
                        glTexCoord2f(1, 1); glVertex2f(w, h);
                        glTexCoord2f(1, 0); glVertex2f(w, 0);
                        glEnd();
                        } }"
            );

    //compute fitness of leader dna image
    //compute what % match DNAimage is to original image
    boost::compute::function<int (int)> computefitnesspercent =
    boost::compute::make_function_from_source<int (int)>(
        "computefitnesspercent",
        "int computefitnesspercent(int x) { }"
    );
            while ()
                {
                //mutate from the leaderDNA
                boost::compute::function<int (int)> mutateDNA =
                boost::compute::make_function_from_source<int (int)>(
                    "mutateDNA",
                    "int mutateDNA(int DNA)
                        {
                        //mutate input DNA randomly
                        mutated_shape = RANDINT(NUM_SHAPES);
                        double roulette = RANDDOUBLE(3);

                        //mutate color
                            //randomly change mutated_shape colour
                                //change red
                                    //up
                                    //down
                                //change green
                                    //up
                                    //down
                                //change blue
                                    //up
                                    //down
                                //change alpha
                                    //up
                                    //down
                        //mutate shape
                            //randomly move one vertex in mutated_shape
                                //randomly pick vertex
                                    //move up
                                    //move down
                                    //move left
                                    //move right
                        //mutate stacking
                            //randomly move one shape up or down stack
                                //randomly select shape
                                    //move shape up stack
                                    //move shape down stack
                        //100% mutation (create new random dna)
                );

    //render mutated DNA to a raster image in opengl texture
    boost::compute::function<int (int)> renderDNA =
    boost::compute::make_function_from_source<int (int)>(
        "renderDNA",
        "int renderDNA(int x)
        {
        //for each shape in dna
            {
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D, gl_texture_);
            glBegin(GL_QUADS);
            glTexCoord2f(0, 0); glVertex2f(0, 0);
            glTexCoord2f(0, 1); glVertex2f(0, h);
            glTexCoord2f(1, 1); glVertex2f(w, h);
            glTexCoord2f(1, 0); glVertex2f(w, 0);
            glEnd();
            } }"
    );

    //compute what % match mutated dna image is to original image
    boost::compute::function<int (int)> computefitnesspercent =
    boost::compute::make_function_from_source<int (int)>(
        "computefitnesspercent",
        "int computefitnesspercent(int x) {
        //get x, y size of images to be compared

        //for each x,y value
            //give % match between leaderDNAimage(x,y) and mutatedDNAimage(x,y)

        //calculate average % value and store to mutatedDNAfitness

         }"
    );

    //check if mutated dna image is fitter, if so overwrite leaderDNA
    if (mutatedDNAfitness > leaderDNAfitness)
        {
            //overwrite leaderDNA
            leaderDNA = mutatedDNA;

            //save dna to disk as filename.dna
            pFile = fopen ("%filename.dna","w");
            fprintf (pFile, DNA);
            fclose (pFile);
        }

    //perform final render, output svg and raster image
        //render final DNA to a raster image in opengl texture
        boost::compute::function<int (int)> renderDNA =
        boost::compute::make_function_from_source<int (int)>(
            "renderDNA",
            "int renderDNA(int x)
            {
                //for each shape in dna
                {
                    glEnable(GL_TEXTURE_2D);
                    glBindTexture(GL_TEXTURE_2D, gl_texture_);
                    glBegin(GL_QUADS);
                    glTexCoord2f(0, 0); glVertex2f(0, 0);
                    glTexCoord2f(0, 1); glVertex2f(0, h);
                    glTexCoord2f(1, 1); glVertex2f(w, h);
                    glTexCoord2f(1, 0); glVertex2f(w, 0);
                    glEnd();
                }
            }"
        );

        //copy raster image from gpu to main memory

        //save raster image to disk as filename.render.png
        pFile = fopen ("%filename.render.png","w");
                    fprintf (pFile, leaderDNAimage);
                    fclose (pFile);

        //render mutated DNA to a vector image
        boost::compute::function<int (int)> renderDNA =
        boost::compute::make_function_from_source<int (int)>(
            "renderDNAvector",
            "int renderDNAvector(DNA)
            {
            //initialise svg string
            //for each shape in dna
                {
                    //add shape to svg
                }
            }"
            //close svg string
        );

        //copy vector image from gpu to main memory

        //save vector image to disk as filename.render.svg
        pFile = fopen ("%filename.render.svg","w");
                    fprintf (pFile, leaderDNAvector);
                    fclose (pFile);
}<|endoftext|>


<commit_before>#ifndef SILICIUM_TO_UNIQUE_HPP
#define SILICIUM_TO_UNIQUE_HPP

#include <memory>

namespace Si
{
	template <class T>
	auto to_unique(T &&t) -> std::unique_ptr<typename std::decay<T>::type>
	{
		typedef typename std::decay<T>::type decayed_T;
		return std::unique_ptr<decayed_T>(new decayed_T(std::forward<T>(t)));
	}
}

namespace Si
{
	using Si::to_unique;
}

#endif
<commit_msg>remove redundant using declaration<commit_after>#ifndef SILICIUM_TO_UNIQUE_HPP
#define SILICIUM_TO_UNIQUE_HPP

#include <memory>

namespace Si
{
	template <class T>
	auto to_unique(T &&t) -> std::unique_ptr<typename std::decay<T>::type>
	{
		typedef typename std::decay<T>::type decayed_T;
		return std::unique_ptr<decayed_T>(new decayed_T(std::forward<T>(t)));
	}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DATABASE_HH_
#define DATABASE_HH_

#include "dht/i_partitioner.hh"
#include "config/ks_meta_data.hh"
#include "locator/abstract_replication_strategy.hh"
#include "core/sstring.hh"
#include "core/shared_ptr.hh"
#include "net/byteorder.hh"
#include "utils/UUID.hh"
#include "utils/hash.hh"
#include "db_clock.hh"
#include "gc_clock.hh"
#include <functional>
#include <cstdint>
#include <unordered_map>
#include <map>
#include <set>
#include <iostream>
#include <boost/functional/hash.hpp>
#include <experimental/optional>
#include <string.h>
#include "types.hh"
#include "compound.hh"
#include "core/future.hh"
#include "cql3/column_specification.hh"
#include <limits>
#include <cstddef>
#include "schema.hh"
#include "timestamp.hh"
#include "tombstone.hh"
#include "atomic_cell.hh"
#include "query-request.hh"
#include "query-result.hh"
#include "keys.hh"
#include "mutation.hh"

class frozen_mutation;

namespace sstables {

class sstable;

}

namespace db {
template<typename T>
class serializer;

class commitlog;
class config;
}

class memtable {
public:
    using partitions_type = std::map<dht::decorated_key, mutation_partition, dht::decorated_key::less_comparator>;
private:
    schema_ptr _schema;
    partitions_type partitions;
public:
    using const_mutation_partition_ptr = std::unique_ptr<const mutation_partition>;
public:
    explicit memtable(schema_ptr schema);
    schema_ptr schema() const { return _schema; }
    mutation_partition& find_or_create_partition(const dht::decorated_key& key);
    mutation_partition& find_or_create_partition_slow(partition_key_view key);
    row& find_or_create_row_slow(const partition_key& partition_key, const clustering_key& clustering_key);
    const_mutation_partition_ptr find_partition(const dht::decorated_key& key) const;
    void apply(const mutation& m);
    void apply(const frozen_mutation& m);
    const partitions_type& all_partitions() const;
};

class column_family {
public:
    struct config {
        sstring datadir;
        bool enable_disk_writes = true;
        bool enable_disk_reads = true;
    };
private:
    schema_ptr _schema;
    config _config;
    std::vector<memtable> _memtables;
    // generation -> sstable. Ordered by key so we can easily get the most recent.
    std::map<unsigned long, std::unique_ptr<sstables::sstable>> _sstables;
    unsigned _sstable_generation = 1;
private:
    memtable& active_memtable() { return _memtables.back(); }
    struct merge_comparator;
public:
    // Queries can be satisfied from multiple data sources, so they are returned
    // as temporaries.
    //
    // FIXME: in case a query is satisfied from a single memtable, avoid a copy
    using const_mutation_partition_ptr = std::unique_ptr<const mutation_partition>;
    using const_row_ptr = std::unique_ptr<const row>;
public:
    column_family(schema_ptr schema, config cfg);
    column_family(column_family&&) = default;
    ~column_family();
    schema_ptr schema() const { return _schema; }
    const_mutation_partition_ptr find_partition(const dht::decorated_key& key) const;
    const_mutation_partition_ptr find_partition_slow(const partition_key& key) const;
    const_row_ptr find_row(const dht::decorated_key& partition_key, const clustering_key& clustering_key) const;
    void apply(const frozen_mutation& m);
    void apply(const mutation& m);
    // Returns at most "cmd.limit" rows
    future<lw_shared_ptr<query::result>> query(const query::read_command& cmd) const;

    future<> populate(sstring datadir);
    void seal_active_memtable();
    const std::vector<memtable>& testonly_all_memtables() const;
private:
    // Iterate over all partitions.  Protocol is the same as std::all_of(),
    // so that iteration can be stopped by returning false.
    // Func signature: bool (const decorated_key& dk, const mutation_partition& mp)
    template <typename Func>
    bool for_all_partitions(Func&& func) const;
    future<> probe_file(sstring sstdir, sstring fname);
public:
    // Iterate over all partitions.  Protocol is the same as std::all_of(),
    // so that iteration can be stopped by returning false.
    bool for_all_partitions_slow(std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const;

    friend std::ostream& operator<<(std::ostream& out, const column_family& cf);
};

class user_types_metadata {
    std::unordered_map<bytes, user_type> _user_types;
public:
    user_type get_type(bytes name) const {
        return _user_types.at(name);
    }
    const std::unordered_map<bytes, user_type>& get_all_types() const {
        return _user_types;
    }
    void add_type(user_type type) {
        auto i = _user_types.find(type->_name);
        assert(i == _user_types.end() || type->is_compatible_with(*i->second));
        _user_types[type->_name] = std::move(type);
    }
    void remove_type(user_type type) {
        _user_types.erase(type->_name);
    }
};

class keyspace {
public:
    struct config {
        sstring datadir;
        bool enable_disk_reads = true;
        bool enable_disk_writes = true;
    };
private:
    std::unique_ptr<locator::abstract_replication_strategy> _replication_strategy;
    config _config;
public:
    explicit keyspace(config cfg) : _config(std::move(cfg)) {}
    user_types_metadata _user_types;
    void create_replication_strategy(::config::ks_meta_data& ksm);
    locator::abstract_replication_strategy& get_replication_strategy();
    column_family::config make_column_family_config(const schema& s) const;
private:
    sstring column_family_directory(const sstring& name, utils::UUID uuid) const;
};

class no_such_keyspace : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

class no_such_column_family : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

// Policy for distributed<database>:
//   broadcast metadata writes
//   local metadata reads
//   use shard_of() for data

class database {
    std::unordered_map<sstring, keyspace> _keyspaces;
    std::unordered_map<utils::UUID, column_family> _column_families;
    std::unordered_map<std::pair<sstring, sstring>, utils::UUID, utils::tuple_hash> _ks_cf_to_uuid;
    std::unique_ptr<db::commitlog> _commitlog;
    std::unique_ptr<db::config> _cfg;

    future<> init_commitlog();
    future<> apply_in_memory(const frozen_mutation&);
    future<> populate(sstring datadir);
public:
    database();
    database(const db::config&);
    database(database&&) = default;
    ~database();

    db::commitlog* commitlog() const {
        return _commitlog.get();
    }

    future<> init_from_data_directory();

    keyspace& add_keyspace(sstring name, keyspace k);
    /** Adds cf with auto-generated UUID. */
    void add_column_family(column_family&&);
    void add_column_family(const utils::UUID&, column_family&&);

    /* throws std::out_of_range if missing */
    const utils::UUID& find_uuid(const sstring& ks, const sstring& cf) const throw (std::out_of_range);
    const utils::UUID& find_uuid(const schema_ptr&) const throw (std::out_of_range);

    /* below, find* throws no_such_<type> on fail */
    keyspace& find_or_create_keyspace(const sstring& name);
    keyspace& find_keyspace(const sstring& name) throw (no_such_keyspace);
    const keyspace& find_keyspace(const sstring& name) const throw (no_such_keyspace);
    bool has_keyspace(const sstring& name) const;
    void update_keyspace(const sstring& name);
    void drop_keyspace(const sstring& name);
    column_family& find_column_family(const sstring& ks, const sstring& name) throw (no_such_column_family);
    const column_family& find_column_family(const sstring& ks, const sstring& name) const throw (no_such_column_family);
    column_family& find_column_family(const utils::UUID&) throw (no_such_column_family);
    const column_family& find_column_family(const utils::UUID&) const throw (no_such_column_family);
    column_family& find_column_family(const schema_ptr&) throw (no_such_column_family);
    const column_family& find_column_family(const schema_ptr&) const throw (no_such_column_family);
    schema_ptr find_schema(const sstring& ks_name, const sstring& cf_name) const throw (no_such_column_family);
    schema_ptr find_schema(const utils::UUID&) const throw (no_such_column_family);
    future<> stop();
    unsigned shard_of(const dht::token& t);
    unsigned shard_of(const mutation& m);
    unsigned shard_of(const frozen_mutation& m);
    future<lw_shared_ptr<query::result>> query(const query::read_command& cmd);
    future<> apply(const frozen_mutation&);
    keyspace::config make_keyspace_config(sstring name) const;
    friend std::ostream& operator<<(std::ostream& out, const database& db);
};

// FIXME: stub
class secondary_index_manager {};

inline
void
column_family::apply(const mutation& m) {
    return active_memtable().apply(m);
}

inline
void
column_family::apply(const frozen_mutation& m) {
    return active_memtable().apply(m);
}

#endif /* DATABASE_HH_ */
<commit_msg>db: add simple memtable sealing policy<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DATABASE_HH_
#define DATABASE_HH_

#include "dht/i_partitioner.hh"
#include "config/ks_meta_data.hh"
#include "locator/abstract_replication_strategy.hh"
#include "core/sstring.hh"
#include "core/shared_ptr.hh"
#include "net/byteorder.hh"
#include "utils/UUID.hh"
#include "utils/hash.hh"
#include "db_clock.hh"
#include "gc_clock.hh"
#include <functional>
#include <cstdint>
#include <unordered_map>
#include <map>
#include <set>
#include <iostream>
#include <boost/functional/hash.hpp>
#include <experimental/optional>
#include <string.h>
#include "types.hh"
#include "compound.hh"
#include "core/future.hh"
#include "cql3/column_specification.hh"
#include <limits>
#include <cstddef>
#include "schema.hh"
#include "timestamp.hh"
#include "tombstone.hh"
#include "atomic_cell.hh"
#include "query-request.hh"
#include "query-result.hh"
#include "keys.hh"
#include "mutation.hh"

class frozen_mutation;

namespace sstables {

class sstable;

}

namespace db {
template<typename T>
class serializer;

class commitlog;
class config;
}

class memtable {
public:
    using partitions_type = std::map<dht::decorated_key, mutation_partition, dht::decorated_key::less_comparator>;
private:
    schema_ptr _schema;
    partitions_type partitions;
public:
    using const_mutation_partition_ptr = std::unique_ptr<const mutation_partition>;
public:
    explicit memtable(schema_ptr schema);
    schema_ptr schema() const { return _schema; }
    mutation_partition& find_or_create_partition(const dht::decorated_key& key);
    mutation_partition& find_or_create_partition_slow(partition_key_view key);
    row& find_or_create_row_slow(const partition_key& partition_key, const clustering_key& clustering_key);
    const_mutation_partition_ptr find_partition(const dht::decorated_key& key) const;
    void apply(const mutation& m);
    void apply(const frozen_mutation& m);
    const partitions_type& all_partitions() const;
};

class column_family {
public:
    struct config {
        sstring datadir;
        bool enable_disk_writes = true;
        bool enable_disk_reads = true;
    };
private:
    schema_ptr _schema;
    config _config;
    std::vector<memtable> _memtables;
    // generation -> sstable. Ordered by key so we can easily get the most recent.
    std::map<unsigned long, std::unique_ptr<sstables::sstable>> _sstables;
    unsigned _sstable_generation = 1;
    unsigned _mutation_count = 0;
private:
    memtable& active_memtable() { return _memtables.back(); }
    struct merge_comparator;
public:
    // Queries can be satisfied from multiple data sources, so they are returned
    // as temporaries.
    //
    // FIXME: in case a query is satisfied from a single memtable, avoid a copy
    using const_mutation_partition_ptr = std::unique_ptr<const mutation_partition>;
    using const_row_ptr = std::unique_ptr<const row>;
public:
    column_family(schema_ptr schema, config cfg);
    column_family(column_family&&) = default;
    ~column_family();
    schema_ptr schema() const { return _schema; }
    const_mutation_partition_ptr find_partition(const dht::decorated_key& key) const;
    const_mutation_partition_ptr find_partition_slow(const partition_key& key) const;
    const_row_ptr find_row(const dht::decorated_key& partition_key, const clustering_key& clustering_key) const;
    void apply(const frozen_mutation& m);
    void apply(const mutation& m);
    // Returns at most "cmd.limit" rows
    future<lw_shared_ptr<query::result>> query(const query::read_command& cmd) const;

    future<> populate(sstring datadir);
    void seal_active_memtable();
    const std::vector<memtable>& testonly_all_memtables() const;
private:
    // Iterate over all partitions.  Protocol is the same as std::all_of(),
    // so that iteration can be stopped by returning false.
    // Func signature: bool (const decorated_key& dk, const mutation_partition& mp)
    template <typename Func>
    bool for_all_partitions(Func&& func) const;
    future<> probe_file(sstring sstdir, sstring fname);
    void seal_on_overflow();
public:
    // Iterate over all partitions.  Protocol is the same as std::all_of(),
    // so that iteration can be stopped by returning false.
    bool for_all_partitions_slow(std::function<bool (const dht::decorated_key&, const mutation_partition&)> func) const;

    friend std::ostream& operator<<(std::ostream& out, const column_family& cf);
};

class user_types_metadata {
    std::unordered_map<bytes, user_type> _user_types;
public:
    user_type get_type(bytes name) const {
        return _user_types.at(name);
    }
    const std::unordered_map<bytes, user_type>& get_all_types() const {
        return _user_types;
    }
    void add_type(user_type type) {
        auto i = _user_types.find(type->_name);
        assert(i == _user_types.end() || type->is_compatible_with(*i->second));
        _user_types[type->_name] = std::move(type);
    }
    void remove_type(user_type type) {
        _user_types.erase(type->_name);
    }
};

class keyspace {
public:
    struct config {
        sstring datadir;
        bool enable_disk_reads = true;
        bool enable_disk_writes = true;
    };
private:
    std::unique_ptr<locator::abstract_replication_strategy> _replication_strategy;
    config _config;
public:
    explicit keyspace(config cfg) : _config(std::move(cfg)) {}
    user_types_metadata _user_types;
    void create_replication_strategy(::config::ks_meta_data& ksm);
    locator::abstract_replication_strategy& get_replication_strategy();
    column_family::config make_column_family_config(const schema& s) const;
private:
    sstring column_family_directory(const sstring& name, utils::UUID uuid) const;
};

class no_such_keyspace : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

class no_such_column_family : public std::runtime_error {
public:
    using runtime_error::runtime_error;
};

// Policy for distributed<database>:
//   broadcast metadata writes
//   local metadata reads
//   use shard_of() for data

class database {
    std::unordered_map<sstring, keyspace> _keyspaces;
    std::unordered_map<utils::UUID, column_family> _column_families;
    std::unordered_map<std::pair<sstring, sstring>, utils::UUID, utils::tuple_hash> _ks_cf_to_uuid;
    std::unique_ptr<db::commitlog> _commitlog;
    std::unique_ptr<db::config> _cfg;

    future<> init_commitlog();
    future<> apply_in_memory(const frozen_mutation&);
    future<> populate(sstring datadir);
public:
    database();
    database(const db::config&);
    database(database&&) = default;
    ~database();

    db::commitlog* commitlog() const {
        return _commitlog.get();
    }

    future<> init_from_data_directory();

    keyspace& add_keyspace(sstring name, keyspace k);
    /** Adds cf with auto-generated UUID. */
    void add_column_family(column_family&&);
    void add_column_family(const utils::UUID&, column_family&&);

    /* throws std::out_of_range if missing */
    const utils::UUID& find_uuid(const sstring& ks, const sstring& cf) const throw (std::out_of_range);
    const utils::UUID& find_uuid(const schema_ptr&) const throw (std::out_of_range);

    /* below, find* throws no_such_<type> on fail */
    keyspace& find_or_create_keyspace(const sstring& name);
    keyspace& find_keyspace(const sstring& name) throw (no_such_keyspace);
    const keyspace& find_keyspace(const sstring& name) const throw (no_such_keyspace);
    bool has_keyspace(const sstring& name) const;
    void update_keyspace(const sstring& name);
    void drop_keyspace(const sstring& name);
    column_family& find_column_family(const sstring& ks, const sstring& name) throw (no_such_column_family);
    const column_family& find_column_family(const sstring& ks, const sstring& name) const throw (no_such_column_family);
    column_family& find_column_family(const utils::UUID&) throw (no_such_column_family);
    const column_family& find_column_family(const utils::UUID&) const throw (no_such_column_family);
    column_family& find_column_family(const schema_ptr&) throw (no_such_column_family);
    const column_family& find_column_family(const schema_ptr&) const throw (no_such_column_family);
    schema_ptr find_schema(const sstring& ks_name, const sstring& cf_name) const throw (no_such_column_family);
    schema_ptr find_schema(const utils::UUID&) const throw (no_such_column_family);
    future<> stop();
    unsigned shard_of(const dht::token& t);
    unsigned shard_of(const mutation& m);
    unsigned shard_of(const frozen_mutation& m);
    future<lw_shared_ptr<query::result>> query(const query::read_command& cmd);
    future<> apply(const frozen_mutation&);
    keyspace::config make_keyspace_config(sstring name) const;
    friend std::ostream& operator<<(std::ostream& out, const database& db);
};

// FIXME: stub
class secondary_index_manager {};

inline
void
column_family::apply(const mutation& m) {
    active_memtable().apply(m);
    seal_on_overflow();
}

inline
void
column_family::seal_on_overflow() {
    // FIXME: something better
    if (++_mutation_count == 10000) {
        _mutation_count = 0;
        seal_active_memtable();
    }
}

inline
void
column_family::apply(const frozen_mutation& m) {
    active_memtable().apply(m);
    seal_on_overflow();
}

#endif /* DATABASE_HH_ */
<|endoftext|>


<commit_before>/*!
 * VerbalExpressions C++ Library v0.1
 * https://github.com/whackashoe/C++VerbalExpressions
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 whackashoe
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef VERBAL_EXPRESSIONS_H_
#define VERBAL_EXPRESSIONS_H_

#define USE_BOOST

#ifdef USE_BOOST
#include <boost/regex.hpp>
namespace veregex = boost;
#else
#include <regex>
namespace veregex = std;
#endif

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class VerEx {
private:
    std::string prefixes;
    std::string source;
    std::string suffixes;
    std::string pattern;
    enum Flags { GLOBAL = 1,
                 MULTILINE = 2,
                 CASEINSENSITIVE = 4 };

    friend std::ostream& operator<<(std::ostream &strm, VerEx &v) {
        return strm << v.pattern;
    }

    unsigned int checkFlags() {
        unsigned int result = 0;
        if(modifiers & CASEINSENSITIVE) result |= veregex::regex::icase;
        return result;
    }

    const std::string reduceLines(const std::string & value) {
        std::string ret = value;
        std::size_t pos = ret.find("\n");
        if(pos == std::string::npos) return ret;
        return ret.substr(0, pos);
    }

public:
    unsigned int modifiers;

    VerEx() : prefixes(""),
              source(""),
              suffixes(""),
              pattern(""),
              modifiers(0){};
    VerEx& operator=(const VerEx& ve) = default;
    ~VerEx() = default;

    VerEx & add(const std::string & value) {
        source = source + value;
        pattern = prefixes + source + suffixes;
        return (*this);
    }

    VerEx & startOfLine(bool enable) {
        prefixes = enable ? "^" : "";
        return add("");
    }

    inline VerEx & startOfLine() {
        return startOfLine(true);
    }

    VerEx & endOfLine(bool enable) {
        suffixes = enable ? "$" : "";
        return add("");
    }

    inline VerEx & endOfLine() {
        return endOfLine(true);
    }

    VerEx & then(const std::string & value) {
        return add("(?:" + value + ")");
    }

    VerEx & find(const std::string & value) {
        return then(value);
    }

    VerEx & maybe(const std::string & value) {
        return add("(?:" + value + ")?");
    }

    VerEx & anything() {
        return add("(?:.*)");
    }

    VerEx & anythingBut(const std::string & value) {
        return add("(?:[^" + value + "]*)");
    }

    VerEx & something() {
        return add("(?:.+)");
    }

    VerEx & somethingBut(const std::string & value) {
        return add("(?:[^" + value + "]+)");
    }

    const std::string replace(const std::string & source, const std::string & value) {
        return veregex::regex_replace(  source,
                                        veregex::regex(pattern, checkFlags()),
                                        value);
    }

    VerEx & lineBreak() {
        return add("(?:(?:\\n)|(?:\\r\\n))");
    }

    inline VerEx & br() {
        return lineBreak();
    }

    VerEx & tab() {
        return add("\\t");
    }

    VerEx & word() {
        return add("\\w+");
    }

    VerEx & anyOf(const std::string & value) {
        return add( "[" + value + "]" );
    }

    VerEx & any(const std::string & value) {
        return anyOf(value);
    }

    VerEx & range(std::vector<std::string> args) {
        std::stringstream value;
        value << "[";

        for(unsigned int _from = 0; _from < args.size(); _from += 2) {
            unsigned int _to = _from+1;
            if (args.size() <= _to) break;

            int from = atoi(args[_from].c_str());
            int to = atoi(args[_to].c_str());

            value << from << "-" << to;
        }

        value << "]";

        return add(value.str());
    }

    VerEx & addModifier(char modifier) {
        switch (modifier) {
            case 'i':
                modifiers |= CASEINSENSITIVE;
                break;
            case 'm':
                modifiers |= MULTILINE;
                break;
            case 'g':
                modifiers |= GLOBAL;
                break;
            default:
                break;
        }

        return (*this);
    }

    VerEx & removeModifier(char modifier) {
        switch (modifier) {
            case 'i':
                modifiers ^= CASEINSENSITIVE;
                break;
            case 'm':
                modifiers ^= MULTILINE;
                break;
            case 'g':
                modifiers ^= GLOBAL;
                break;
            default:
                break;
        }

        return (*this);
    }

    VerEx & withAnyCase(bool enable) {
        if (enable) addModifier( 'i' );
        else removeModifier( 'i' );
        return (*this);
    }

    inline VerEx & withAnyCase() {
        return withAnyCase(true);
    }

    VerEx & searchOneLine(bool enable) {
        if (enable) removeModifier( 'm' );
        else addModifier( 'm' );
        return (*this);
    }

    inline VerEx & searchOneLine() {
        return searchOneLine(true);
    }

    VerEx & searchGlobal(bool enable) {
        if (enable) addModifier( 'g' );
        else removeModifier( 'g' );
        return (*this);
    }

    inline VerEx & searchGlobal() {
        return searchGlobal(true);
    }

    VerEx & multiple(const std::string & value) {
        if(value.at(0) != '*' && value.at(0) != '+')
            add("+");

        return add(value);
    }

    VerEx & alt(const std::string & value) {
        if (prefixes.find("(") == std::string::npos) prefixes += "(";
        if (suffixes.find(")") == std::string::npos) suffixes = ")" + suffixes;

        add( ")|(" );
        return then(value);
    }

    bool test(const std::string & value) {
        std::string toTest;
        if(modifiers & MULTILINE) toTest = value;
        else                      toTest = reduceLines(value);

        if(modifiers & GLOBAL)
            return veregex::regex_search(toTest, boost::regex(pattern, checkFlags()));
        else
            return veregex::regex_match(toTest, boost::regex(pattern, checkFlags()));
    }
};

#endif
<commit_msg>change inner boost to alias<commit_after>/*!
 * VerbalExpressions C++ Library v0.1
 * https://github.com/whackashoe/C++VerbalExpressions
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 whackashoe
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef VERBAL_EXPRESSIONS_H_
#define VERBAL_EXPRESSIONS_H_

#define USE_BOOST

#ifdef USE_BOOST
#include <boost/regex.hpp>
namespace veregex = boost;
#else
#include <regex>
namespace veregex = std;
#endif

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class VerEx {
private:
    std::string prefixes;
    std::string source;
    std::string suffixes;
    std::string pattern;
    enum Flags { GLOBAL = 1,
                 MULTILINE = 2,
                 CASEINSENSITIVE = 4 };

    friend std::ostream& operator<<(std::ostream &strm, VerEx &v) {
        return strm << v.pattern;
    }

    unsigned int checkFlags() {
        unsigned int result = 0;
        if(modifiers & CASEINSENSITIVE) result |= veregex::regex::icase;
        return result;
    }

    const std::string reduceLines(const std::string & value) {
        std::string ret = value;
        std::size_t pos = ret.find("\n");
        if(pos == std::string::npos) return ret;
        return ret.substr(0, pos);
    }

public:
    unsigned int modifiers;

    VerEx() : prefixes(""),
              source(""),
              suffixes(""),
              pattern(""),
              modifiers(0){};
    VerEx& operator=(const VerEx& ve) = default;
    ~VerEx() = default;

    VerEx & add(const std::string & value) {
        source = source + value;
        pattern = prefixes + source + suffixes;
        return (*this);
    }

    VerEx & startOfLine(bool enable) {
        prefixes = enable ? "^" : "";
        return add("");
    }

    inline VerEx & startOfLine() {
        return startOfLine(true);
    }

    VerEx & endOfLine(bool enable) {
        suffixes = enable ? "$" : "";
        return add("");
    }

    inline VerEx & endOfLine() {
        return endOfLine(true);
    }

    VerEx & then(const std::string & value) {
        return add("(?:" + value + ")");
    }

    VerEx & find(const std::string & value) {
        return then(value);
    }

    VerEx & maybe(const std::string & value) {
        return add("(?:" + value + ")?");
    }

    VerEx & anything() {
        return add("(?:.*)");
    }

    VerEx & anythingBut(const std::string & value) {
        return add("(?:[^" + value + "]*)");
    }

    VerEx & something() {
        return add("(?:.+)");
    }

    VerEx & somethingBut(const std::string & value) {
        return add("(?:[^" + value + "]+)");
    }

    const std::string replace(const std::string & source, const std::string & value) {
        return veregex::regex_replace(  source,
                                        veregex::regex(pattern, checkFlags()),
                                        value);
    }

    VerEx & lineBreak() {
        return add("(?:(?:\\n)|(?:\\r\\n))");
    }

    inline VerEx & br() {
        return lineBreak();
    }

    VerEx & tab() {
        return add("\\t");
    }

    VerEx & word() {
        return add("\\w+");
    }

    VerEx & anyOf(const std::string & value) {
        return add( "[" + value + "]" );
    }

    VerEx & any(const std::string & value) {
        return anyOf(value);
    }

    VerEx & range(std::vector<std::string> args) {
        std::stringstream value;
        value << "[";

        for(unsigned int _from = 0; _from < args.size(); _from += 2) {
            unsigned int _to = _from+1;
            if (args.size() <= _to) break;

            int from = atoi(args[_from].c_str());
            int to = atoi(args[_to].c_str());

            value << from << "-" << to;
        }

        value << "]";

        return add(value.str());
    }

    VerEx & addModifier(char modifier) {
        switch (modifier) {
            case 'i':
                modifiers |= CASEINSENSITIVE;
                break;
            case 'm':
                modifiers |= MULTILINE;
                break;
            case 'g':
                modifiers |= GLOBAL;
                break;
            default:
                break;
        }

        return (*this);
    }

    VerEx & removeModifier(char modifier) {
        switch (modifier) {
            case 'i':
                modifiers ^= CASEINSENSITIVE;
                break;
            case 'm':
                modifiers ^= MULTILINE;
                break;
            case 'g':
                modifiers ^= GLOBAL;
                break;
            default:
                break;
        }

        return (*this);
    }

    VerEx & withAnyCase(bool enable) {
        if (enable) addModifier( 'i' );
        else removeModifier( 'i' );
        return (*this);
    }

    inline VerEx & withAnyCase() {
        return withAnyCase(true);
    }

    VerEx & searchOneLine(bool enable) {
        if (enable) removeModifier( 'm' );
        else addModifier( 'm' );
        return (*this);
    }

    inline VerEx & searchOneLine() {
        return searchOneLine(true);
    }

    VerEx & searchGlobal(bool enable) {
        if (enable) addModifier( 'g' );
        else removeModifier( 'g' );
        return (*this);
    }

    inline VerEx & searchGlobal() {
        return searchGlobal(true);
    }

    VerEx & multiple(const std::string & value) {
        if(value.at(0) != '*' && value.at(0) != '+')
            add("+");

        return add(value);
    }

    VerEx & alt(const std::string & value) {
        if (prefixes.find("(") == std::string::npos) prefixes += "(";
        if (suffixes.find(")") == std::string::npos) suffixes = ")" + suffixes;

        add( ")|(" );
        return then(value);
    }

    bool test(const std::string & value) {
        std::string toTest;
        if(modifiers & MULTILINE) toTest = value;
        else                      toTest = reduceLines(value);

        if(modifiers & GLOBAL)
            return veregex::regex_search(toTest, veregex::regex(pattern, checkFlags()));
        else
            return veregex::regex_match(toTest, veregex::regex(pattern, checkFlags()));
    }
};

#endif
<|endoftext|>


<commit_before>#include <util/Logger.h>
#include "ZoomView.h"

namespace gui {

static logger::LogChannel zoomviewlog("zoomviewlog", "[ZoomView] ");

ZoomView::ZoomView() :
		_scale(1.0),
		_shift(0.0, 0.0),
		_zoomStep(1.1) {

	registerInput(_content, "painter");
	registerOutput(_zoomed, "painter");

	_content.registerBackwardSlot(_update);
	_content.registerBackwardSlot(_keyDown);
	_content.registerBackwardSlot(_keyUp);
	_content.registerBackwardSlot(_mouseDown);
	_content.registerBackwardSlot(_mouseUp);
	_content.registerBackwardSlot(_mouseMove);
	_content.registerBackwardCallback(&ZoomView::onInputSet, this);
	_content.registerBackwardCallback(&ZoomView::onModified, this);
	_content.registerBackwardCallback(&ZoomView::onContentChanged, this);
	_content.registerBackwardCallback(&ZoomView::onSizeChanged, this);

	_zoomed.registerForwardSlot(_modified);
	_zoomed.registerForwardSlot(_contentChanged);
	_zoomed.registerForwardSlot(_sizeChanged);
	_zoomed.registerForwardCallback(&ZoomView::onUpdate, this);
	_zoomed.registerForwardCallback(&ZoomView::onKeyUp, this);
	_zoomed.registerForwardCallback(&ZoomView::onKeyDown, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseUp, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseDown, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseMove, this);
}

void
ZoomView::onInputSet(const pipeline::InputSet<Painter>& signal) {

	LOG_ALL(zoomviewlog) << "got a new painter" << std::endl;

	if (!_zoomed)
		_zoomed.createData();

	_zoomed->setContent(_content);

	_modified();
}

void
ZoomView::onModified(const pipeline::Modified& signal) {

	// just pass this signal on
	_modified();
}

void
ZoomView::onContentChanged(const ContentChanged& signal) {

	_contentChanged();
}

void
ZoomView::onSizeChanged(const SizeChanged& signal) {

	_zoomed->updateSize();

	_sizeChanged(SizeChanged(_zoomed->getSize()));
}

void
ZoomView::onUpdate(const pipeline::Update& signal) {

	_update(signal);

	_zoomed->setScale(_scale);
	_zoomed->setShift(_shift);
}

void
ZoomView::onKeyUp(const KeyUp& signal) {

	// pass on the signal
	_keyUp(signal);
}

void
ZoomView::onKeyDown(KeyDown& signal) {

	LOG_ALL(zoomviewlog) << "a key was pressed" << std::endl;

	if (signal.key == keys::R) {

		LOG_ALL(zoomviewlog) << "resetting scale and shift" << std::endl;

		_scale = 1.0;
		_shift = util::point<double>(0.0, 0.0);

		_modified();

		signal.processed = true;

	} else {

		_keyDown(signal);
	}
}

void
ZoomView::onMouseUp(const MouseUp& signal) {

	LOG_ALL(zoomviewlog) << "a button was released" << std::endl;

	MouseUp zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseUp(zoomedSignal);
}

void
ZoomView::onMouseDown(const MouseDown& signal) {

	LOG_ALL(zoomviewlog) << "a button was pressed" << std::endl;

	MouseDown zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseDown(zoomedSignal);

	if (zoomedSignal.processed)
		return;

	util::point<double> position = signal.position;

	LOG_ALL(zoomviewlog) << "mouse button " << signal.button << " down, position is " << position << std::endl;

	if (signal.button == buttons::Left) {

		LOG_ALL(zoomviewlog) << "it's the left mouse button -- start dragging mode" << std::endl;

		_dragging = true;
		_buttonDown = position;

		return;
	}

	// in the following, treat x and y zoom-corrected:
	position.x /= _scale;
	position.y /= _scale;

	// if control is pressed, increase zoom speed
	double zoomStep = _zoomStep;
	if (signal.modifiers & keys::ControlDown)
		zoomStep *= 2;

	// mouse wheel up
	if (signal.button == buttons::WheelUp) {

		LOG_ALL(zoomviewlog) << "it's the left wheel up" << std::endl;

		_scale *= zoomStep;
		_shift += position*(1.0/zoomStep - 1.0);

		LOG_ALL(zoomviewlog) << "mouse wheel up, new zoom "
							 << _scale << ", shift " << _shift
							 << ", position was " << position << std::endl;
	}

	// mouse wheel down
	if (signal.button == buttons::WheelDown) {

		LOG_ALL(zoomviewlog) << "it's the left wheel down" << std::endl;

		_scale *= 1.0/zoomStep;
		_shift += position*(zoomStep - 1.0);

		LOG_ALL(zoomviewlog) << "mouse wheel down, new zoom "
							 << _scale << ", shift " << _shift
							 << ", position was " << position << std::endl;
	}

	_modified();
}

void
ZoomView::onMouseMove(const MouseMove& signal) {

	LOG_ALL(zoomviewlog) << "the mouse is moved" << std::endl;

	MouseMove zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseMove(zoomedSignal);

	if (zoomedSignal.processed)
		return;

	if (!_dragging) {

		return;
	}

	LOG_ALL(zoomviewlog) << "I am in dragging mode" << std::endl;

	double amp = 1.0;
	if (signal.modifiers & keys::ControlDown)
		amp = 10.0;

	// mouse is dragged
	if (signal.modifiers & buttons::LeftDown) {

		LOG_ALL(zoomviewlog) << "left button is still pressed" << std::endl;

		util::point<double> moved = signal.position - _buttonDown;

		_shift += moved*amp/_scale;

		_buttonDown = signal.position;

		_zoomed->setShift(_shift);

		_modified();

	} else {

		LOG_ALL(zoomviewlog) << "left button released -- stop dragging" << std::endl;

		_dragging = false;
	}
}

} // namespace gui
<commit_msg>made ZoomView only react to mouse events if control is pressed<commit_after>#include <util/Logger.h>
#include "ZoomView.h"

namespace gui {

static logger::LogChannel zoomviewlog("zoomviewlog", "[ZoomView] ");

ZoomView::ZoomView() :
		_scale(1.0),
		_shift(0.0, 0.0),
		_zoomStep(1.1) {

	registerInput(_content, "painter");
	registerOutput(_zoomed, "painter");

	_content.registerBackwardSlot(_update);
	_content.registerBackwardSlot(_keyDown);
	_content.registerBackwardSlot(_keyUp);
	_content.registerBackwardSlot(_mouseDown);
	_content.registerBackwardSlot(_mouseUp);
	_content.registerBackwardSlot(_mouseMove);
	_content.registerBackwardCallback(&ZoomView::onInputSet, this);
	_content.registerBackwardCallback(&ZoomView::onModified, this);
	_content.registerBackwardCallback(&ZoomView::onContentChanged, this);
	_content.registerBackwardCallback(&ZoomView::onSizeChanged, this);

	_zoomed.registerForwardSlot(_modified);
	_zoomed.registerForwardSlot(_contentChanged);
	_zoomed.registerForwardSlot(_sizeChanged);
	_zoomed.registerForwardCallback(&ZoomView::onUpdate, this);
	_zoomed.registerForwardCallback(&ZoomView::onKeyUp, this);
	_zoomed.registerForwardCallback(&ZoomView::onKeyDown, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseUp, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseDown, this);
	_zoomed.registerForwardCallback(&ZoomView::onMouseMove, this);
}

void
ZoomView::onInputSet(const pipeline::InputSet<Painter>& signal) {

	LOG_ALL(zoomviewlog) << "got a new painter" << std::endl;

	if (!_zoomed)
		_zoomed.createData();

	_zoomed->setContent(_content);

	_modified();
}

void
ZoomView::onModified(const pipeline::Modified& signal) {

	// just pass this signal on
	_modified();
}

void
ZoomView::onContentChanged(const ContentChanged& signal) {

	_contentChanged();
}

void
ZoomView::onSizeChanged(const SizeChanged& signal) {

	_zoomed->updateSize();

	_sizeChanged(SizeChanged(_zoomed->getSize()));
}

void
ZoomView::onUpdate(const pipeline::Update& signal) {

	_update(signal);

	_zoomed->setScale(_scale);
	_zoomed->setShift(_shift);
}

void
ZoomView::onKeyUp(const KeyUp& signal) {

	// pass on the signal
	_keyUp(signal);
}

void
ZoomView::onKeyDown(KeyDown& signal) {

	LOG_ALL(zoomviewlog) << "a key was pressed" << std::endl;

	if (signal.key == keys::R) {

		LOG_ALL(zoomviewlog) << "resetting scale and shift" << std::endl;

		_scale = 1.0;
		_shift = util::point<double>(0.0, 0.0);

		_modified();

		signal.processed = true;

	} else {

		_keyDown(signal);
	}
}

void
ZoomView::onMouseUp(const MouseUp& signal) {

	LOG_ALL(zoomviewlog) << "a button was released" << std::endl;

	MouseUp zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseUp(zoomedSignal);
}

void
ZoomView::onMouseDown(const MouseDown& signal) {

	LOG_ALL(zoomviewlog) << "a button was pressed" << std::endl;

	MouseDown zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseDown(zoomedSignal);

	if (zoomedSignal.processed || !(signal.modifiers & keys::ControlDown))
		return;

	util::point<double> position = signal.position;

	LOG_ALL(zoomviewlog) << "mouse button " << signal.button << " down, position is " << position << std::endl;

	if (signal.button == buttons::Left) {

		LOG_ALL(zoomviewlog) << "it's the left mouse button -- start dragging mode" << std::endl;

		_dragging = true;
		_buttonDown = position;

		return;
	}

	// in the following, treat x and y zoom-corrected:
	position.x /= _scale;
	position.y /= _scale;

	// if shift is pressed, increase zoom speed
	double zoomStep = _zoomStep;
	if (signal.modifiers & keys::ShiftDown)
		zoomStep *= 2;

	// mouse wheel up
	if (signal.button == buttons::WheelUp) {

		LOG_ALL(zoomviewlog) << "it's the left wheel up" << std::endl;

		_scale *= zoomStep;
		_shift += position*(1.0/zoomStep - 1.0);

		LOG_ALL(zoomviewlog) << "mouse wheel up, new zoom "
							 << _scale << ", shift " << _shift
							 << ", position was " << position << std::endl;
	}

	// mouse wheel down
	if (signal.button == buttons::WheelDown) {

		LOG_ALL(zoomviewlog) << "it's the left wheel down" << std::endl;

		_scale *= 1.0/zoomStep;
		_shift += position*(zoomStep - 1.0);

		LOG_ALL(zoomviewlog) << "mouse wheel down, new zoom "
							 << _scale << ", shift " << _shift
							 << ", position was " << position << std::endl;
	}

	_modified();
}

void
ZoomView::onMouseMove(const MouseMove& signal) {

	LOG_ALL(zoomviewlog) << "the mouse is moved" << std::endl;

	MouseMove zoomedSignal = signal;
	zoomedSignal.position /= _scale;
	zoomedSignal.position -= _shift;

	_mouseMove(zoomedSignal);

	if (zoomedSignal.processed || !(signal.modifiers & keys::ControlDown))
		return;

	if (!_dragging) {

		return;
	}

	LOG_ALL(zoomviewlog) << "I am in dragging mode" << std::endl;

	double amp = 1.0;
	if (signal.modifiers & keys::ShiftDown)
		amp = 10.0;

	// mouse is dragged
	if (signal.modifiers & buttons::LeftDown) {

		LOG_ALL(zoomviewlog) << "left button is still pressed" << std::endl;

		util::point<double> moved = signal.position - _buttonDown;

		_shift += moved*amp/_scale;

		_buttonDown = signal.position;

		_zoomed->setShift(_shift);

		_modified();

	} else {

		LOG_ALL(zoomviewlog) << "left button released -- stop dragging" << std::endl;

		_dragging = false;
	}
}

} // namespace gui
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2018 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/format.hpp>
#include <sys/stat.h>
#include <libbio/fasta_reader.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/types.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {

	class delegate : public libbio::fasta_reader_delegate
	{
	protected:
		v2m::vector_type *m_reference{};
		char const *m_identifier{};
		bool m_found_seq{};

	public:
		delegate(v2m::vector_type &reference, char const *identifier):
			m_reference(&reference),
			m_identifier(identifier)
		{
		}

		virtual bool handle_comment_line(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			return true;
		}

		virtual bool handle_identifier(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			if (m_found_seq)
				return false;

			if ((!m_identifier) || sv == m_identifier)
			{
				m_found_seq = true;
				std::cerr << " reading sequence with identifier " << sv << "…" << std::flush;
			}

			return true;
		}

		virtual bool handle_sequence_line(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			if (!m_found_seq)
				return false;

			std::copy(sv.begin(), sv.end(), std::back_inserter(*m_reference));
			return true;
		}
	};
}

namespace vcf2multialign {

	// Read the contents of a FASTA file into a single sequence.
	void read_single_fasta_seq(lb::mmap_handle <char> &ref_fasta_handle, vector_type &reference, char const *ref_seq_name)
	{
		lb::fasta_reader reader;
		delegate cb(reference, ref_seq_name);

		std::cerr << "Reading reference FASTA into memory…";
		reader.parse(ref_fasta_handle, cb);
		std::cerr << " Done." << std::endl;
	}
}
<commit_msg>Output the reference length when done<commit_after>/*
 * Copyright (c) 2017-2018 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/format.hpp>
#include <sys/stat.h>
#include <libbio/fasta_reader.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/types.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {

	class delegate : public libbio::fasta_reader_delegate
	{
	protected:
		v2m::vector_type *m_reference{};
		char const *m_identifier{};
		bool m_found_seq{};

	public:
		delegate(v2m::vector_type &reference, char const *identifier):
			m_reference(&reference),
			m_identifier(identifier)
		{
		}

		virtual bool handle_comment_line(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			return true;
		}

		virtual bool handle_identifier(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			if (m_found_seq)
				return false;

			if ((!m_identifier) || sv == m_identifier)
			{
				m_found_seq = true;
				std::cerr << " reading sequence with identifier " << sv << "…" << std::flush;
			}

			return true;
		}

		virtual bool handle_sequence_line(lb::fasta_reader &reader, std::string_view const &sv) override
		{
			if (!m_found_seq)
				return false;

			std::copy(sv.begin(), sv.end(), std::back_inserter(*m_reference));
			return true;
		}
	};
}

namespace vcf2multialign {

	// Read the contents of a FASTA file into a single sequence.
	void read_single_fasta_seq(lb::mmap_handle <char> &ref_fasta_handle, vector_type &reference, char const *ref_seq_name)
	{
		lb::fasta_reader reader;
		delegate cb(reference, ref_seq_name);

		std::cerr << "Reading reference FASTA into memory…";
		reader.parse(ref_fasta_handle, cb);
		std::cerr << " Done. Reference length was " << reference.size() << '.' << std::endl;
	}
}
<|endoftext|>


<commit_before>#include "Geometry.hpp"
#include "Line.hpp"
#include "PolylineCollection.hpp"
#include "clipper.hpp"
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <vector>

#ifdef SLIC3R_DEBUG
#include "SVG.hpp"
#endif

using namespace boost::polygon;  // provides also high() and low()

namespace Slic3r { namespace Geometry {

static bool
sort_points (Point a, Point b)
{
    return (a.x < b.x) || (a.x == b.x && a.y < b.y);
}

/* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */
void
convex_hull(Points &points, Polygon* hull)
{
    assert(points.size() >= 3);
    // sort input points
    std::sort(points.begin(), points.end(), sort_points);

    int n = points.size(), k = 0;
    hull->points.resize(2*n);

    // Build lower hull
    for (int i = 0; i < n; i++) {
        while (k >= 2 && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--;
        hull->points[k++] = points[i];
    }

    // Build upper hull
    for (int i = n-2, t = k+1; i >= 0; i--) {
        while (k >= t && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--;
        hull->points[k++] = points[i];
    }

    hull->points.resize(k);

    assert( hull->points.front().coincides_with(hull->points.back()) );
    hull->points.pop_back();
}

/* accepts an arrayref of points and returns a list of indices
   according to a nearest-neighbor walk */
void
chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near)
{
    PointPtrs my_points;
    std::map<Point*,Points::size_type> indices;
    my_points.reserve(points.size());
    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
        my_points.push_back(&*it);
        indices[&*it] = it - points.begin();
    }

    retval.reserve(points.size());
    while (!my_points.empty()) {
        Points::size_type idx = start_near.nearest_point_index(my_points);
        start_near = *my_points[idx];
        retval.push_back(indices[ my_points[idx] ]);
        my_points.erase(my_points.begin() + idx);
    }
}

void
chained_path(Points &points, std::vector<Points::size_type> &retval)
{
    if (points.empty()) return;  // can't call front() on empty vector
    chained_path(points, retval, points.front());
}

/* retval and items must be different containers */
template<class T>
void
chained_path_items(Points &points, T &items, T &retval)
{
    std::vector<Points::size_type> indices;
    chained_path(points, indices);
    for (std::vector<Points::size_type>::const_iterator it = indices.begin(); it != indices.end(); ++it)
        retval.push_back(items[*it]);
}
template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval);

Line
MedialAxis::edge_to_line(const VD::edge_type &edge) {
    Line line;
    line.a.x = edge.vertex0()->x();
    line.a.y = edge.vertex0()->y();
    line.b.x = edge.vertex1()->x();
    line.b.y = edge.vertex1()->y();
    return line;
}

void
MedialAxis::build(Polylines* polylines)
{
    /*
    // build bounding box (we use it for clipping infinite segments)
    // --> we have no infinite segments
    this->bb = BoundingBox(this->lines);
    */

    construct_voronoi(this->lines.begin(), this->lines.end(), &this->vd);

    // collect valid edges (i.e. prune those not belonging to MAT)
    // note: this keeps twins, so it contains twice the number of the valid edges
    this->edges.clear();
    for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
        if (this->is_valid_edge(*edge)) this->edges.insert(&*edge);
    }

    // count valid segments for each vertex
    std::map< const VD::vertex_type*,std::list<const VD::edge_type*> > vertex_edges;
    std::list<const VD::vertex_type*> entry_nodes;
    for (VD::const_vertex_iterator vertex = this->vd.vertices().begin(); vertex != this->vd.vertices().end(); ++vertex) {
        // get a reference to the list of valid edges originating from this vertex
        std::list<const VD::edge_type*>& edges = vertex_edges[&*vertex];

        // get one random edge originating from this vertex
        const VD::edge_type* edge = vertex->incident_edge();
        do {
            if (this->edges.count(edge) > 0)    // only count valid edges
                edges.push_back(edge);
            edge = edge->rot_next();            // next edge originating from this vertex
        } while (edge != vertex->incident_edge());

        // if there's only one edge starting at this vertex then it's a leaf
        if (edges.size() == 1) entry_nodes.push_back(&*vertex);
    }

    // iterate through the leafs to prune short branches
    for (std::list<const VD::vertex_type*>::const_iterator vertex = entry_nodes.begin(); vertex != entry_nodes.end(); ++vertex) {
        const VD::vertex_type* v = *vertex;

        // start a polyline from this vertex
        Polyline polyline;
        polyline.points.push_back(Point(v->x(), v->y()));

        // keep track of visited edges to prevent infinite loops
        std::set<const VD::edge_type*> visited_edges;

        do {
            // get edge starting from v
            const VD::edge_type* edge = vertex_edges[v].front();

            // if we picked the edge going backwards (thus the twin of the previous edge)
            if (visited_edges.count(edge->twin()) > 0) {
                edge = vertex_edges[v].back();
            }

            // avoid getting twice on the same edge
            if (visited_edges.count(edge) > 0) break;
            visited_edges.insert(edge);

            // get ending vertex for this edge and append it to the polyline
            v = edge->vertex1();
            polyline.points.push_back(Point( v->x(), v->y() ));

            // if two edges start at this vertex (one forward one backwards) then
            // it's not branching and we can go on
        } while (vertex_edges[v].size() == 2);

        // if this branch is too short, invalidate all of its edges so that
        // they will be ignored when building actual polylines in the loop below
        if (polyline.length() < this->width) {
            for (std::set<const VD::edge_type*>::const_iterator edge = visited_edges.begin(); edge != visited_edges.end(); ++edge) {
                (void)this->edges.erase(*edge);
                (void)this->edges.erase((*edge)->twin());
            }
        }
    }

    // iterate through the valid edges to build polylines
    while (!this->edges.empty()) {
        const VD::edge_type& edge = **this->edges.begin();

        // start a polyline
        Polyline polyline;
        polyline.points.push_back(Point( edge.vertex0()->x(), edge.vertex0()->y() ));
        polyline.points.push_back(Point( edge.vertex1()->x(), edge.vertex1()->y() ));

        // remove this edge and its twin from the available edges
        (void)this->edges.erase(&edge);
        (void)this->edges.erase(edge.twin());

        // get next points
        this->process_edge_neighbors(edge, &polyline.points);

        // get previous points
        Points pp;
        this->process_edge_neighbors(*edge.twin(), &pp);
        polyline.points.insert(polyline.points.begin(), pp.rbegin(), pp.rend());

        // append polyline to result
        polylines->push_back(polyline);
    }
}

void
MedialAxis::process_edge_neighbors(const VD::edge_type& edge, Points* points)
{
    // Since rot_next() works on the edge starting point but we want
    // to find neighbors on the ending point, we just swap edge with
    // its twin.
    const VD::edge_type& twin = *edge.twin();

    // count neighbors for this edge
    std::vector<const VD::edge_type*> neighbors;
    for (const VD::edge_type* neighbor = twin.rot_next(); neighbor != &twin; neighbor = neighbor->rot_next()) {
        if (this->edges.count(neighbor) > 0) neighbors.push_back(neighbor);
    }

    // if we have a single neighbor then we can continue recursively
    if (neighbors.size() == 1) {
        const VD::edge_type& neighbor = *neighbors.front();
        points->push_back(Point( neighbor.vertex1()->x(), neighbor.vertex1()->y() ));
        (void)this->edges.erase(&neighbor);
        (void)this->edges.erase(neighbor.twin());
        this->process_edge_neighbors(neighbor, points);
    }
}

bool
MedialAxis::is_valid_edge(const VD::edge_type& edge) const
{
    // if we only process segments representing closed loops, none if the
    // infinite edges (if any) would be part of our MAT anyway
    if (edge.is_secondary() || edge.is_infinite()) return false;

    /* If the cells sharing this edge have a common vertex, we're not interested
       in this edge. Why? Because it means that the edge lies on the bisector of
       two contiguous input lines and it was included in the Voronoi graph because
       it's the locus of centers of circles tangent to both vertices. Due to the
       "thin" nature of our input, these edges will be very short and not part of
       our wanted output. The best way would be to just filter out the edges that
       are not the locus of the maximally inscribed disks (requirement of MAT)
       but I don't know how to do it. Maybe we could check the relative angle of
       the two segments (we are only interested in facing segments). */

    const VD::cell_type &cell1 = *edge.cell();
    const VD::cell_type &cell2 = *edge.twin()->cell();
    if (cell1.contains_segment() && cell2.contains_segment()) {
        Line segment1 = this->retrieve_segment(cell1);
        Line segment2 = this->retrieve_segment(cell2);
        if (segment1.a == segment2.b || segment1.b == segment2.a) return false;
        if (fabs(segment1.atan2_() - segment2.atan2_()) < PI/3) {
            //printf("segment1 atan2 = %f, segment2 atan2 = %f\n", segment1.atan2_(), segment2.atan2_());
            //printf("  => SAME ATAN2\n");
            return false;
        }
    }

    return true;
}

Line
MedialAxis::retrieve_segment(const VD::cell_type& cell) const
{
    VD::cell_type::source_index_type index = cell.source_index() - this->points.size();
    return this->lines[index];
}

} }
<commit_msg>Consider contour thickness when validating medial axis segments<commit_after>#include "Geometry.hpp"
#include "Line.hpp"
#include "PolylineCollection.hpp"
#include "clipper.hpp"
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <vector>

#ifdef SLIC3R_DEBUG
#include "SVG.hpp"
#endif

using namespace boost::polygon;  // provides also high() and low()

namespace Slic3r { namespace Geometry {

static bool
sort_points (Point a, Point b)
{
    return (a.x < b.x) || (a.x == b.x && a.y < b.y);
}

/* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */
void
convex_hull(Points &points, Polygon* hull)
{
    assert(points.size() >= 3);
    // sort input points
    std::sort(points.begin(), points.end(), sort_points);

    int n = points.size(), k = 0;
    hull->points.resize(2*n);

    // Build lower hull
    for (int i = 0; i < n; i++) {
        while (k >= 2 && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--;
        hull->points[k++] = points[i];
    }

    // Build upper hull
    for (int i = n-2, t = k+1; i >= 0; i--) {
        while (k >= t && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--;
        hull->points[k++] = points[i];
    }

    hull->points.resize(k);

    assert( hull->points.front().coincides_with(hull->points.back()) );
    hull->points.pop_back();
}

/* accepts an arrayref of points and returns a list of indices
   according to a nearest-neighbor walk */
void
chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near)
{
    PointPtrs my_points;
    std::map<Point*,Points::size_type> indices;
    my_points.reserve(points.size());
    for (Points::iterator it = points.begin(); it != points.end(); ++it) {
        my_points.push_back(&*it);
        indices[&*it] = it - points.begin();
    }

    retval.reserve(points.size());
    while (!my_points.empty()) {
        Points::size_type idx = start_near.nearest_point_index(my_points);
        start_near = *my_points[idx];
        retval.push_back(indices[ my_points[idx] ]);
        my_points.erase(my_points.begin() + idx);
    }
}

void
chained_path(Points &points, std::vector<Points::size_type> &retval)
{
    if (points.empty()) return;  // can't call front() on empty vector
    chained_path(points, retval, points.front());
}

/* retval and items must be different containers */
template<class T>
void
chained_path_items(Points &points, T &items, T &retval)
{
    std::vector<Points::size_type> indices;
    chained_path(points, indices);
    for (std::vector<Points::size_type>::const_iterator it = indices.begin(); it != indices.end(); ++it)
        retval.push_back(items[*it]);
}
template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval);

Line
MedialAxis::edge_to_line(const VD::edge_type &edge) {
    Line line;
    line.a.x = edge.vertex0()->x();
    line.a.y = edge.vertex0()->y();
    line.b.x = edge.vertex1()->x();
    line.b.y = edge.vertex1()->y();
    return line;
}

void
MedialAxis::build(Polylines* polylines)
{
    /*
    // build bounding box (we use it for clipping infinite segments)
    // --> we have no infinite segments
    this->bb = BoundingBox(this->lines);
    */

    construct_voronoi(this->lines.begin(), this->lines.end(), &this->vd);

    // collect valid edges (i.e. prune those not belonging to MAT)
    // note: this keeps twins, so it contains twice the number of the valid edges
    this->edges.clear();
    for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
        if (this->is_valid_edge(*edge)) this->edges.insert(&*edge);
    }

    // count valid segments for each vertex
    std::map< const VD::vertex_type*,std::list<const VD::edge_type*> > vertex_edges;
    std::list<const VD::vertex_type*> entry_nodes;
    for (VD::const_vertex_iterator vertex = this->vd.vertices().begin(); vertex != this->vd.vertices().end(); ++vertex) {
        // get a reference to the list of valid edges originating from this vertex
        std::list<const VD::edge_type*>& edges = vertex_edges[&*vertex];

        // get one random edge originating from this vertex
        const VD::edge_type* edge = vertex->incident_edge();
        do {
            if (this->edges.count(edge) > 0)    // only count valid edges
                edges.push_back(edge);
            edge = edge->rot_next();            // next edge originating from this vertex
        } while (edge != vertex->incident_edge());

        // if there's only one edge starting at this vertex then it's a leaf
        if (edges.size() == 1) entry_nodes.push_back(&*vertex);
    }

    // iterate through the leafs to prune short branches
    for (std::list<const VD::vertex_type*>::const_iterator vertex = entry_nodes.begin(); vertex != entry_nodes.end(); ++vertex) {
        const VD::vertex_type* v = *vertex;

        // start a polyline from this vertex
        Polyline polyline;
        polyline.points.push_back(Point(v->x(), v->y()));

        // keep track of visited edges to prevent infinite loops
        std::set<const VD::edge_type*> visited_edges;

        do {
            // get edge starting from v
            const VD::edge_type* edge = vertex_edges[v].front();

            // if we picked the edge going backwards (thus the twin of the previous edge)
            if (visited_edges.count(edge->twin()) > 0) {
                edge = vertex_edges[v].back();
            }

            // avoid getting twice on the same edge
            if (visited_edges.count(edge) > 0) break;
            visited_edges.insert(edge);

            // get ending vertex for this edge and append it to the polyline
            v = edge->vertex1();
            polyline.points.push_back(Point( v->x(), v->y() ));

            // if two edges start at this vertex (one forward one backwards) then
            // it's not branching and we can go on
        } while (vertex_edges[v].size() == 2);

        // if this branch is too short, invalidate all of its edges so that
        // they will be ignored when building actual polylines in the loop below
        if (polyline.length() < this->width) {
            for (std::set<const VD::edge_type*>::const_iterator edge = visited_edges.begin(); edge != visited_edges.end(); ++edge) {
                (void)this->edges.erase(*edge);
                (void)this->edges.erase((*edge)->twin());
            }
        }
    }

    // iterate through the valid edges to build polylines
    while (!this->edges.empty()) {
        const VD::edge_type& edge = **this->edges.begin();

        // start a polyline
        Polyline polyline;
        polyline.points.push_back(Point( edge.vertex0()->x(), edge.vertex0()->y() ));
        polyline.points.push_back(Point( edge.vertex1()->x(), edge.vertex1()->y() ));

        // remove this edge and its twin from the available edges
        (void)this->edges.erase(&edge);
        (void)this->edges.erase(edge.twin());

        // get next points
        this->process_edge_neighbors(edge, &polyline.points);

        // get previous points
        Points pp;
        this->process_edge_neighbors(*edge.twin(), &pp);
        polyline.points.insert(polyline.points.begin(), pp.rbegin(), pp.rend());

        // append polyline to result
        polylines->push_back(polyline);
    }
}

void
MedialAxis::process_edge_neighbors(const VD::edge_type& edge, Points* points)
{
    // Since rot_next() works on the edge starting point but we want
    // to find neighbors on the ending point, we just swap edge with
    // its twin.
    const VD::edge_type& twin = *edge.twin();

    // count neighbors for this edge
    std::vector<const VD::edge_type*> neighbors;
    for (const VD::edge_type* neighbor = twin.rot_next(); neighbor != &twin; neighbor = neighbor->rot_next()) {
        if (this->edges.count(neighbor) > 0) neighbors.push_back(neighbor);
    }

    // if we have a single neighbor then we can continue recursively
    if (neighbors.size() == 1) {
        const VD::edge_type& neighbor = *neighbors.front();
        points->push_back(Point( neighbor.vertex1()->x(), neighbor.vertex1()->y() ));
        (void)this->edges.erase(&neighbor);
        (void)this->edges.erase(neighbor.twin());
        this->process_edge_neighbors(neighbor, points);
    }
}

bool
MedialAxis::is_valid_edge(const VD::edge_type& edge) const
{
    // if we only process segments representing closed loops, none if the
    // infinite edges (if any) would be part of our MAT anyway
    if (edge.is_secondary() || edge.is_infinite()) return false;

    /* If the cells sharing this edge have a common vertex, we're not interested
       in this edge. Why? Because it means that the edge lies on the bisector of
       two contiguous input lines and it was included in the Voronoi graph because
       it's the locus of centers of circles tangent to both vertices. Due to the
       "thin" nature of our input, these edges will be very short and not part of
       our wanted output. The best way would be to just filter out the edges that
       are not the locus of the maximally inscribed disks (requirement of MAT)
       but I don't know how to do it. Maybe we could check the relative angle of
       the two segments (we are only interested in facing segments). */

    const VD::cell_type &cell1 = *edge.cell();
    const VD::cell_type &cell2 = *edge.twin()->cell();
    if (cell1.contains_segment() && cell2.contains_segment()) {
        Line segment1 = this->retrieve_segment(cell1);
        Line segment2 = this->retrieve_segment(cell2);
        if (segment1.a == segment2.b || segment1.b == segment2.a) return false;
        if (fabs(segment1.atan2_() - segment2.atan2_()) < PI/3) return false;

        // we can assume that distance between any of the vertices and any of the cell segments
        // is about the same
        Point p0( edge.vertex0()->x(), edge.vertex0()->y() );
        double dist = p0.distance_to(segment1);

        // if distance between this edge and the thin area boundary is greater
        // than half the max width, then it's not a true medial axis segment;
        // if it's too small then it's not suitable for extrusion since it would
        // exceed the desired shape too much (this also traps some very narrow
        // areas caused by collapsing/mitering that we should ignore)
        if (dist > this->width/2 || dist < this->width/10) return false;
    }

    return true;
}

Line
MedialAxis::retrieve_segment(const VD::cell_type& cell) const
{
    VD::cell_type::source_index_type index = cell.source_index() - this->points.size();
    return this->lines[index];
}

} }
<|endoftext|>