<commit_before>#include "snarls.hpp"
#include "hash_map.hpp"
using namespace sdsl;
namespace vg {

class DistanceIndex {

    /*The distance index. Used for calculation of the minimum distance between
       two positions and for a maximum distance estimation. The maximum distance
       estimation is at least as large as the maximum distance between two
       positions up to a specified cap*/

    public:
    //Constructor
    DistanceIndex (HandleGraph* vg, SnarlManager* snarlManager, uint64_t cap);

    //Constructor to load index from serialization
    DistanceIndex (HandleGraph* vg, SnarlManager* snarlManager, istream& in);

    //Serialize object into out
    void serialize(ostream& out);

    //Load serialized object from in
    void load(istream& in);

    /*Get the minimum distance between two positions
      pos1 must be on a node contained in snarl1 and not on any children of
      snarl1. The same for pos2 and snarl2
    */
    int64_t minDistance( pos_t pos1, pos_t pos2);
    int64_t minDistance(
         const Snarl* snarl1, const Snarl* snarl2, pos_t pos1, pos_t pos2);

    /*Get an upper bound of the distance between two positions */
    int64_t maxDistance(pos_t pos1, pos_t pos2);

    //Helper function to find the minimum value that is not -1
    static int64_t minPos(vector<int64_t> vals);

    //Given a node, find the snarl containing it
    const Snarl* snarlOf(id_t nodeID);

    protected:
    void printSelf();
    class SnarlIndex {

        /* Stores distance information for nodes in a snarl.
           visitToIndex maps each visit (node_id, negative if reverse) to an int
           distances stores all the distance bewteen each pair of visits in a
           snarl
        */

        public:

            //Constructor
            SnarlIndex(DistanceIndex* di,
                          unordered_set<pair<id_t, bool>>& allNodes,
                          pair<id_t, bool> start, pair<id_t, bool> end);

            //Construct from vector - inverse of toVector
            SnarlIndex(DistanceIndex* di, vector<int64_t> v);

            /*Store contents of object as a vector of ints for serialization
              Stored as [# nodes, start node id, end node id, snarl length] +
                        [visit to index as list of node ids in order of index] +
                        [distances]
            */
            vector<int64_t>  toVector();

            //Distance between beginning of node start and beginning of node end
            //Only works for nodes heading their chains (which represent the chains), or snarl boundaries.
            int64_t snarlDistance(HandleGraph* graph,NetGraph* ng,pair<id_t, bool> start,
                                                         pair<id_t, bool> end);

            //Distance between end of node start and beginning of node end
            //Only works for nodes heading their chains (which represent the chains), or snarl boundaries.
            int64_t snarlDistanceShort(pair<id_t, bool> start,
                                       pair<id_t, bool> end);

            //Add the distance from start to end to the index
            void insertDistance(pair<id_t, bool> start, pair<id_t, bool> curr,
                     int64_t dist);

            //Length of a node
            int64_t nodeLength(HandleGraph*graph, NetGraph* ng,  id_t node);

            //Total length of the snarl
            int64_t snarlLength(HandleGraph* graph, NetGraph* ng);

            /*Given distances from a position to either end of a node, find the
              shortest distance from that position to the start and end nodes of
              the snarl
            */
            pair<int64_t, int64_t> distToEnds(HandleGraph* graph, NetGraph* ng,
                             id_t node, bool rev, int64_t distL, int64_t distR);

            void printSelf();

        protected:

            //Maps node to index to get its distance
            hash_map< pair<id_t, bool>, size_t> visitToIndex;

             /*Store the distance between every pair nodes, -1 indicates no path
             For child snarls that are unary or only connected to one node
             in the snarl, distances between that node leaving the snarl
             and any other node is -1
             */
            int_vector<> distances;

            //ID of the first node in the snarl, also key for distance index
            pair<id_t, bool> snarlStart;

            //End facing out of snarl
            pair<id_t, bool> snarlEnd;

            //The index into distances for distance start->end
            size_t index(pair<id_t, bool> start, pair<id_t, bool> end);

        private:
            DistanceIndex* distIndex;

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    class ChainIndex {
        /*Stores distances between snarls in a chain*/

        public:

            //Constructor
            ChainIndex(hash_map<id_t, size_t> s, vector<int64_t> p,
                        vector<int64_t> fd, vector<int64_t> rev );

            //Constructor from vector of ints after serialization
            ChainIndex(vector<int64_t> v);

            /*Convert contents into vector of ints for serialization
               stored as [node_id1, prefixsum1 start, prefixsum1 end,
                          loopfd1, loopfd2, node_id2, ...]
            */
            vector<int64_t> toVector();

            /**
             * Distance between two node sides in a chain. id_t values specify
             * the nodes, and bool values specify the sides. Side orientations
             * are relative to the node's orientation *in the chain*, so if
             * reading through the chain in its forward orientation you
             * encounter the node in reverse, then true is the *left* side of
             * the node and false is the *right* side.
             */
            int64_t chainDistance(pair<id_t, bool> start, pair<id_t, bool> end);

            /**
             * Takes the graph and two node sides, with orientations specified
             * relative to the nodes' orientation in their chain (i.e. nodes
             * backward in the chain have false represent the *end* of the
             * node).
             *
             * Returns the distance from the **opposite** side of the start
             * node to the specified side of the end node.
             */
            int64_t chainDistanceShort(HandleGraph* graph, pair<id_t, bool> start,
                                                  pair<id_t, bool> end);
            //Length of entire chain
            int64_t chainLength();

            /* Given the distance from a position to either end of a snarl in
               the chain, find the shortest distance from the position to
               either end of the chain
            */
            pair<int64_t, int64_t> distToEnds(pair<id_t, bool> start,
                                              int64_t distL, int64_t distR);
            void printSelf();

        protected:

            hash_map<id_t, size_t> snarlToIndex;

            /*Dist from start of chain to start and end of each boundary node of
              all snarls in the chain*/
            int_vector<> prefixSum;

            /*For each boundary node of snarls in the chain, the distance
               from the start of the node traversing forward to the end of
               the same node traversing backwards*/
            int_vector<> loopFd;

            /*For each boundary node of snarls in the chain, the distance
               from the end of the node traversing backward to the start of
               the same node traversing forward*/

            int_vector<> loopRev;

            /*Helper function for finding distances*/
            int64_t chainDistanceHelper(pair<size_t, bool> start,
                                   pair<size_t, bool> end, bool recurse = true);

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    class MaxDistanceIndex {
        //Index for calculating the maximum distance between two points
        public:

            //Constructor
            MaxDistanceIndex();
            MaxDistanceIndex(DistanceIndex* di, const vector<const Snarl*> chain,
                                                                uint64_t cap);

            //Actual distance function for finding upper bound for distance
            int64_t maxDistance( pos_t pos1, pos_t pos2);

//TODO: Finish testing        protected:
            int_vector<> nodeToComponent;//Maps each node to its connected component
            int_vector<> minDistances;   //Min and max distances to
            int_vector<> maxDistances;   //sink nodes in topological order
            uint64_t numCycles;         //Number of cyclic connected components
            uint64_t numComponents;     //Number of connected components
            uint64_t cap;               //Maximum distance to be considered

            void printSelf();

        private:
            //Helper functions for constructor
            //Assign each node to a connected component of cycles
            DistanceIndex* distIndex;
            uint64_t findComponents( int_vector<>& nodeToComponent,
                             int_vector<>& maxDists, int_vector<>& minDistsFd,
                             int_vector<>& minDistsRev,
                             uint64_t currComponent, bool onlyCycles          );
            //Populate minDistances and maxDistances
            void calculateMaxDistances(unordered_set<pair<id_t, bool>>& sinkNodes,
                      int_vector<>& nodeToComponent,int_vector<>& maxDists,
                      int_vector<>& minDistsFd, int_vector<>& minDistsRev);

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    int64_t sizeOf();
    ///////// Data members of overall index

    //map each node to connected component for max distance estimation
    hash_map<id_t, size_t> nodeToCycles;

    //map from start node of a snarl to its index
    unordered_map<pair<id_t, bool>, SnarlIndex> snarlDistances;

    //map from node id of first node in snarl to that chain's index
    hash_map<id_t, ChainIndex> chainDistances;

    //Graph and snarl manager for this index
    HandleGraph* graph;

    SnarlManager* sm;

    /*Index to find the snarl containing a node
      The start node id of the snarl containing each node - negative if
       the start node is reverse
    TODO: Maybe put this somewhere else*/
    dac_vector<> nodeToSnarl;
    id_t minNodeID; //minimum node id of the graph
    id_t maxNodeID; //maximum node id of the graph

//    MaxDistanceIndex maxIndex;

    ////// Private helper functions

    //Helper function for constructor - populate the minimum distance index
    int64_t calculateMinIndex(const Chain* chain);

    //Helper function for constructor - populate node to snarl
    int_vector<> calculateNodeToSnarl(SnarlManager* sm);

    //Flag each node with true if it is in a cycle that has minimum length
    //smaller than cap
    void flagCycles(const Snarl* snarl, bit_vector& inCycle,
                    uint64_t cap);

    //Minimum distance of a loop that involves node
    int64_t loopDistance(pair<id_t, bool> node1, pair<id_t, bool> node2);
    int64_t loopDistance( const Snarl* snarl1, const Snarl* snarl2,
                          pair<id_t, bool> node1, pair<id_t, bool> node2);

    /*Helper function for distance calculation
      Returns the distance to the start of and end of the child snarl of
      common ancestor containing snarl, commonAncestor if snarl is
      the common ancestor
    */
    pair<pair<int64_t, int64_t>, const Snarl*> distToCommonAncestor(
                const Snarl* snarl, const Snarl* commonAncestor, pos_t& pos);

    // Methods for testing
    int64_t checkChainDist(id_t snarl, size_t index);
    int64_t checkChainLoopFd(id_t snarl, size_t index);
    int64_t checkChainLoopRev(id_t snarl, size_t index);
    friend class SnarlIndex;
    friend class ChainIndex;
    friend class TestDistanceIndex;

};

}
<commit_msg>add include guards to distance.hpp<commit_after>#ifndef VG_DISTANCE_HPP_INCLUDED
#define VG_DISTANCE_HPP_INCLUDED

#include "snarls.hpp"
#include "hash_map.hpp"
using namespace sdsl;
namespace vg {

class DistanceIndex {

    /*The distance index. Used for calculation of the minimum distance between
       two positions and for a maximum distance estimation. The maximum distance
       estimation is at least as large as the maximum distance between two
       positions up to a specified cap*/

    public:
    //Constructor
    DistanceIndex (HandleGraph* vg, SnarlManager* snarlManager, uint64_t cap);

    //Constructor to load index from serialization
    DistanceIndex (HandleGraph* vg, SnarlManager* snarlManager, istream& in);

    //Serialize object into out
    void serialize(ostream& out);

    //Load serialized object from in
    void load(istream& in);

    /*Get the minimum distance between two positions
      pos1 must be on a node contained in snarl1 and not on any children of
      snarl1. The same for pos2 and snarl2
    */
    int64_t minDistance( pos_t pos1, pos_t pos2);
    int64_t minDistance(
         const Snarl* snarl1, const Snarl* snarl2, pos_t pos1, pos_t pos2);

    /*Get an upper bound of the distance between two positions */
    int64_t maxDistance(pos_t pos1, pos_t pos2);

    //Helper function to find the minimum value that is not -1
    static int64_t minPos(vector<int64_t> vals);

    //Given a node, find the snarl containing it
    const Snarl* snarlOf(id_t nodeID);

    protected:
    void printSelf();
    class SnarlIndex {

        /* Stores distance information for nodes in a snarl.
           visitToIndex maps each visit (node_id, negative if reverse) to an int
           distances stores all the distance bewteen each pair of visits in a
           snarl
        */

        public:

            //Constructor
            SnarlIndex(DistanceIndex* di,
                          unordered_set<pair<id_t, bool>>& allNodes,
                          pair<id_t, bool> start, pair<id_t, bool> end);

            //Construct from vector - inverse of toVector
            SnarlIndex(DistanceIndex* di, vector<int64_t> v);

            /*Store contents of object as a vector of ints for serialization
              Stored as [# nodes, start node id, end node id, snarl length] +
                        [visit to index as list of node ids in order of index] +
                        [distances]
            */
            vector<int64_t>  toVector();

            //Distance between beginning of node start and beginning of node end
            //Only works for nodes heading their chains (which represent the chains), or snarl boundaries.
            int64_t snarlDistance(HandleGraph* graph,NetGraph* ng,pair<id_t, bool> start,
                                                         pair<id_t, bool> end);

            //Distance between end of node start and beginning of node end
            //Only works for nodes heading their chains (which represent the chains), or snarl boundaries.
            int64_t snarlDistanceShort(pair<id_t, bool> start,
                                       pair<id_t, bool> end);

            //Add the distance from start to end to the index
            void insertDistance(pair<id_t, bool> start, pair<id_t, bool> curr,
                     int64_t dist);

            //Length of a node
            int64_t nodeLength(HandleGraph*graph, NetGraph* ng,  id_t node);

            //Total length of the snarl
            int64_t snarlLength(HandleGraph* graph, NetGraph* ng);

            /*Given distances from a position to either end of a node, find the
              shortest distance from that position to the start and end nodes of
              the snarl
            */
            pair<int64_t, int64_t> distToEnds(HandleGraph* graph, NetGraph* ng,
                             id_t node, bool rev, int64_t distL, int64_t distR);

            void printSelf();

        protected:

            //Maps node to index to get its distance
            hash_map< pair<id_t, bool>, size_t> visitToIndex;

             /*Store the distance between every pair nodes, -1 indicates no path
             For child snarls that are unary or only connected to one node
             in the snarl, distances between that node leaving the snarl
             and any other node is -1
             */
            int_vector<> distances;

            //ID of the first node in the snarl, also key for distance index
            pair<id_t, bool> snarlStart;

            //End facing out of snarl
            pair<id_t, bool> snarlEnd;

            //The index into distances for distance start->end
            size_t index(pair<id_t, bool> start, pair<id_t, bool> end);

        private:
            DistanceIndex* distIndex;

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    class ChainIndex {
        /*Stores distances between snarls in a chain*/

        public:

            //Constructor
            ChainIndex(hash_map<id_t, size_t> s, vector<int64_t> p,
                        vector<int64_t> fd, vector<int64_t> rev );

            //Constructor from vector of ints after serialization
            ChainIndex(vector<int64_t> v);

            /*Convert contents into vector of ints for serialization
               stored as [node_id1, prefixsum1 start, prefixsum1 end,
                          loopfd1, loopfd2, node_id2, ...]
            */
            vector<int64_t> toVector();

            /**
             * Distance between two node sides in a chain. id_t values specify
             * the nodes, and bool values specify the sides. Side orientations
             * are relative to the node's orientation *in the chain*, so if
             * reading through the chain in its forward orientation you
             * encounter the node in reverse, then true is the *left* side of
             * the node and false is the *right* side.
             */
            int64_t chainDistance(pair<id_t, bool> start, pair<id_t, bool> end);

            /**
             * Takes the graph and two node sides, with orientations specified
             * relative to the nodes' orientation in their chain (i.e. nodes
             * backward in the chain have false represent the *end* of the
             * node).
             *
             * Returns the distance from the **opposite** side of the start
             * node to the specified side of the end node.
             */
            int64_t chainDistanceShort(HandleGraph* graph, pair<id_t, bool> start,
                                                  pair<id_t, bool> end);
            //Length of entire chain
            int64_t chainLength();

            /* Given the distance from a position to either end of a snarl in
               the chain, find the shortest distance from the position to
               either end of the chain
            */
            pair<int64_t, int64_t> distToEnds(pair<id_t, bool> start,
                                              int64_t distL, int64_t distR);
            void printSelf();

        protected:

            hash_map<id_t, size_t> snarlToIndex;

            /*Dist from start of chain to start and end of each boundary node of
              all snarls in the chain*/
            int_vector<> prefixSum;

            /*For each boundary node of snarls in the chain, the distance
               from the start of the node traversing forward to the end of
               the same node traversing backwards*/
            int_vector<> loopFd;

            /*For each boundary node of snarls in the chain, the distance
               from the end of the node traversing backward to the start of
               the same node traversing forward*/

            int_vector<> loopRev;

            /*Helper function for finding distances*/
            int64_t chainDistanceHelper(pair<size_t, bool> start,
                                   pair<size_t, bool> end, bool recurse = true);

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    class MaxDistanceIndex {
        //Index for calculating the maximum distance between two points
        public:

            //Constructor
            MaxDistanceIndex();
            MaxDistanceIndex(DistanceIndex* di, const vector<const Snarl*> chain,
                                                                uint64_t cap);

            //Actual distance function for finding upper bound for distance
            int64_t maxDistance( pos_t pos1, pos_t pos2);

//TODO: Finish testing        protected:
            int_vector<> nodeToComponent;//Maps each node to its connected component
            int_vector<> minDistances;   //Min and max distances to
            int_vector<> maxDistances;   //sink nodes in topological order
            uint64_t numCycles;         //Number of cyclic connected components
            uint64_t numComponents;     //Number of connected components
            uint64_t cap;               //Maximum distance to be considered

            void printSelf();

        private:
            //Helper functions for constructor
            //Assign each node to a connected component of cycles
            DistanceIndex* distIndex;
            uint64_t findComponents( int_vector<>& nodeToComponent,
                             int_vector<>& maxDists, int_vector<>& minDistsFd,
                             int_vector<>& minDistsRev,
                             uint64_t currComponent, bool onlyCycles          );
            //Populate minDistances and maxDistances
            void calculateMaxDistances(unordered_set<pair<id_t, bool>>& sinkNodes,
                      int_vector<>& nodeToComponent,int_vector<>& maxDists,
                      int_vector<>& minDistsFd, int_vector<>& minDistsRev);

        friend class DistanceIndex;
        friend class TestDistanceIndex;
    };

    int64_t sizeOf();
    ///////// Data members of overall index

    //map each node to connected component for max distance estimation
    hash_map<id_t, size_t> nodeToCycles;

    //map from start node of a snarl to its index
    unordered_map<pair<id_t, bool>, SnarlIndex> snarlDistances;

    //map from node id of first node in snarl to that chain's index
    hash_map<id_t, ChainIndex> chainDistances;

    //Graph and snarl manager for this index
    HandleGraph* graph;

    SnarlManager* sm;

    /*Index to find the snarl containing a node
      The start node id of the snarl containing each node - negative if
       the start node is reverse
    TODO: Maybe put this somewhere else*/
    dac_vector<> nodeToSnarl;
    id_t minNodeID; //minimum node id of the graph
    id_t maxNodeID; //maximum node id of the graph

//    MaxDistanceIndex maxIndex;

    ////// Private helper functions

    //Helper function for constructor - populate the minimum distance index
    int64_t calculateMinIndex(const Chain* chain);

    //Helper function for constructor - populate node to snarl
    int_vector<> calculateNodeToSnarl(SnarlManager* sm);

    //Flag each node with true if it is in a cycle that has minimum length
    //smaller than cap
    void flagCycles(const Snarl* snarl, bit_vector& inCycle,
                    uint64_t cap);

    //Minimum distance of a loop that involves node
    int64_t loopDistance(pair<id_t, bool> node1, pair<id_t, bool> node2);
    int64_t loopDistance( const Snarl* snarl1, const Snarl* snarl2,
                          pair<id_t, bool> node1, pair<id_t, bool> node2);

    /*Helper function for distance calculation
      Returns the distance to the start of and end of the child snarl of
      common ancestor containing snarl, commonAncestor if snarl is
      the common ancestor
    */
    pair<pair<int64_t, int64_t>, const Snarl*> distToCommonAncestor(
                const Snarl* snarl, const Snarl* commonAncestor, pos_t& pos);

    // Methods for testing
    int64_t checkChainDist(id_t snarl, size_t index);
    int64_t checkChainLoopFd(id_t snarl, size_t index);
    int64_t checkChainLoopRev(id_t snarl, size_t index);
    friend class SnarlIndex;
    friend class ChainIndex;
    friend class TestDistanceIndex;

};

}

#endif
<|endoftext|>


<commit_before>#include <catch/catch.hpp>

#include <vili/parser/parser.hpp>

TEST_CASE("Inline object")
{
    SECTION("Simple object")
    {
        vili::node root
            = vili::parser::from_string("object: {a: 15, b: [16, 17], c: \"18\"}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array { 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Empty object")
    {
        vili::node root
            = vili::parser::from_string("object: {}");
        REQUIRE(root["object"].empty());
    }
}

TEST_CASE("Multiline object")
{
    SECTION("Empty object")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "   \n"
            "  }");
        REQUIRE(root["object"].empty());
    }

    SECTION("Comma separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15, b: [16, 17], c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Newline separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Mixed separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Eol and spaces")
    {
        vili::node root = vili::parser::from_string(
            "object:     {  \n"
            "    a: 15  \n"
            "        ,    \n"
            "b: [16, 17]  \n"
            "\n"
            "   c: \"18\"       \n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

}

TEST_CASE("Nested objects")
{
    SECTION("One object inside object")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: {\n"
            "a: 16, b: 17},\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"]["a"].as<vili::integer>() == 16);
        REQUIRE(root["object"]["b"]["b"].as<vili::integer>() == 17);
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }
}

TEST_CASE("Incorrect object")
{
    SECTION("Missing closing bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"),
        vili::exceptions::parsing_error);
    }

    SECTION("Missing opening bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: \n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Comma after last element")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Missing comma")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17] c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Newline after opening bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: \n"
            "{\n"
            "a: 15,\n"
            "b: [16, 17] c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }
}<commit_msg>changed test title<commit_after>#include <catch/catch.hpp>

#include <vili/parser/parser.hpp>

TEST_CASE("Inline object")
{
    SECTION("Simple object")
    {
        vili::node root
            = vili::parser::from_string("object: {a: 15, b: [16, 17], c: \"18\"}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array { 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Empty object")
    {
        vili::node root
            = vili::parser::from_string("object: {}");
        REQUIRE(root["object"].empty());
    }
}

TEST_CASE("Multiline object")
{
    SECTION("Empty object")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "   \n"
            "  }");
        REQUIRE(root["object"].empty());
    }

    SECTION("Comma separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15, b: [16, 17], c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Newline separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Mixed separator")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

    SECTION("Eol and spaces")
    {
        vili::node root = vili::parser::from_string(
            "object:     {  \n"
            "    a: 15  \n"
            "        ,    \n"
            "b: [16, 17]  \n"
            "\n"
            "   c: \"18\"       \n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"].as<vili::array>() == vili::array{ 16, 17 });
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }

}

TEST_CASE("Nested objects")
{
    SECTION("One object inside object")
    {
        vili::node root = vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: {\n"
            "a: 16, b: 17},\n"
            "c: \"18\"\n"
            "}");
        REQUIRE(root["object"]["a"].as<vili::integer>() == 15);
        REQUIRE(root["object"]["b"]["a"].as<vili::integer>() == 16);
        REQUIRE(root["object"]["b"]["b"].as<vili::integer>() == 17);
        REQUIRE(root["object"]["c"].as<vili::string>() == "18");
    }
}

TEST_CASE("Incorrect object")
{
    SECTION("Missing closing bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"),
        vili::exceptions::parsing_error);
    }

    SECTION("Missing opening bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: \n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\"\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Comma after last element")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17]\n"
            "c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Missing comma")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: {\n"
            "a: 15,\n"
            "b: [16, 17] c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }

    SECTION("Newline before opening bracket")
    {
        REQUIRE_THROWS_AS(vili::parser::from_string(
            "object: \n"
            "{\n"
            "a: 15,\n"
            "b: [16, 17] c: \"18\",\n"
            "}"),
        vili::exceptions::parsing_error);
    }
}<|endoftext|>


<commit_before>#include <sys/time.h>

#include "thread_private.h"
#include "parameters.h"
#include "exception.h"

bool align_req = false;
int align_size = PAGE_SIZE;

extern struct timeval global_start;

void check_read_content(char *buf, int size, off_t off)
{
	// I assume the space in the buffer is larger than 8 bytes.
	off_t aligned_off = off & (~(sizeof(off_t) - 1));
	long data[2];
	data[0] = aligned_off / sizeof(off_t);
	data[1] = aligned_off / sizeof(off_t) + 1;
	long expected = 0;
	int copy_size = size < (int) sizeof(off_t) ? size : (int) sizeof(off_t);
	memcpy(&expected, ((char *) data) + (off - aligned_off), copy_size);
	long read_value = 0;
	memcpy(&read_value, buf, copy_size);
	if(read_value != expected)
		printf("%ld %ld\n", read_value, expected);
	assert(read_value == expected);
}

void create_write_data(char *buf, int size, off_t off)
{
	off_t aligned_start = off & (~(sizeof(off_t) - 1));
	off_t aligned_end = (off + size) & (~(sizeof(off_t) - 1));
	long start_data = aligned_start / sizeof(off_t);
	long end_data = aligned_end / sizeof(off_t);

	/* If all data is in one 8-byte word. */
	if (aligned_start == aligned_end) {
		memcpy(buf, ((char *) &start_data) + (off - aligned_start), size);
		return;
	}

	int first_size =  (int)(sizeof(off_t) - (off - aligned_start));
	int last_size = (int) (off + size - aligned_end);

	if (first_size == sizeof(off_t))
		first_size = 0;
	if (first_size)
		memcpy(buf, ((char *) &start_data) + (off - aligned_start),
				first_size);
	// Make each buffer written to SSDs different, so it's hard for SSDs
	// to do some tricks on it.
	struct timeval zero = {0, 0};
	long diff = time_diff_us(zero, global_start);
	for (int i = first_size; i < aligned_end - off; i += sizeof(off_t)) {
		*((long *) (buf + i)) = (off + i) / sizeof(off_t) + diff;
	}
	if (aligned_end > aligned_start
			|| (aligned_end == aligned_start && first_size == 0)) {
		if (last_size)
			memcpy(buf + (aligned_end - off), (char *) &end_data, last_size);
	}

	check_read_content(buf, size, off);
}

class cleanup_callback: public callback
{
	rand_buf *buf;
	ssize_t read_bytes;
	int thread_id;
	thread_private *thread;
public:
	cleanup_callback(rand_buf *buf, int idx, thread_private *thread) {
		this->buf = buf;
		read_bytes = 0;
		this->thread_id = idx;
		this->thread = thread;
	}

	int invoke(io_request *rqs[], int num) {
		assert(thread == thread::get_curr_thread());
		for (int i = 0; i < num; i++) {
			io_request *rq = rqs[i];
			if (rq->get_access_method() == READ && config.is_verify_read()) {
				off_t off = rq->get_offset();
				for (int i = 0; i < rq->get_num_bufs(); i++) {
					check_read_content(rq->get_buf(i), rq->get_buf_size(i), off);
					off += rq->get_buf_size(i);
				}
			}
			for (int i = 0; i < rq->get_num_bufs(); i++)
				buf->free_entry(rq->get_buf(i));
			read_bytes += rq->get_size();
		}
#ifdef STATISTICS
		thread->num_completes.inc(num);
		thread->num_pending.dec(num);
#endif
		return 0;
	}

	ssize_t get_size() {
		return read_bytes;
	}
};

ssize_t thread_private::get_read_bytes() {
	if (cb)
		return cb->get_size();
	else
		return read_bytes;
}

void thread_private::init() {
	io = factory->create_io(this);
	io->set_max_num_pending_ios(params.get_aio_depth_per_file());
	io->init();

	rand_buf *buf = new rand_buf(config.get_buf_size(),
			config.get_entry_size(), node_id);
	this->buf = buf;
	if (io->support_aio()) {
		cb = new cleanup_callback(buf, idx, this);
		io->set_callback(cb);
	}
}

class work2req_converter
{
	workload_t workload;
	int align_size;
	rand_buf *buf;
	io_interface *io;
public:
	work2req_converter(io_interface *io, rand_buf * buf, int align_size) {
		workload.off = -1;
		workload.size = -1;
		workload.read = 0;
		this->align_size = align_size;
		this->buf = buf;
		this->io = io;
	}

	void init(const workload_t &workload) {
		this->workload = workload;
		if (align_size > 0) {
			this->workload.off = ROUND(workload.off, align_size);
			this->workload.size = ROUNDUP(workload.off
					+ workload.size, align_size)
				- ROUND(workload.off, align_size);
		}
	}

	bool has_complete() const {
		return workload.size <= 0;
	}

	int to_reqs(int buf_type, int num, io_request reqs[]);
};

int work2req_converter::to_reqs(int buf_type, int num, io_request reqs[])
{
	int node_id = io->get_node_id();
	int access_method = workload.read ? READ : WRITE;
	off_t off = workload.off;
	int size = workload.size;

	if (buf_type == MULTI_BUF) {
		throw unsupported_exception();
#if 0
		assert(off % PAGE_SIZE == 0);
		int num_vecs = size / PAGE_SIZE;
		reqs[i].init(off, io, access_method, node_id);
		assert(buf->get_entry_size() >= PAGE_SIZE);
		for (int k = 0; k < num_vecs; k++) {
			reqs[i].add_buf(buf->next_entry(PAGE_SIZE), PAGE_SIZE);
		}
		workload.off += size;
		workload.size = 0;
#endif
	}
	else if (buf_type == SINGLE_SMALL_BUF) {
		int i = 0;
		while (size > 0 && i < num) {
			off_t next_off = ROUNDUP_PAGE(off + 1);
			if (next_off > off + size)
				next_off = off + size;
			char *p = buf->next_entry(next_off - off);
			if (p == NULL)
				break;
			if (access_method == WRITE && config.is_verify_read())
				create_write_data(p, next_off - off, off);
			reqs[i].init(p, off, next_off - off, access_method,
					io, node_id);
			size -= next_off - off;
			off = next_off;
			i++;
		}
		workload.off = off;
		workload.size = size;
		return i;
	}
	else {
		char *p = buf->next_entry(size);
		if (p == NULL)
			return 0;
		if (access_method == WRITE && config.is_verify_read())
			create_write_data(p, size, off);
		reqs[0].init(p, off, size, access_method, io, node_id);
		workload.off += size;
		workload.size = 0;
		return 1;
	}
}

void thread_private::run()
{
	gettimeofday(&start_time, NULL);
	io_request reqs[NUM_REQS_BY_USER];
	char *entry = NULL;
	if (config.is_use_aio())
		assert(io->support_aio());
	if (!config.is_use_aio()) {
		entry = (char *) valloc(config.get_entry_size());
	}
	work2req_converter converter(io, buf, align_size);
	while (gen->has_next()) {
		if (config.is_use_aio()) {
			int i;
			int num_reqs_by_user = min(io->get_remaining_io_slots(), NUM_REQS_BY_USER);
			for (i = 0; i < num_reqs_by_user; ) {
				if (converter.has_complete() && gen->has_next()) {
					converter.init(gen->next());
				}
				int ret = converter.to_reqs(config.get_buf_type(),
						num_reqs_by_user - i, reqs + i);
				if (ret == 0)
					break;
				i += ret;
			}
			io->access(reqs, i);
			while (io->get_remaining_io_slots() <= 0) {
				int num_ios = io->get_max_num_pending_ios() / 10;
				if (num_ios == 0)
					num_ios = 1;
				io->wait4complete(num_ios);
			}
			num_accesses += i;
#ifdef STATISTICS
			int curr = num_pending.inc(i);
			if (max_num_pending < curr)
				max_num_pending = curr;
			if (num_accesses % 100 == 0) {
				num_sampling++;
				tot_num_pending += curr;
			}
#endif
		}
		else {
			int ret = 0;
			workload_t workload = gen->next();
			off_t off = workload.off;
			int access_method = workload.read ? READ : WRITE;
			int entry_size = workload.size;
			if (align_req) {
				off = ROUND(off, align_size);
				entry_size = ROUNDUP(off + entry_size, align_size)
					- ROUND(off, align_size);
			}

			if (config.get_buf_type() == SINGLE_SMALL_BUF) {
				while (entry_size > 0) {
					/*
					 * generate the data for writing the file,
					 * so the data in the file isn't changed.
					 */
					if (access_method == WRITE && config.is_verify_read()) {
						create_write_data(entry, entry_size, off);
					}
					// There is at least one byte we need to access in the page.
					// By adding 1 and rounding up the offset, we'll get the next page
					// behind the current offset.
					off_t next_off = ROUNDUP_PAGE(off + 1);
					if (next_off > off + entry_size)
						next_off = off + entry_size;
					io_status status = io->access(entry, off, next_off - off,
							access_method);
					assert(!(status == IO_UNSUPPORTED));
					if (status == IO_OK) {
						num_accesses++;
						if (access_method == READ && config.is_verify_read()) {
							check_read_content(entry, next_off - off, off);
						}
						read_bytes += ret;
					}
					if (status == IO_FAIL) {
						perror("access");
						::exit(1);
					}
					entry_size -= next_off - off;
					off = next_off;
				}
			}
			else {
				if (access_method == WRITE && config.is_verify_read()) {
					create_write_data(entry, entry_size, off);
				}
				io_status status = io->access(entry, off, entry_size,
						access_method);
				assert(!(status == IO_UNSUPPORTED));
				if (status == IO_OK) {
					num_accesses++;
					if (access_method == READ && config.is_verify_read()) {
						check_read_content(entry, entry_size, off);
					}
					read_bytes += ret;
				}
				if (status == IO_FAIL) {
					perror("access");
					::exit(1);
				}
			}
		}
	}
	printf("thread %d has issued all requests\n", idx);
	io->cleanup();
	gettimeofday(&end_time, NULL);

	// Stop itself.
	stop();
}

int thread_private::attach2cpu()
{
#if 0
	cpu_set_t cpuset;
	pthread_t thread = pthread_self();
	CPU_ZERO(&cpuset);
	int cpu_num = idx % NCPUS;
	CPU_SET(cpu_num, &cpuset);
	int ret = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
	if (ret != 0) {
		perror("pthread_setaffinity_np");
		exit(1);
	}
	return ret;
#endif
	return 0;
}

#ifdef USE_PROCESS
static int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

static int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}
#endif
<commit_msg>Fix another bug in converting workload to io requests.<commit_after>#include <sys/time.h>

#include "thread_private.h"
#include "parameters.h"
#include "exception.h"

bool align_req = false;
int align_size = PAGE_SIZE;

extern struct timeval global_start;

void check_read_content(char *buf, int size, off_t off)
{
	// I assume the space in the buffer is larger than 8 bytes.
	off_t aligned_off = off & (~(sizeof(off_t) - 1));
	long data[2];
	data[0] = aligned_off / sizeof(off_t);
	data[1] = aligned_off / sizeof(off_t) + 1;
	long expected = 0;
	int copy_size = size < (int) sizeof(off_t) ? size : (int) sizeof(off_t);
	memcpy(&expected, ((char *) data) + (off - aligned_off), copy_size);
	long read_value = 0;
	memcpy(&read_value, buf, copy_size);
	if(read_value != expected)
		printf("%ld %ld\n", read_value, expected);
	assert(read_value == expected);
}

void create_write_data(char *buf, int size, off_t off)
{
	off_t aligned_start = off & (~(sizeof(off_t) - 1));
	off_t aligned_end = (off + size) & (~(sizeof(off_t) - 1));
	long start_data = aligned_start / sizeof(off_t);
	long end_data = aligned_end / sizeof(off_t);

	/* If all data is in one 8-byte word. */
	if (aligned_start == aligned_end) {
		memcpy(buf, ((char *) &start_data) + (off - aligned_start), size);
		return;
	}

	int first_size =  (int)(sizeof(off_t) - (off - aligned_start));
	int last_size = (int) (off + size - aligned_end);

	if (first_size == sizeof(off_t))
		first_size = 0;
	if (first_size)
		memcpy(buf, ((char *) &start_data) + (off - aligned_start),
				first_size);
	// Make each buffer written to SSDs different, so it's hard for SSDs
	// to do some tricks on it.
	struct timeval zero = {0, 0};
	long diff = time_diff_us(zero, global_start);
	for (int i = first_size; i < aligned_end - off; i += sizeof(off_t)) {
		*((long *) (buf + i)) = (off + i) / sizeof(off_t) + diff;
	}
	if (aligned_end > aligned_start
			|| (aligned_end == aligned_start && first_size == 0)) {
		if (last_size)
			memcpy(buf + (aligned_end - off), (char *) &end_data, last_size);
	}

	check_read_content(buf, size, off);
}

class cleanup_callback: public callback
{
	rand_buf *buf;
	ssize_t read_bytes;
	int thread_id;
	thread_private *thread;
public:
	cleanup_callback(rand_buf *buf, int idx, thread_private *thread) {
		this->buf = buf;
		read_bytes = 0;
		this->thread_id = idx;
		this->thread = thread;
	}

	int invoke(io_request *rqs[], int num) {
		assert(thread == thread::get_curr_thread());
		for (int i = 0; i < num; i++) {
			io_request *rq = rqs[i];
			if (rq->get_access_method() == READ && config.is_verify_read()) {
				off_t off = rq->get_offset();
				for (int i = 0; i < rq->get_num_bufs(); i++) {
					check_read_content(rq->get_buf(i), rq->get_buf_size(i), off);
					off += rq->get_buf_size(i);
				}
			}
			for (int i = 0; i < rq->get_num_bufs(); i++)
				buf->free_entry(rq->get_buf(i));
			read_bytes += rq->get_size();
		}
#ifdef STATISTICS
		thread->num_completes.inc(num);
		thread->num_pending.dec(num);
#endif
		return 0;
	}

	ssize_t get_size() {
		return read_bytes;
	}
};

ssize_t thread_private::get_read_bytes() {
	if (cb)
		return cb->get_size();
	else
		return read_bytes;
}

void thread_private::init() {
	io = factory->create_io(this);
	io->set_max_num_pending_ios(params.get_aio_depth_per_file());
	io->init();

	rand_buf *buf = new rand_buf(config.get_buf_size(),
			config.get_entry_size(), node_id);
	this->buf = buf;
	if (io->support_aio()) {
		cb = new cleanup_callback(buf, idx, this);
		io->set_callback(cb);
	}
}

class work2req_converter
{
	workload_t workload;
	int align_size;
	rand_buf *buf;
	io_interface *io;
public:
	work2req_converter(io_interface *io, rand_buf * buf, int align_size) {
		workload.off = -1;
		workload.size = -1;
		workload.read = 0;
		this->align_size = align_size;
		this->buf = buf;
		this->io = io;
	}

	void init(const workload_t &workload) {
		this->workload = workload;
		if (align_size > 0) {
			this->workload.off = ROUND(workload.off, align_size);
			this->workload.size = ROUNDUP(workload.off
					+ workload.size, align_size)
				- ROUND(workload.off, align_size);
		}
	}

	bool has_complete() const {
		return workload.size <= 0;
	}

	int to_reqs(int buf_type, int num, io_request reqs[]);
};

int work2req_converter::to_reqs(int buf_type, int num, io_request reqs[])
{
	int node_id = io->get_node_id();
	int access_method = workload.read ? READ : WRITE;
	off_t off = workload.off;
	int size = workload.size;

	if (buf_type == MULTI_BUF) {
		throw unsupported_exception();
#if 0
		assert(off % PAGE_SIZE == 0);
		int num_vecs = size / PAGE_SIZE;
		reqs[i].init(off, io, access_method, node_id);
		assert(buf->get_entry_size() >= PAGE_SIZE);
		for (int k = 0; k < num_vecs; k++) {
			reqs[i].add_buf(buf->next_entry(PAGE_SIZE), PAGE_SIZE);
		}
		workload.off += size;
		workload.size = 0;
#endif
	}
	else if (buf_type == SINGLE_SMALL_BUF) {
		int i = 0;
		while (size > 0 && i < num) {
			off_t next_off = ROUNDUP_PAGE(off + 1);
			if (next_off > off + size)
				next_off = off + size;
			char *p = buf->next_entry(next_off - off);
			if (p == NULL)
				break;
			if (access_method == WRITE && config.is_verify_read())
				create_write_data(p, next_off - off, off);
			reqs[i].init(p, off, next_off - off, access_method,
					io, node_id);
			size -= next_off - off;
			off = next_off;
			i++;
		}
		workload.off = off;
		workload.size = size;
		return i;
	}
	else {
		char *p = buf->next_entry(size);
		if (p == NULL)
			return 0;
		if (access_method == WRITE && config.is_verify_read())
			create_write_data(p, size, off);
		reqs[0].init(p, off, size, access_method, io, node_id);
		workload.off += size;
		workload.size = 0;
		return 1;
	}
}

void thread_private::run()
{
	gettimeofday(&start_time, NULL);
	io_request reqs[NUM_REQS_BY_USER];
	char *entry = NULL;
	if (config.is_use_aio())
		assert(io->support_aio());
	if (!config.is_use_aio()) {
		entry = (char *) valloc(config.get_entry_size());
	}
	work2req_converter converter(io, buf, align_size);
	while (gen->has_next()) {
		if (config.is_use_aio()) {
			int i;
			int num_reqs_by_user = min(io->get_remaining_io_slots(), NUM_REQS_BY_USER);
			for (i = 0; i < num_reqs_by_user; ) {
				if (converter.has_complete() && gen->has_next()) {
					converter.init(gen->next());
				}
				if (converter.has_complete())
					break;
				int ret = converter.to_reqs(config.get_buf_type(),
						num_reqs_by_user - i, reqs + i);
				if (ret == 0)
					break;
				i += ret;
			}
			io->access(reqs, i);
			while (io->get_remaining_io_slots() <= 0) {
				int num_ios = io->get_max_num_pending_ios() / 10;
				if (num_ios == 0)
					num_ios = 1;
				io->wait4complete(num_ios);
			}
			num_accesses += i;
#ifdef STATISTICS
			int curr = num_pending.inc(i);
			if (max_num_pending < curr)
				max_num_pending = curr;
			if (num_accesses % 100 == 0) {
				num_sampling++;
				tot_num_pending += curr;
			}
#endif
		}
		else {
			int ret = 0;
			workload_t workload = gen->next();
			off_t off = workload.off;
			int access_method = workload.read ? READ : WRITE;
			int entry_size = workload.size;
			if (align_req) {
				off = ROUND(off, align_size);
				entry_size = ROUNDUP(off + entry_size, align_size)
					- ROUND(off, align_size);
			}

			if (config.get_buf_type() == SINGLE_SMALL_BUF) {
				while (entry_size > 0) {
					/*
					 * generate the data for writing the file,
					 * so the data in the file isn't changed.
					 */
					if (access_method == WRITE && config.is_verify_read()) {
						create_write_data(entry, entry_size, off);
					}
					// There is at least one byte we need to access in the page.
					// By adding 1 and rounding up the offset, we'll get the next page
					// behind the current offset.
					off_t next_off = ROUNDUP_PAGE(off + 1);
					if (next_off > off + entry_size)
						next_off = off + entry_size;
					io_status status = io->access(entry, off, next_off - off,
							access_method);
					assert(!(status == IO_UNSUPPORTED));
					if (status == IO_OK) {
						num_accesses++;
						if (access_method == READ && config.is_verify_read()) {
							check_read_content(entry, next_off - off, off);
						}
						read_bytes += ret;
					}
					if (status == IO_FAIL) {
						perror("access");
						::exit(1);
					}
					entry_size -= next_off - off;
					off = next_off;
				}
			}
			else {
				if (access_method == WRITE && config.is_verify_read()) {
					create_write_data(entry, entry_size, off);
				}
				io_status status = io->access(entry, off, entry_size,
						access_method);
				assert(!(status == IO_UNSUPPORTED));
				if (status == IO_OK) {
					num_accesses++;
					if (access_method == READ && config.is_verify_read()) {
						check_read_content(entry, entry_size, off);
					}
					read_bytes += ret;
				}
				if (status == IO_FAIL) {
					perror("access");
					::exit(1);
				}
			}
		}
	}
	printf("thread %d has issued all requests\n", idx);
	io->cleanup();
	gettimeofday(&end_time, NULL);

	// Stop itself.
	stop();
}

int thread_private::attach2cpu()
{
#if 0
	cpu_set_t cpuset;
	pthread_t thread = pthread_self();
	CPU_ZERO(&cpuset);
	int cpu_num = idx % NCPUS;
	CPU_SET(cpu_num, &cpuset);
	int ret = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
	if (ret != 0) {
		perror("pthread_setaffinity_np");
		exit(1);
	}
	return ret;
#endif
	return 0;
}

#ifdef USE_PROCESS
static int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

static int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}
#endif
<|endoftext|>


<commit_before>
#include <QMouseEvent>
#include <QModelIndex>
#include <QItemSelectionModel>
#include "PGTATreeView.h"

PGTATreeView::PGTATreeView(QWidget *parent) :
    QTreeView(parent)
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    setDragDropMode(QAbstractItemView::DragDrop);
    setDefaultDropAction(Qt::MoveAction);
    setDragEnabled(true);
    setDropIndicatorShown(true);
}

PGTATreeView::~PGTATreeView()
{
}

void PGTATreeView::mousePressEvent(QMouseEvent *event)
    {
        QModelIndex item = indexAt(event->pos());
        bool selected = selectionModel()->isSelected(indexAt(event->pos()));
        QTreeView::mousePressEvent(event);
        Qt::MouseButton button = event->button();
        if ((item.row() == -1 && item.column() == -1) || (selected && (button == Qt::LeftButton)))
        {
            clearSelection();
            const QModelIndex index;
            selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
        }
    }
<commit_msg>Changed how selection works to fix issues with drag and drop.<commit_after>
#include <QMouseEvent>
#include <QModelIndex>
#include <QItemSelectionModel>
#include "PGTATreeView.h"

PGTATreeView::PGTATreeView(QWidget *parent) :
    QTreeView(parent)
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    setDragDropMode(QAbstractItemView::DragDrop);
    setDefaultDropAction(Qt::MoveAction);
    setDragEnabled(true);
    setDropIndicatorShown(true);
}

PGTATreeView::~PGTATreeView()
{
}

void PGTATreeView::mousePressEvent(QMouseEvent *event)
    {
        QModelIndex item = indexAt(event->pos());
        bool selected = selectionModel()->isSelected(indexAt(event->pos()));
        QTreeView::mousePressEvent(event);
        Qt::MouseButton button = event->button();
        if (item.row() == -1 && item.column() == -1)
        {
            clearSelection();
            const QModelIndex index;
            selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select);
        }
    }

<|endoftext|>


<commit_before>#include "circuits/circuit.h"
#include "matrix/matrix.h"
#include "gtest/gtest.h"
#include <iostream>
#include <stdio.h>

using namespace std;

TEST(ElementStampsTest, Resistor) {
    // Arrange
                      // (val)(a)(b)
    Element resistor("R1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    resistor.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0,    0,    0, 0},
        {0,  0.1, -0.1, 0},
        {0, -0.1,  0.1, 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VCCS) {
    /*
     * Voltage Controlled Current Source
     * (a.k.a. Transconductance)
     */

    // Arrange
                              // (val)(a)(b)(c)(d)
    Element transconductance("G1", 10, 1, 2, 3, 4);
    int numVariables = 4;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    transconductance.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0, 0 , 0 ,   0 ,   0 , 0},
        {0, 0 , 0 ,  10 , -10 , 0},
        {0, 0 , 0 , -10 ,  10 , 0},
        {0, 0 , 0 ,   0 ,   0 , 0},
        {0, 0 , 0 ,   0 ,   0 , 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, CurrentSource) {
    // Arrange
                           // (val)(a)(b)
    Element currentSource("I1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    currentSource.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0, 0 , 0 ,  0},
        {0, 0 , 0 , -10},
        {0, 0 , 0 ,  10}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VoltageSource) {
    // Arrange
                           // (val)(a)(b)
    Element voltageSource("V1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    voltageSource.addCurrentVariables(numVariables, dummyVariablesList);

    // Act
    voltageSource.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        { 0,  0 , 0 ,  0 ,   0 },
        { 0,  0 , 0 ,  1 ,   0 },
        { 0,  0 , 0 , -1 ,   0 },
        { 0, -1 , 1 ,  0 , -10 }
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VCVS) {
    /*
     * Voltage Controlled Voltage Source
     * (a.k.a. Voltage Amplifier)
     */
    // Arrange
                              // (val)(a)(b)(c)(d)
    Element voltageAmplifier("E1", 10, 1, 2, 3, 4);
    int numVariables = 4;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    voltageAmplifier.addCurrentVariables(numVariables, dummyVariablesList);

    // Act
    voltageAmplifier.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
       // 0    1    2   3     4   jx   i
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  1 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 , -1 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 , -1 , +1, 10 , -10 ,  0 , 0 }
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(CircuitStampsTest, SimpleCircuit) {
    // Arrange
    int numNodes = 6;
    int numElements = 9;
    int numVariables = 9;
    vector<Element> netlist(10);
    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);
    // From netlist data/simples.net
    // Changes order (not netlist parameters order)! Value first!
                     // ( name, val, a, b, ... )
    netlist[1] = Element("R0102", 1, 1, 2);
    netlist[2] = Element("R0301", 1, 3, 1);
    netlist[3] = Element("R0403", 1, 4, 3);
    netlist[4] = Element("R0004", 1, 0, 4);
    netlist[5] = Element("R0502", 1, 5, 2);
    netlist[6] = Element("R0605", 1, 6, 5);
    netlist[7] = Element("O0300", 0, 3, 0, 1, 0); // OpAmps have no value!!!
    netlist[8] = Element("O0600", 0, 6, 0, 5, 4);
    netlist[9] = Element("V0200", 1, 2, 0);
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    int pivotNumVariables = numNodes;
    netlist[7].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[8].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[9].addCurrentVariables(pivotNumVariables, dummyVariablesList);

    // Act
    applyStamps(numElements, numVariables, netlist, matrix);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  2 , -1 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 , -1 ,  2 ,  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  1 ,  0 },
        {  0 , -1 ,  0 ,  2 , -1 ,  0 ,  0 ,  1 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 , -1 ,  2 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  2 , -1 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  1 ,  0 ,  0 },
        {  0 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 , -1 },
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}
<commit_msg>Fixes major bug on tests :ant: :ant: :ant: :ant: :ant:<commit_after>#include "circuits/circuit.h"
#include "matrix/matrix.h"
#include "gtest/gtest.h"
#include <iostream>
#include <stdio.h>

using namespace std;

TEST(ElementStampsTest, Resistor) {
    // Arrange
                      // (val)(a)(b)
    Element resistor("R1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    resistor.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0,    0,    0, 0},
        {0,  0.1, -0.1, 0},
        {0, -0.1,  0.1, 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VCCS) {
    /*
     * Voltage Controlled Current Source
     * (a.k.a. Transconductance)
     */

    // Arrange
                              // (val)(a)(b)(c)(d)
    Element transconductance("G1", 10, 1, 2, 3, 4);
    int numVariables = 4;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    transconductance.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0, 0 , 0 ,   0 ,   0 , 0},
        {0, 0 , 0 ,  10 , -10 , 0},
        {0, 0 , 0 , -10 ,  10 , 0},
        {0, 0 , 0 ,   0 ,   0 , 0},
        {0, 0 , 0 ,   0 ,   0 , 0}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, CurrentSource) {
    // Arrange
                           // (val)(a)(b)
    Element currentSource("I1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    init(numVariables, matrix);

    // Act
    currentSource.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {0, 0 , 0 ,  0},
        {0, 0 , 0 , -10},
        {0, 0 , 0 ,  10}
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VoltageSource) {
    // Arrange
                           // (val)(a)(b)
    Element voltageSource("V1", 10, 1, 2);
    int numVariables = 2;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    voltageSource.addCurrentVariables(numVariables, dummyVariablesList);

    // Important!!! Should be initialized after updating numVariables
    // with extra current variables!
    init(numVariables, matrix);

    // Act
    voltageSource.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        { 0,  0 , 0 ,  0 ,   0 },
        { 0,  0 , 0 ,  1 ,   0 },
        { 0,  0 , 0 , -1 ,   0 },
        { 0, -1 , 1 ,  0 , -10 }
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(ElementStampsTest, VCVS) {
    /*
     * Voltage Controlled Voltage Source
     * (a.k.a. Voltage Amplifier)
     */
    // Arrange
                              // (val)(a)(b)(c)(d)
    Element voltageAmplifier("E1", 10, 1, 2, 3, 4);
    int numVariables = 4;

    double matrix[MAX_NODES+1][MAX_NODES+2];
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    voltageAmplifier.addCurrentVariables(numVariables, dummyVariablesList);

    // Important!!! Should be initialized after updating numVariables
    // with extra current variables!
    init(numVariables, matrix);

    // Act
    voltageAmplifier.applyStamp(matrix, numVariables);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
       // 0    1    2   3     4   jx   i
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  1 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 , -1 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 ,  0 ,  0 , 0 ,   0 ,  0 , 0 },
        { 0 , -1 , +1, 10 , -10 ,  0 , 0 }
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}

TEST(CircuitStampsTest, SimpleCircuit) {
    // Arrange
    int numNodes = 6;
    int numElements = 9;
    int numVariables = 9;
    vector<Element> netlist(10);
    double matrix[MAX_NODES+1][MAX_NODES+2];
    // From netlist data/simples.net
    // Changes order (not netlist parameters order)! Value first!
                     // ( name, val, a, b, ... )
    netlist[1] = Element("R0102", 1, 1, 2);
    netlist[2] = Element("R0301", 1, 3, 1);
    netlist[3] = Element("R0403", 1, 4, 3);
    netlist[4] = Element("R0004", 1, 0, 4);
    netlist[5] = Element("R0502", 1, 5, 2);
    netlist[6] = Element("R0605", 1, 6, 5);
    netlist[7] = Element("O0300", 0, 3, 0, 1, 0); // OpAmps have no value!!!
    netlist[8] = Element("O0600", 0, 6, 0, 5, 4);
    netlist[9] = Element("V0200", 1, 2, 0);
    // Bad smell about the need of this member function...
    // Without it, only first part of matrix would be populated!
    vector<string> dummyVariablesList(10);
    int pivotNumVariables = numNodes;
    netlist[7].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[8].addCurrentVariables(pivotNumVariables, dummyVariablesList);
    netlist[9].addCurrentVariables(pivotNumVariables, dummyVariablesList);

    // Important!!! Should be initialized after updating numVariables
    // with extra current variables!
    init(numVariables, matrix);

    // Act
    applyStamps(numElements, numVariables, netlist, matrix);

    // Assert
    double expected[MAX_NODES+1][MAX_NODES+2] = {
        {  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  2 , -1 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 , -1 ,  2 ,  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  1 ,  0 },
        {  0 , -1 ,  0 ,  2 , -1 ,  0 ,  0 ,  1 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 , -1 ,  2 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  2 , -1 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  1 ,  0 ,  0 },
        {  0 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 ,  0 ,  0 , -1 ,  1 ,  0 ,  0 ,  0 ,  0 ,  0 },
        {  0 ,  0 , -1 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 , -1 },
    };
    for (int i=1; i<=numVariables; i++) {
        for (int j=1; j<=numVariables+1; j++) {
            EXPECT_EQ(expected[i][j], matrix[i][j]);
        }
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2001 by W.C.A. Wijngaards

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include "csutil/util.h"
#include "igraphic/imageio.h"
#include "igraphic/image.h"
#include "imesh/object.h"
#include "isoengin.h"
#include "isolight.h"
#include "isomesh.h"
#include "isospr.h"
#include "isoview.h"
#include "isoworld.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "iutil/cfgmgr.h"
#include "iutil/evdefs.h"
#include "iutil/event.h"
#include "iutil/eventq.h"
#include "iutil/object.h"
#include "iutil/objreg.h"
#include "ivaria/reporter.h"
#include "ivideo/graph2d.h"
#include "ivideo/graph3d.h"
#include "ivideo/txtmgr.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_IBASE (csIsoEngine)
  SCF_IMPLEMENTS_INTERFACE (iIsoEngine)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_FACTORY (csIsoEngine)

SCF_IMPLEMENT_EMBEDDED_IBASE (csIsoEngine::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csIsoEngine::EventHandler)
  SCF_IMPLEMENTS_INTERFACE (iEventHandler)
SCF_IMPLEMENT_IBASE_END

SCF_EXPORT_CLASS_TABLE (iso)
  SCF_EXPORT_CLASS_DEP (csIsoEngine, "crystalspace.engine.iso",
    "Crystal Space Isometric Engine",
    "crystalspace.kernel., crystalspace.graphics3d., crystalspace.graphics2d.")
SCF_EXPORT_CLASS_TABLE_END

void csIsoEngine::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  iReporter* rep = CS_QUERY_REGISTRY (object_reg, iReporter);
  if (rep)
  {
    rep->ReportV (severity, "crystalspace.engine.iso", msg, arg);
    rep->DecRef ();
  }
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

csIsoEngine::csIsoEngine (iBase *iParent)
{
  SCF_CONSTRUCT_IBASE (iParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  scfiEventHandler = NULL;
  object_reg = NULL;
  g2d = NULL;
  g3d = NULL;
  txtmgr = NULL;
  world = NULL;
}

csIsoEngine::~csIsoEngine ()
{
  if (scfiEventHandler)
  {
    iEventQueue* q = CS_QUERY_REGISTRY(object_reg, iEventQueue);
    if (q != 0)
    {
      q->RemoveListener (scfiEventHandler);
      q->DecRef ();
    }
    scfiEventHandler->DecRef ();
  }
  materials.scfiMaterialList.RemoveAll ();
  if (g3d) g3d->DecRef();
}

bool csIsoEngine::Initialize (iObjectRegistry* p)
{
  object_reg = p;
  // Tell system driver that we want to handle broadcast events
  if (!scfiEventHandler)
    scfiEventHandler = new EventHandler (this);
  iEventQueue* q = CS_QUERY_REGISTRY(object_reg, iEventQueue);
  if (q != 0)
  {
    q->RegisterListener (scfiEventHandler, CSMASK_Broadcast);
    q->DecRef ();
  }
  return true;
}

bool csIsoEngine::HandleEvent (iEvent& Event)
{
  // Handle some system-driver broadcasts
  if (Event.Type == csevBroadcast)
    switch (Event.Command.Code)
    {
      case cscmdSystemOpen:
      {
        // system is open we can get ptrs now
        g3d = CS_QUERY_REGISTRY (object_reg, iGraphics3D);
        if (!g3d)
        {
          Report (CS_REPORTER_SEVERITY_ERROR, "IsoEngine: could not get G3D.");
          return false;
        }
        g2d = g3d->GetDriver2D ();
        if (!g2d)
        {
          Report (CS_REPORTER_SEVERITY_ERROR, "IsoEngine: could not get G2D.");
          return false;
        }
        txtmgr = g3d->GetTextureManager();
        if (!txtmgr)
        {
          Report (CS_REPORTER_SEVERITY_ERROR,
            "IsoEngine: could not get TextureManager.");
          return false;
        }
        return true;
      }
      case cscmdSystemClose:
      {
        // We must free all material and texture handles since after
        // G3D->Close() they all become invalid, no matter whenever
        // we did or didn't an IncRef on them.
	materials.scfiMaterialList.RemoveAll ();
        return true;
      }
      case cscmdContextResize:
      {
        return false;
      }
      case cscmdContextClose:
      {
        return false;
      }
    } /* endswitch */

  return false;
}

iIsoWorld* csIsoEngine::CreateWorld()
{
  return new csIsoWorld(this);
}

iIsoView* csIsoEngine::CreateView(iIsoWorld *world)
{
  return new csIsoView(this, this, world);
}

iIsoSprite* csIsoEngine::CreateSprite()
{
  return new csIsoSprite(this);
}

iIsoMeshSprite* csIsoEngine::CreateMeshSprite()
{
  return new csIsoMeshSprite(this);
}

int csIsoEngine::GetBeginDrawFlags () const
{
  return CSDRAW_CLEARZBUFFER;
}

iIsoSprite* csIsoEngine::CreateFloorSprite(const csVector3& pos, float w,
      float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0,0,0), 0, 0);
  spr->AddVertex(csVector3(0, 0, w), 1, 0);
  spr->AddVertex(csVector3(h, 0, w), 1, 1);
  spr->AddVertex(csVector3(h, 0, 0), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateFrontSprite(const csVector3& pos, float w,
      float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  float hw = w * 0.25;
  spr->AddVertex(csVector3(-hw, 0,-hw), 0, 0);
  spr->AddVertex(csVector3(-hw, h, -hw), 1, 0);
  spr->AddVertex(csVector3(+hw, h, +hw), 1, 1);
  spr->AddVertex(csVector3(+hw, 0, +hw), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateZWallSprite(const csVector3& pos, float w,
  float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0, 0, 0), 0, 0);
  spr->AddVertex(csVector3(0, h, 0), 1, 0);
  spr->AddVertex(csVector3(0, h, w), 1, 1);
  spr->AddVertex(csVector3(0, 0, w), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateXWallSprite(const csVector3& pos, float w,
  float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0, 0, 0), 0, 0);
  spr->AddVertex(csVector3(0, h, 0), 1, 0);
  spr->AddVertex(csVector3(w, h, 0), 1, 1);
  spr->AddVertex(csVector3(w, 0, 0), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoLight* csIsoEngine::CreateLight()
{
  return new csIsoLight(this);
}

iMaterialWrapper *csIsoEngine::CreateMaterialWrapper(const char *vfsfilename,
	          const char *materialname)
{
  iImageIO *imgloader = NULL;
  iVFS *VFS = NULL;
  iDataBuffer *buf = NULL;
  iImage *image = NULL;
  iTextureHandle *handle = NULL;
  csIsoMaterial *material = NULL;
  iMaterialHandle *math = NULL;
  iMaterialWrapper *mat_wrap = NULL;

  imgloader = CS_QUERY_REGISTRY (object_reg, iImageIO);
  if(imgloader==NULL)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not get image loader plugin. "
    	"Failed to load file %s.", vfsfilename);
    goto create_out;
  }

  VFS = CS_QUERY_REGISTRY (object_reg, iVFS);
  if(VFS==NULL)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not get VFS plugin. "
    	"Failed to load file %s.", vfsfilename);
    goto create_out;
  }

  buf = VFS->ReadFile (vfsfilename);
  if(!buf)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not read vfs file %s\n",
      vfsfilename);
    goto create_out;
  }

  image = imgloader->Load(buf->GetUint8 (), buf->GetSize (),
			  txtmgr->GetTextureFormat ());
  if(!image)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "The imageloader could not load image %s", vfsfilename);
    goto create_out;
  }

  handle = txtmgr->RegisterTexture(image, CS_TEXTURE_2D | CS_TEXTURE_3D);
  if(!handle)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "Texturemanager could not register texture %s", vfsfilename);
    goto create_out;
  }

  material = new csIsoMaterial(handle);
  math = txtmgr->RegisterMaterial(material);
  if(math)
  {
    mat_wrap = materials.scfiMaterialList.NewMaterial (math);
    mat_wrap->IncRef ();	// Jorrit: @@@ Not sure why this is needed?
    mat_wrap->QueryObject ()->SetName (materialname);
  }
  else
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "Texturemanager could not register material %s", materialname);
    goto create_out;
  }

 create_out:
  if (math) math->DecRef ();
  if (image) image->DecRef ();
  if (buf) buf->DecRef();
  if (imgloader) imgloader->DecRef ();
  if (VFS) VFS->DecRef ();

  return mat_wrap;
}

iMeshFactoryWrapper *csIsoEngine::CreateMeshFactory(const char* classId,
    const char *name)
{
  iMeshObjectFactory *mesh_fact;
  iMeshObjectType *mesh_type;

  if (name)
  {
    iMeshFactoryWrapper* wrap = meshfactories.
    	scfiMeshFactoryList.FindByName (name);
    if (wrap)
      return wrap;
  }

  iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  mesh_type = CS_QUERY_PLUGIN_CLASS (plugin_mgr, classId, iMeshObjectType);

  if(!mesh_type)
    mesh_type = CS_LOAD_PLUGIN (plugin_mgr, classId, iMeshObjectType);
  plugin_mgr->DecRef ();
  if(!mesh_type)
    return NULL;

  csIsoMeshFactoryWrapper* wrap = NULL;
  mesh_fact = mesh_type->NewFactory ();
  if (mesh_fact)
  {
    //AddMeshFactory (mesh_fact, name);
    //mesh_fact->DecRef ();
    wrap = new csIsoMeshFactoryWrapper (mesh_fact);
    iObject* obj = SCF_QUERY_INTERFACE (wrap, iObject);
    obj->SetName (name);
    obj->DecRef ();
    meshfactories.scfiMeshFactoryList.Add (&(wrap->scfiMeshFactoryWrapper));
    wrap->DecRef ();
    mesh_type->DecRef ();
    return &(wrap->scfiMeshFactoryWrapper);
  }
  mesh_type->DecRef ();
  return NULL;
}

<commit_msg>CreateMeshFactory() was leaking a iMeshObjectFactory, added a DecRef()<commit_after>/*
    Copyright (C) 2001 by W.C.A. Wijngaards

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include "csutil/util.h"
#include "igraphic/imageio.h"
#include "igraphic/image.h"
#include "imesh/object.h"
#include "isoengin.h"
#include "isolight.h"
#include "isomesh.h"
#include "isospr.h"
#include "isoview.h"
#include "isoworld.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "iutil/cfgmgr.h"
#include "iutil/evdefs.h"
#include "iutil/event.h"
#include "iutil/eventq.h"
#include "iutil/object.h"
#include "iutil/objreg.h"
#include "ivaria/reporter.h"
#include "ivideo/graph2d.h"
#include "ivideo/graph3d.h"
#include "ivideo/txtmgr.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_IBASE (csIsoEngine)
  SCF_IMPLEMENTS_INTERFACE (iIsoEngine)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_FACTORY (csIsoEngine)

SCF_IMPLEMENT_EMBEDDED_IBASE (csIsoEngine::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csIsoEngine::EventHandler)
  SCF_IMPLEMENTS_INTERFACE (iEventHandler)
SCF_IMPLEMENT_IBASE_END

SCF_EXPORT_CLASS_TABLE (iso)
  SCF_EXPORT_CLASS_DEP (csIsoEngine, "crystalspace.engine.iso",
    "Crystal Space Isometric Engine",
    "crystalspace.kernel., crystalspace.graphics3d., crystalspace.graphics2d.")
SCF_EXPORT_CLASS_TABLE_END

void csIsoEngine::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  iReporter* rep = CS_QUERY_REGISTRY (object_reg, iReporter);
  if (rep)
  {
    rep->ReportV (severity, "crystalspace.engine.iso", msg, arg);
    rep->DecRef ();
  }
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

csIsoEngine::csIsoEngine (iBase *iParent)
{
  SCF_CONSTRUCT_IBASE (iParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  scfiEventHandler = NULL;
  object_reg = NULL;
  g2d = NULL;
  g3d = NULL;
  txtmgr = NULL;
  world = NULL;
}

csIsoEngine::~csIsoEngine ()
{
  if (scfiEventHandler)
  {
    iEventQueue* q = CS_QUERY_REGISTRY(object_reg, iEventQueue);
    if (q != 0)
    {
      q->RemoveListener (scfiEventHandler);
      q->DecRef ();
    }
    scfiEventHandler->DecRef ();
  }
  materials.scfiMaterialList.RemoveAll ();
  if (g3d) g3d->DecRef();
}

bool csIsoEngine::Initialize (iObjectRegistry* p)
{
  object_reg = p;
  // Tell system driver that we want to handle broadcast events
  if (!scfiEventHandler)
    scfiEventHandler = new EventHandler (this);
  iEventQueue* q = CS_QUERY_REGISTRY(object_reg, iEventQueue);
  if (q != 0)
  {
    q->RegisterListener (scfiEventHandler, CSMASK_Broadcast);
    q->DecRef ();
  }
  return true;
}

bool csIsoEngine::HandleEvent (iEvent& Event)
{
  // Handle some system-driver broadcasts
  if (Event.Type == csevBroadcast)
    switch (Event.Command.Code)
    {
      case cscmdSystemOpen:
      {
        // system is open we can get ptrs now
        g3d = CS_QUERY_REGISTRY (object_reg, iGraphics3D);
        if (!g3d)
        {
          Report (CS_REPORTER_SEVERITY_ERROR, "IsoEngine: could not get G3D.");
          return false;
        }
        g2d = g3d->GetDriver2D ();
        if (!g2d)
        {
          Report (CS_REPORTER_SEVERITY_ERROR, "IsoEngine: could not get G2D.");
          return false;
        }
        txtmgr = g3d->GetTextureManager();
        if (!txtmgr)
        {
          Report (CS_REPORTER_SEVERITY_ERROR,
            "IsoEngine: could not get TextureManager.");
          return false;
        }
        return true;
      }
      case cscmdSystemClose:
      {
        // We must free all material and texture handles since after
        // G3D->Close() they all become invalid, no matter whenever
        // we did or didn't an IncRef on them.
	materials.scfiMaterialList.RemoveAll ();
        return true;
      }
      case cscmdContextResize:
      {
        return false;
      }
      case cscmdContextClose:
      {
        return false;
      }
    } /* endswitch */

  return false;
}

iIsoWorld* csIsoEngine::CreateWorld()
{
  return new csIsoWorld(this);
}

iIsoView* csIsoEngine::CreateView(iIsoWorld *world)
{
  return new csIsoView(this, this, world);
}

iIsoSprite* csIsoEngine::CreateSprite()
{
  return new csIsoSprite(this);
}

iIsoMeshSprite* csIsoEngine::CreateMeshSprite()
{
  return new csIsoMeshSprite(this);
}

int csIsoEngine::GetBeginDrawFlags () const
{
  return CSDRAW_CLEARZBUFFER;
}

iIsoSprite* csIsoEngine::CreateFloorSprite(const csVector3& pos, float w,
      float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0,0,0), 0, 0);
  spr->AddVertex(csVector3(0, 0, w), 1, 0);
  spr->AddVertex(csVector3(h, 0, w), 1, 1);
  spr->AddVertex(csVector3(h, 0, 0), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateFrontSprite(const csVector3& pos, float w,
      float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  float hw = w * 0.25;
  spr->AddVertex(csVector3(-hw, 0,-hw), 0, 0);
  spr->AddVertex(csVector3(-hw, h, -hw), 1, 0);
  spr->AddVertex(csVector3(+hw, h, +hw), 1, 1);
  spr->AddVertex(csVector3(+hw, 0, +hw), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateZWallSprite(const csVector3& pos, float w,
  float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0, 0, 0), 0, 0);
  spr->AddVertex(csVector3(0, h, 0), 1, 0);
  spr->AddVertex(csVector3(0, h, w), 1, 1);
  spr->AddVertex(csVector3(0, 0, w), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoSprite* csIsoEngine::CreateXWallSprite(const csVector3& pos, float w,
  float h)
{
  iIsoSprite *spr = new csIsoSprite(this);
  spr->AddVertex(csVector3(0, 0, 0), 0, 0);
  spr->AddVertex(csVector3(0, h, 0), 1, 0);
  spr->AddVertex(csVector3(w, h, 0), 1, 1);
  spr->AddVertex(csVector3(w, 0, 0), 0, 1);
  spr->SetPosition(pos);
  return spr;
}

iIsoLight* csIsoEngine::CreateLight()
{
  return new csIsoLight(this);
}

iMaterialWrapper *csIsoEngine::CreateMaterialWrapper(const char *vfsfilename,
	          const char *materialname)
{
  iImageIO *imgloader = NULL;
  iVFS *VFS = NULL;
  iDataBuffer *buf = NULL;
  iImage *image = NULL;
  iTextureHandle *handle = NULL;
  csIsoMaterial *material = NULL;
  iMaterialHandle *math = NULL;
  iMaterialWrapper *mat_wrap = NULL;

  imgloader = CS_QUERY_REGISTRY (object_reg, iImageIO);
  if(imgloader==NULL)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not get image loader plugin. "
    	"Failed to load file %s.", vfsfilename);
    goto create_out;
  }

  VFS = CS_QUERY_REGISTRY (object_reg, iVFS);
  if(VFS==NULL)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not get VFS plugin. "
    	"Failed to load file %s.", vfsfilename);
    goto create_out;
  }

  buf = VFS->ReadFile (vfsfilename);
  if(!buf)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not read vfs file %s\n",
      vfsfilename);
    goto create_out;
  }

  image = imgloader->Load(buf->GetUint8 (), buf->GetSize (),
			  txtmgr->GetTextureFormat ());
  if(!image)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "The imageloader could not load image %s", vfsfilename);
    goto create_out;
  }

  handle = txtmgr->RegisterTexture(image, CS_TEXTURE_2D | CS_TEXTURE_3D);
  if(!handle)
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "Texturemanager could not register texture %s", vfsfilename);
    goto create_out;
  }

  material = new csIsoMaterial(handle);
  math = txtmgr->RegisterMaterial(material);
  if(math)
  {
    mat_wrap = materials.scfiMaterialList.NewMaterial (math);
    mat_wrap->IncRef ();	// Jorrit: @@@ Not sure why this is needed?
    mat_wrap->QueryObject ()->SetName (materialname);
  }
  else
  {
    Report (CS_REPORTER_SEVERITY_ERROR,
      "Texturemanager could not register material %s", materialname);
    goto create_out;
  }

 create_out:
  if (math) math->DecRef ();
  if (image) image->DecRef ();
  if (buf) buf->DecRef();
  if (imgloader) imgloader->DecRef ();
  if (VFS) VFS->DecRef ();

  return mat_wrap;
}

iMeshFactoryWrapper *csIsoEngine::CreateMeshFactory(const char* classId,
    const char *name)
{
  iMeshObjectFactory *mesh_fact;
  iMeshObjectType *mesh_type;

  if (name)
  {
    iMeshFactoryWrapper* wrap = meshfactories.
    	scfiMeshFactoryList.FindByName (name);
    if (wrap)
      return wrap;
  }

  iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  mesh_type = CS_QUERY_PLUGIN_CLASS (plugin_mgr, classId, iMeshObjectType);

  if(!mesh_type)
    mesh_type = CS_LOAD_PLUGIN (plugin_mgr, classId, iMeshObjectType);
  plugin_mgr->DecRef ();
  if(!mesh_type)
    return NULL;

  csIsoMeshFactoryWrapper* wrap = NULL;
  mesh_fact = mesh_type->NewFactory ();
  if (mesh_fact)
  {
    //AddMeshFactory (mesh_fact, name);
    //mesh_fact->DecRef ();
    wrap = new csIsoMeshFactoryWrapper (mesh_fact);
    iObject* obj = SCF_QUERY_INTERFACE (wrap, iObject);
    obj->SetName (name);
    obj->DecRef ();
    meshfactories.scfiMeshFactoryList.Add (&(wrap->scfiMeshFactoryWrapper));
    wrap->DecRef ();
    mesh_fact->DecRef();
    mesh_type->DecRef ();
    return &(wrap->scfiMeshFactoryWrapper);
  }
  mesh_type->DecRef ();
  return NULL;
}

<|endoftext|>