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

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE graphalgorithm_test
#include <boost/test/unit_test.hpp>
#include <unordered_map>
#include <vector>
#include <votca/tools/graph.h>
#include <votca/tools/graph_bf_visitor.h>
#include <votca/tools/graphalgorithm.h>
#include <votca/tools/graphdistvisitor.h>
#include <votca/tools/graphnode.h>

using namespace std;
using namespace votca::tools;

using namespace boost;
using namespace boost::unit_test;

BOOST_AUTO_TEST_SUITE(graphalgorithm_test)

BOOST_AUTO_TEST_CASE(single_network_algorithm_test) {
  {
    // In this test we add two nodes and an edge describing
    // their connection thus the singleNetwork function will
    // return true.

    // Create edge
    Edge ed(0, 1);
    vector<Edge> edges;
    edges.push_back(ed);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;

    Graph g(edges, nodes);

    Graph_BF_Visitor gb_v;

    BOOST_CHECK(gb_v.queEmpty());
    BOOST_CHECK_THROW(gb_v.exec(g, ed), runtime_error);

    bool single_n = singleNetwork(g, gb_v);
    BOOST_CHECK(single_n);
    BOOST_CHECK(gb_v.queEmpty());

    Graph_BF_Visitor gb_v2;
    gb_v2.setStartingVertex(2);
    BOOST_CHECK_THROW(singleNetwork(g, gb_v2), invalid_argument);
  }

  {

    // In this test we add 3 nodes but only one edge
    // this means that one of the nodes will not be
    // attached to the other two. Thus the singleNetwork
    // function should return false.

    // Create edge
    Edge ed(0, 1);
    vector<Edge> edges;
    edges.push_back(ed);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;

    Graph g(edges, nodes);

    Graph_BF_Visitor gb_v;

    BOOST_CHECK(gb_v.queEmpty());
    BOOST_CHECK_THROW(gb_v.exec(g, ed), runtime_error);

    bool single_n = singleNetwork(g, gb_v);
    BOOST_CHECK(!single_n);
    BOOST_CHECK(gb_v.queEmpty());
  }
}

BOOST_AUTO_TEST_CASE(decoupleIsolatedSubGraphs_algorithm_test) {
  {
    // In this test we add two nodes and an edge describing
    // their connection

    // Create edge
    Edge ed(0, 1);
    vector<Edge> edges;
    edges.push_back(ed);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;

    Graph g(edges, nodes);

    auto subGraphs = decoupleIsolatedSubGraphs(g);

    BOOST_CHECK_EQUAL(subGraphs.size(), 1);
    BOOST_CHECK_EQUAL(*(subGraphs.at(0)), g);
  }

  {

    // Create edge
    //     2
    //     |
    // 0 - 1 - 3
    //     |
    //     4

    Edge ed1(0, 1);
    Edge ed2(1, 2);
    Edge ed3(1, 3);
    Edge ed4(1, 4);

    //
    // 5 - 6
    //
    Edge ed5(5, 6);

    vector<Edge> edges;
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);
    vector<std::shared_ptr<Graph>> sub_graphs = decoupleIsolatedSubGraphs(g);
    BOOST_CHECK_EQUAL(sub_graphs.size(), 2);

    // Create sub graphs to compare with the graphs stored in 'sub_graphs'

    vector<Edge> sub_graph1_edges;
    sub_graph1_edges.push_back(ed1);
    sub_graph1_edges.push_back(ed2);
    sub_graph1_edges.push_back(ed3);
    sub_graph1_edges.push_back(ed4);

    vector<Edge> sub_graph2_edges;
    sub_graph2_edges.push_back(ed5);

    unordered_map<int, GraphNode> sub_graph1_nodes;
    sub_graph1_nodes[0] = gn1;
    sub_graph1_nodes[1] = gn2;
    sub_graph1_nodes[2] = gn3;
    sub_graph1_nodes[3] = gn4;
    sub_graph1_nodes[4] = gn5;

    unordered_map<int, GraphNode> sub_graph2_nodes;
    sub_graph2_nodes[0] = gn6;
    sub_graph2_nodes[1] = gn7;

    Graph sub_graph1(sub_graph1_edges, sub_graph1_nodes);
    Graph sub_graph2(sub_graph2_edges, sub_graph2_nodes);

    // Cycle sub_graphs
    bool sub_graph1_found = false;
    bool sub_graph2_found = false;

    for (auto graph_sub_it = sub_graphs.begin();
         graph_sub_it != sub_graphs.end(); ++graph_sub_it) {
      if (**graph_sub_it == sub_graph1) sub_graph1_found = true;
      if (**graph_sub_it == sub_graph2) sub_graph2_found = true;
    }
    BOOST_CHECK(sub_graph1_found);
    BOOST_CHECK(sub_graph2_found);
  }
}

BOOST_AUTO_TEST_CASE(structureid_test) {
  {

    // Create edge
    Edge ed(0, 1);
    Edge ed1(1, 2);
    Edge ed2(2, 3);
    Edge ed3(3, 4);
    Edge ed4(4, 5);
    Edge ed5(5, 0);
    Edge ed6(3, 6);

    vector<Edge> edges;
    edges.push_back(ed);
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);
    edges.push_back(ed6);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);

    auto structId = findStructureId<GraphDistVisitor>(g);

    string answer = "Dist0Dist1Dist1Dist1Dist2Dist2Dist3";
    BOOST_CHECK_EQUAL(structId, answer);
  }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Added reduced graph test<commit_after>/*
 *            Copyright 2009-2018 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE graphalgorithm_test
#include <boost/test/unit_test.hpp>
#include <memory>
#include <unordered_map>
#include <vector>
#include <votca/tools/graph.h>
#include <votca/tools/reducedgraph.h>
#include <votca/tools/graph_bf_visitor.h>
#include <votca/tools/graphalgorithm.h>
#include <votca/tools/graphdistvisitor.h>
#include <votca/tools/graphnode.h>

using namespace std;
using namespace votca::tools;

using namespace boost;
using namespace boost::unit_test;

BOOST_AUTO_TEST_SUITE(graphalgorithm_test)

BOOST_AUTO_TEST_CASE(single_network_algorithm_test) {
  {
    // In this test we add two nodes and an edge describing
    // their connection thus the singleNetwork function will
    // return true.

    // Create edge
    Edge ed(0, 1);
    vector<Edge> edges;
    edges.push_back(ed);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;

    Graph g(edges, nodes);

    Graph_BF_Visitor gb_v;

    BOOST_CHECK(gb_v.queEmpty());
    //gb_v.exec(g,ed);
    BOOST_CHECK_THROW(gb_v.exec(g, ed), runtime_error);

    bool single_n = singleNetwork(g, gb_v);
    cerr << "is single network " << single_n << endl;
    BOOST_CHECK(single_n);
    BOOST_CHECK(gb_v.queEmpty());

    Graph_BF_Visitor gb_v2;
    gb_v2.setStartingVertex(2);
    BOOST_CHECK_THROW(singleNetwork(g, gb_v2), invalid_argument);
  }

  {

    // In this test we add 3 nodes but only one edge
    // this means that one of the nodes will not be
    // attached to the other two. Thus the singleNetwork
    // function should return false.

    // Create edge
    Edge ed(0, 1);
    vector<Edge> edges;
    edges.push_back(ed);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;

    Graph g(edges, nodes);

    Graph_BF_Visitor gb_v;

    BOOST_CHECK(gb_v.queEmpty());
    BOOST_CHECK_THROW(gb_v.exec(g, ed), runtime_error);

    bool single_n = singleNetwork(g, gb_v);
    BOOST_CHECK(!single_n);
    BOOST_CHECK(gb_v.queEmpty());
  }
}

BOOST_AUTO_TEST_CASE(reduceGraph_algorithm_test) {
  {
    // Create edge
    //     2
    //     |
    // 0 - 1 - 3
    //     |
    //     4

    Edge ed1(0, 1);
    Edge ed2(1, 2);
    Edge ed3(1, 3);
    Edge ed4(1, 4);

    //
    // 5 - 6
    //
    Edge ed5(5, 6);

    vector<Edge> edges;
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    //
    // 5 - 6
    //
    Edge ed5(5, 6);

    vector<Edge> edges;
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);
    vector<std::shared_ptr<Graph>> sub_graphs = decoupleIsolatedSubGraphs(g);
    BOOST_CHECK_EQUAL(sub_graphs.size(), 2);

    // Create sub graphs to compare with the graphs stored in 'sub_graphs'

    vector<Edge> sub_graph1_edges;
    sub_graph1_edges.push_back(ed1);
    sub_graph1_edges.push_back(ed2);
    sub_graph1_edges.push_back(ed3);
    sub_graph1_edges.push_back(ed4);

    vector<Edge> sub_graph2_edges;
    sub_graph2_edges.push_back(ed5);

    unordered_map<int, GraphNode> sub_graph1_nodes;
    sub_graph1_nodes[0] = gn1;
    sub_graph1_nodes[1] = gn2;
    sub_graph1_nodes[2] = gn3;
    sub_graph1_nodes[3] = gn4;
    sub_graph1_nodes[4] = gn5;

    unordered_map<int, GraphNode> sub_graph2_nodes;
    sub_graph2_nodes[0] = gn6;
    sub_graph2_nodes[1] = gn7;

    Graph sub_graph1(sub_graph1_edges, sub_graph1_nodes);
    Graph sub_graph2(sub_graph2_edges, sub_graph2_nodes);

    // Cycle sub_graphs
    bool sub_graph1_found = false;
    bool sub_graph2_found = false;

    for (auto graph_sub_it = sub_graphs.begin();
         graph_sub_it != sub_graphs.end(); ++graph_sub_it) {
      if (**graph_sub_it == sub_graph1) sub_graph1_found = true;
      if (**graph_sub_it == sub_graph2) sub_graph2_found = true;
    }
    BOOST_CHECK(sub_graph1_found);
    BOOST_CHECK(sub_graph2_found);
  }
}

BOOST_AUTO_TEST_CASE(structureid_test) {
  {

    // Create edge
    Edge ed(0, 1);
    Edge ed1(1, 2);
    Edge ed2(2, 3);
    Edge ed3(3, 4);
    Edge ed4(4, 5);
    Edge ed5(5, 0);
    Edge ed6(3, 6);

    vector<Edge> edges;
    edges.push_back(ed);
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);
    edges.push_back(ed6);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);

    auto structId = findStructureId<GraphDistVisitor>(g);

    string answer = "Dist0Dist1Dist1Dist1Dist2Dist2Dist3";
    BOOST_CHECK_EQUAL(structId, answer);
  }
}

BOOST_AUTO_TEST_SUITE_END()
/*
 *            Copyright 2009-2018 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE graphalgorithm_test
#include <boost/test/unit_test.hpp>
#include <unordered_map>
#include <vector>
#include <votca/tools/graph.h>
#include <votca/tools/graph_bf_visitor.h>
#include <votca/tools/graphalgorithm.h>
#include <votca/tools/graphdistvisitor.h>
#include <votca/tools/graphnode.h>

using namespace std;
using namespace votca::tools;

using namespace boost;
using namespace boost::unit_test;

BOOST_AUTO_TEST_SUITE(graphalgorithm_test)

BOOST_AUTO_TEST_CASE(single_network_algorithm_test) {
  {
    // In this test we add two nodes and an edge describing
    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);
    vector<std::shared_ptr<Graph>> sub_graphs = decoupleIsolatedSubGraphs(g);
    BOOST_CHECK_EQUAL(sub_graphs.size(), 2);

    // Create sub graphs to compare with the graphs stored in 'sub_graphs'

    vector<Edge> sub_graph1_edges;
    sub_graph1_edges.push_back(ed1);
    sub_graph1_edges.push_back(ed2);
    sub_graph1_edges.push_back(ed3);
    sub_graph1_edges.push_back(ed4);

    vector<Edge> sub_graph2_edges;
    sub_graph2_edges.push_back(ed5);

    unordered_map<int, GraphNode> sub_graph1_nodes;
    sub_graph1_nodes[0] = gn1;
    sub_graph1_nodes[1] = gn2;
    sub_graph1_nodes[2] = gn3;
    sub_graph1_nodes[3] = gn4;
    sub_graph1_nodes[4] = gn5;

    unordered_map<int, GraphNode> sub_graph2_nodes;
    sub_graph2_nodes[0] = gn6;
    sub_graph2_nodes[1] = gn7;

    Graph sub_graph1(sub_graph1_edges, sub_graph1_nodes);
    Graph sub_graph2(sub_graph2_edges, sub_graph2_nodes);

    // Cycle sub_graphs
    bool sub_graph1_found = false;
    bool sub_graph2_found = false;

    for (auto graph_sub_it = sub_graphs.begin();
         graph_sub_it != sub_graphs.end(); ++graph_sub_it) {
      if (**graph_sub_it == sub_graph1) sub_graph1_found = true;
      if (**graph_sub_it == sub_graph2) sub_graph2_found = true;
    }
    BOOST_CHECK(sub_graph1_found);
    BOOST_CHECK(sub_graph2_found);
  }
}

BOOST_AUTO_TEST_CASE(structureid_test) {
  {

    // Create edge
    Edge ed(0, 1);
    Edge ed1(1, 2);
    Edge ed2(2, 3);
    Edge ed3(3, 4);
    Edge ed4(4, 5);
    Edge ed5(5, 0);
    Edge ed6(3, 6);

    vector<Edge> edges;
    edges.push_back(ed);
    edges.push_back(ed1);
    edges.push_back(ed2);
    edges.push_back(ed3);
    edges.push_back(ed4);
    edges.push_back(ed5);
    edges.push_back(ed6);

    // Create Graph nodes
    GraphNode gn1;
    GraphNode gn2;
    GraphNode gn3;
    GraphNode gn4;
    GraphNode gn5;
    GraphNode gn6;
    GraphNode gn7;

    unordered_map<int, GraphNode> nodes;
    nodes[0] = gn1;
    nodes[1] = gn2;
    nodes[2] = gn3;
    nodes[3] = gn4;
    nodes[4] = gn5;
    nodes[5] = gn6;
    nodes[6] = gn7;

    Graph g(edges, nodes);

    auto structId = findStructureId<GraphDistVisitor>(g);

    string answer = "Dist0Dist1Dist1Dist1Dist2Dist2Dist3";
    BOOST_CHECK_EQUAL(structId, answer);
  }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <map>
#include <stack>

#include "splice-pool.hpp"
#include "gtest/gtest.h"

namespace
{
    const std::vector<int> values{3, 1, 4, 1, 5, 9};

    std::vector<splicer::Node<int>> makeNodes()
    {
        std::vector<splicer::Node<int>> nodes(values.size());

        for (std::size_t i(0); i < values.size(); ++i)
        {
            nodes[i].val() = values[i];
        }

        return nodes;
    }

    splicer::Stack<int> makeStack(std::vector<splicer::Node<int>>& nodes)
    {
        splicer::Stack<int> stack;

        for (std::size_t i(0); i < nodes.size(); ++i)
        {
            stack.push(&nodes[i]);
        }

        return stack;
    }

    // If we're checking stack contents we don't care about the order.  This
    // utility tracks that all values are present.
    template<typename T>
    class Counter
    {
    public:
        void add(T val) { ++m_counts[val]; }

        bool sub(T val)
        {
            if (!m_counts.count(val)) return false;
            if (!--m_counts[val]) m_counts.erase(val);

            return true;
        }

        bool empty() const { return m_counts.empty(); }

    private:
        std::map<T, int> m_counts;
    };
}

TEST(Stack, PopEmpty)
{
    splicer::Stack<int> stack;
    splicer::Node<int>* node(nullptr);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_NO_THROW(node = stack.pop());

    EXPECT_EQ(node, nullptr);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
}

TEST(Stack, PushNode)
{
    splicer::Stack<int> stack;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    EXPECT_TRUE(stack.empty());

    stack.push(&node);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);

    EXPECT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
}

TEST(Stack, PushStack)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    other.push(&node);
    EXPECT_FALSE(other.empty());
    EXPECT_EQ(other.size(), 1);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);

    stack.push(other);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(other.size(), 0);

    ASSERT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_EQ(other.size(), 0);
}

TEST(Stack, PopStackEmpty)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    EXPECT_NO_THROW(other = stack.popStack(1));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());

    EXPECT_NO_THROW(other = stack.popStack(0));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackZero)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(0));

    ASSERT_EQ(stack.size(), total);
    ASSERT_FALSE(stack.empty());

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackPartial)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(2));

    EXPECT_EQ(stack.size(), total - 2);
    EXPECT_EQ(other.size(), 2);

    Counter<int> stackCounter;
    Counter<int> otherCounter;

    for (std::size_t i(0); i < values.size(); ++i)
    {
        if (i < total - 2) stackCounter.add(values[i]);
        else otherCounter.add(values[i]);
    }

    while (!other.empty())
    {
        ASSERT_TRUE(otherCounter.sub(other.pop()->val()));
    }

    while (!stack.empty())
    {
        ASSERT_TRUE(stackCounter.sub(stack.pop()->val()));
    }

    ASSERT_TRUE(stack.empty());
    ASSERT_TRUE(other.empty());

    ASSERT_TRUE(stackCounter.empty());
    ASSERT_TRUE(otherCounter.empty());
}

TEST(Stack, PopStackFull)
{
    // TODO
}

TEST(Stack, PopStackTooMany)
{
    // TODO
}

TEST(Stack, PushPopSingle)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&](std::size_t i)->void
    {
        const int value(values.at(i));
        splicer::Node<int>& node(nodes.at(i));

        ASSERT_EQ(value, node.val());

        validator.push(value);
        stack.push(&node);

        ASSERT_FALSE(validator.empty());
        ASSERT_FALSE(stack.empty());
        ASSERT_EQ(stack.size(), i + 1);
        ASSERT_EQ(stack.size(), validator.size());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    for (std::size_t i(0); i < values.size(); ++i) doPush(i);

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

TEST(Stack, PushPopOtherStack)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&]()->void
    {
        splicer::Stack<int> other;

        for (auto& node : nodes)
        {
            other.push(&node);
            validator.push(node.val());
        }

        ASSERT_FALSE(other.empty());
        ASSERT_TRUE(stack.empty());

        stack.push(other);

        ASSERT_TRUE(other.empty());
        ASSERT_FALSE(stack.empty());

        ASSERT_FALSE(validator.empty());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    doPush();

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

<commit_msg>Add the rest of the popStack test cases.<commit_after>#include <map>
#include <stack>

#include "splice-pool.hpp"
#include "gtest/gtest.h"

namespace
{
    const std::vector<int> values{3, 1, 4, 1, 5, 9};

    std::vector<splicer::Node<int>> makeNodes()
    {
        std::vector<splicer::Node<int>> nodes(values.size());

        for (std::size_t i(0); i < values.size(); ++i)
        {
            nodes[i].val() = values[i];
        }

        return nodes;
    }

    splicer::Stack<int> makeStack(std::vector<splicer::Node<int>>& nodes)
    {
        splicer::Stack<int> stack;

        for (std::size_t i(0); i < nodes.size(); ++i)
        {
            stack.push(&nodes[i]);
        }

        return stack;
    }

    // If we're checking stack contents we don't care about the order.  This
    // utility tracks that all values are present.
    template<typename T>
    class Counter
    {
    public:
        void add(T val) { ++m_counts[val]; }

        bool sub(T val)
        {
            if (!m_counts.count(val)) return false;
            if (!--m_counts[val]) m_counts.erase(val);

            return true;
        }

        bool empty() const { return m_counts.empty(); }

    private:
        std::map<T, int> m_counts;
    };
}

TEST(Stack, PopEmpty)
{
    splicer::Stack<int> stack;
    splicer::Node<int>* node(nullptr);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_NO_THROW(node = stack.pop());

    EXPECT_EQ(node, nullptr);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
}

TEST(Stack, PushNode)
{
    splicer::Stack<int> stack;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    EXPECT_TRUE(stack.empty());

    stack.push(&node);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);

    EXPECT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
}

TEST(Stack, PushStack)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    other.push(&node);
    EXPECT_FALSE(other.empty());
    EXPECT_EQ(other.size(), 1);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);

    stack.push(other);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(other.size(), 0);

    ASSERT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_EQ(other.size(), 0);
}

TEST(Stack, PopStackEmpty)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    EXPECT_NO_THROW(other = stack.popStack(1));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());

    EXPECT_NO_THROW(other = stack.popStack(0));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackZero)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(0));

    ASSERT_EQ(stack.size(), total);
    ASSERT_FALSE(stack.empty());

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackPartial)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(2));

    EXPECT_EQ(stack.size(), total - 2);
    EXPECT_EQ(other.size(), 2);

    Counter<int> stackCounter;
    Counter<int> otherCounter;

    for (std::size_t i(0); i < values.size(); ++i)
    {
        if (i < total - 2) stackCounter.add(values[i]);
        else otherCounter.add(values[i]);
    }

    while (!other.empty())
    {
        ASSERT_TRUE(otherCounter.sub(other.pop()->val()));
    }

    while (!stack.empty())
    {
        ASSERT_TRUE(stackCounter.sub(stack.pop()->val()));
    }

    ASSERT_TRUE(stack.empty());
    ASSERT_TRUE(other.empty());

    ASSERT_TRUE(stackCounter.empty());
    ASSERT_TRUE(otherCounter.empty());
}

TEST(Stack, PopStackFull)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    Counter<int> counter;
    for (const auto v : values) counter.add(v);

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    while (!other.empty())
    {
        ASSERT_TRUE(counter.sub(other.pop()->val()));
    }

    EXPECT_TRUE(counter.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackTooMany)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    Counter<int> counter;
    for (const auto v : values) counter.add(v);

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total + 1));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    while (!other.empty())
    {
        ASSERT_TRUE(counter.sub(other.pop()->val()));
    }

    EXPECT_TRUE(counter.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PushPopSingle)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&](std::size_t i)->void
    {
        const int value(values.at(i));
        splicer::Node<int>& node(nodes.at(i));

        ASSERT_EQ(value, node.val());

        validator.push(value);
        stack.push(&node);

        ASSERT_FALSE(validator.empty());
        ASSERT_FALSE(stack.empty());
        ASSERT_EQ(stack.size(), i + 1);
        ASSERT_EQ(stack.size(), validator.size());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    for (std::size_t i(0); i < values.size(); ++i) doPush(i);

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

TEST(Stack, PushPopOtherStack)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&]()->void
    {
        splicer::Stack<int> other;

        for (auto& node : nodes)
        {
            other.push(&node);
            validator.push(node.val());
        }

        ASSERT_FALSE(other.empty());
        ASSERT_TRUE(stack.empty());

        stack.push(other);

        ASSERT_TRUE(other.empty());
        ASSERT_FALSE(stack.empty());

        ASSERT_FALSE(validator.empty());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    doPush();

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

<|endoftext|>


<commit_before>#include <map>
#include <stack>

#include "splice-pool.hpp"
#include "gtest/gtest.h"

namespace
{
    const std::vector<int> values{3, 1, 4, 1, 5, 9};

    std::vector<splicer::Node<int>> makeNodes()
    {
        std::vector<splicer::Node<int>> nodes(values.size());

        for (std::size_t i(0); i < values.size(); ++i)
        {
            nodes[i].val() = values[i];
        }

        return nodes;
    }

    splicer::Stack<int> makeStack(std::vector<splicer::Node<int>>& nodes)
    {
        splicer::Stack<int> stack;

        for (std::size_t i(0); i < nodes.size(); ++i)
        {
            stack.push(&nodes[i]);
        }

        return stack;
    }

    // If we're checking stack contents we don't care about the order.  This
    // utility tracks that all values are present.
    template<typename T>
    class Counter
    {
    public:
        void add(T val) { ++m_counts[val]; }

        bool sub(T val)
        {
            if (!m_counts.count(val)) return false;
            if (!--m_counts[val]) m_counts.erase(val);

            return true;
        }

        bool empty() const { return m_counts.empty(); }

    private:
        std::map<T, int> m_counts;
    };
}

TEST(Stack, PopEmpty)
{
    splicer::Stack<int> stack;
    splicer::Node<int>* node(nullptr);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_NO_THROW(node = stack.pop());

    EXPECT_EQ(node, nullptr);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
}

TEST(Stack, PushNode)
{
    splicer::Stack<int> stack;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    EXPECT_TRUE(stack.empty());

    stack.push(&node);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);

    EXPECT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
}

TEST(Stack, Swap)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    splicer::Stack<int> other;

    EXPECT_EQ(stack.size(), values.size());
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(other.size(), 0);
    EXPECT_TRUE(other.empty());

    stack.swap(other);

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), values.size());
    EXPECT_FALSE(other.empty());

    for (std::size_t i(0); i < values.size(); ++i)
    {
        ASSERT_EQ(other.pop()->val(), values[values.size() - i - 1]);
    }

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PushStack)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    other.push(&node);
    EXPECT_FALSE(other.empty());
    EXPECT_EQ(other.size(), 1);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);

    stack.push(other);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(other.size(), 0);

    ASSERT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_EQ(other.size(), 0);
}

TEST(Stack, PopStackEmpty)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    EXPECT_NO_THROW(other = stack.popStack(1));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());

    EXPECT_NO_THROW(other = stack.popStack(0));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackZero)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(0));

    ASSERT_EQ(stack.size(), total);
    ASSERT_FALSE(stack.empty());

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackPartial)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(2));

    EXPECT_EQ(stack.size(), total - 2);
    EXPECT_EQ(other.size(), 2);

    std::size_t i(total);

    while (--i < total)
    {
        const auto check(values[i]);

        if (i >= 4) ASSERT_EQ(other.pop()->val(), check);
        else ASSERT_EQ(stack.pop()->val(), check);
    }

    ASSERT_TRUE(stack.empty());
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackFull)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    for (std::size_t i(total - 1); i < total; --i)
    {
        ASSERT_EQ(other.pop()->val(), values[i]);
    }

    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackTooMany)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total * 2));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    for (std::size_t i(total - 1); i < total; --i)
    {
        ASSERT_EQ(other.pop()->val(), values[i]);
    }

    EXPECT_TRUE(other.empty());
}

TEST(Stack, PushPopSingle)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&](std::size_t i)->void
    {
        const int value(values.at(i));
        splicer::Node<int>& node(nodes.at(i));

        ASSERT_EQ(value, node.val());

        validator.push(value);
        stack.push(&node);

        ASSERT_FALSE(validator.empty());
        ASSERT_FALSE(stack.empty());
        ASSERT_EQ(stack.size(), i + 1);
        ASSERT_EQ(stack.size(), validator.size());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    for (std::size_t i(0); i < values.size(); ++i) doPush(i);

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

TEST(Stack, PushPopOtherStack)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&]()->void
    {
        splicer::Stack<int> other;

        for (auto& node : nodes)
        {
            other.push(&node);
            validator.push(node.val());
        }

        ASSERT_FALSE(other.empty());
        ASSERT_TRUE(stack.empty());

        stack.push(other);

        ASSERT_TRUE(other.empty());
        ASSERT_FALSE(stack.empty());

        ASSERT_FALSE(validator.empty());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    doPush();

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

<commit_msg>Remove an unused testing class.<commit_after>#include <map>
#include <stack>

#include "splice-pool.hpp"
#include "gtest/gtest.h"

namespace
{
    const std::vector<int> values{3, 1, 4, 1, 5, 9};

    std::vector<splicer::Node<int>> makeNodes()
    {
        std::vector<splicer::Node<int>> nodes(values.size());

        for (std::size_t i(0); i < values.size(); ++i)
        {
            nodes[i].val() = values[i];
        }

        return nodes;
    }

    splicer::Stack<int> makeStack(std::vector<splicer::Node<int>>& nodes)
    {
        splicer::Stack<int> stack;

        for (std::size_t i(0); i < nodes.size(); ++i)
        {
            stack.push(&nodes[i]);
        }

        return stack;
    }
}

TEST(Stack, PopEmpty)
{
    splicer::Stack<int> stack;
    splicer::Node<int>* node(nullptr);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_NO_THROW(node = stack.pop());

    EXPECT_EQ(node, nullptr);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);
}

TEST(Stack, PushNode)
{
    splicer::Stack<int> stack;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    EXPECT_TRUE(stack.empty());

    stack.push(&node);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);

    EXPECT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
}

TEST(Stack, Swap)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    splicer::Stack<int> other;

    EXPECT_EQ(stack.size(), values.size());
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(other.size(), 0);
    EXPECT_TRUE(other.empty());

    stack.swap(other);

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), values.size());
    EXPECT_FALSE(other.empty());

    for (std::size_t i(0); i < values.size(); ++i)
    {
        ASSERT_EQ(other.pop()->val(), values[values.size() - i - 1]);
    }

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PushStack)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    const int value(4);

    splicer::Node<int> node;
    node.val() = value;

    other.push(&node);
    EXPECT_FALSE(other.empty());
    EXPECT_EQ(other.size(), 1);

    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(stack.size(), 0);

    stack.push(other);
    EXPECT_FALSE(stack.empty());
    EXPECT_EQ(stack.size(), 1);
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(other.size(), 0);

    ASSERT_EQ(stack.pop()->val(), value);
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
    EXPECT_EQ(stack.size(), 0);
    EXPECT_EQ(other.size(), 0);
}

TEST(Stack, PopStackEmpty)
{
    splicer::Stack<int> stack;
    splicer::Stack<int> other;

    EXPECT_NO_THROW(other = stack.popStack(1));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());

    EXPECT_NO_THROW(other = stack.popStack(0));
    EXPECT_TRUE(stack.empty());
    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackZero)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(0));

    ASSERT_EQ(stack.size(), total);
    ASSERT_FALSE(stack.empty());

    ASSERT_EQ(other.size(), 0);
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackPartial)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    splicer::Stack<int> other(stack.popStack(2));

    EXPECT_EQ(stack.size(), total - 2);
    EXPECT_EQ(other.size(), 2);

    std::size_t i(total);

    while (--i < total)
    {
        const auto check(values[i]);

        if (i >= 4) ASSERT_EQ(other.pop()->val(), check);
        else ASSERT_EQ(stack.pop()->val(), check);
    }

    ASSERT_TRUE(stack.empty());
    ASSERT_TRUE(other.empty());
}

TEST(Stack, PopStackFull)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    for (std::size_t i(total - 1); i < total; --i)
    {
        ASSERT_EQ(other.pop()->val(), values[i]);
    }

    EXPECT_TRUE(other.empty());
}

TEST(Stack, PopStackTooMany)
{
    std::vector<splicer::Node<int>> nodes(makeNodes());
    splicer::Stack<int> stack(makeStack(nodes));

    const std::size_t total(values.size());

    ASSERT_EQ(stack.size(), total);

    splicer::Stack<int> other(stack.popStack(total * 2));

    EXPECT_EQ(stack.size(), 0);
    EXPECT_TRUE(stack.empty());
    EXPECT_EQ(other.size(), total);
    EXPECT_FALSE(other.empty());

    for (std::size_t i(total - 1); i < total; --i)
    {
        ASSERT_EQ(other.pop()->val(), values[i]);
    }

    EXPECT_TRUE(other.empty());
}

TEST(Stack, PushPopSingle)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&](std::size_t i)->void
    {
        const int value(values.at(i));
        splicer::Node<int>& node(nodes.at(i));

        ASSERT_EQ(value, node.val());

        validator.push(value);
        stack.push(&node);

        ASSERT_FALSE(validator.empty());
        ASSERT_FALSE(stack.empty());
        ASSERT_EQ(stack.size(), i + 1);
        ASSERT_EQ(stack.size(), validator.size());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    for (std::size_t i(0); i < values.size(); ++i) doPush(i);

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

TEST(Stack, PushPopOtherStack)
{
    std::stack<int> validator;
    splicer::Stack<int> stack;
    std::vector<splicer::Node<int>> nodes(makeNodes());

    auto doPush([&]()->void
    {
        splicer::Stack<int> other;

        for (auto& node : nodes)
        {
            other.push(&node);
            validator.push(node.val());
        }

        ASSERT_FALSE(other.empty());
        ASSERT_TRUE(stack.empty());

        stack.push(other);

        ASSERT_TRUE(other.empty());
        ASSERT_FALSE(stack.empty());

        ASSERT_FALSE(validator.empty());
    });

    auto doPop([&](std::size_t i)->void
    {
        const int value(values.at(i));

        ASSERT_EQ(value, validator.top());
        validator.pop();

        ASSERT_EQ(value, stack.pop()->val());
        ASSERT_EQ(validator.empty(), stack.empty());
    });

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());

    doPush();

    ASSERT_FALSE(validator.empty());
    ASSERT_FALSE(stack.empty());

    for (std::size_t i(values.size() - 1); i < values.size(); --i) doPop(i);

    ASSERT_TRUE(validator.empty());
    ASSERT_TRUE(stack.empty());
}

<|endoftext|>


<commit_before>/****************************************************************************
*  themefile.cpp - Theme file handling
*
*  Copyright (C) 2003 Hans Karlsson <karlsson.h@home.se>
*  Copyright (C) 2003-2004 Adam Geitgey <adam@rootnode.org>
*  Copyright (c) 2004 Petri Damstn <damu@iki.fi>
*
*  This file is part of SuperKaramba.
*
*  SuperKaramba is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  SuperKaramba is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with SuperKaramba; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************/
#include "themefile.h"
#include "lineparser.h"
#include "themelocale.h"
#include <kdebug.h>
#include <kurl.h>
#include <kzip.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <qtextstream.h>
#include <qfileinfo.h>
#include <qdom.h>
#include <qdir.h>

class ZipFile
{
  public:
    ZipFile(const QString& zipfile, const QString& filename) :
      m_zip(0), m_file(0), m_filename(filename)
    {
      if(filename.isEmpty())
        return;

      const KArchiveDirectory* dir;
      const KArchiveEntry* entry;

      m_zip = new KZip(zipfile);

      if(!m_zip->open(IO_ReadOnly))
      {
        qDebug("Unable to open '%s' for reading.", zipfile.ascii());
        return;
      }
      dir = m_zip->directory();
      if(dir == 0)
      {
        qDebug("Error reading directory contents of file %s", zipfile.ascii());
        return;
      }

      entry = dir->entry(filename);
      if(entry == 0 || !entry->isFile())
        return;

      m_file = static_cast<const KArchiveFile*>(entry);
    }

    virtual ~ZipFile()
    {
      if(m_zip)
      {
        m_zip->close();
        delete  m_zip;
      }
    }

    QByteArray data()
    {
      if(m_file)
        return m_file->data();
      else
      {
        if(!m_filename.isEmpty())
          qDebug("Error reading file %s from zip", m_filename.ascii());
        return QByteArray();
      }
    }

    bool exists()
    {
      return (m_file != 0);
    }

  private:
    KZip* m_zip;
    const KArchiveFile* m_file;
    QString m_filename;
};

ThemeFile::ThemeFile(const KURL& url)
  : m_stream(0), m_locale(0)
{
  if(url.isValid())
    set(url);
}

ThemeFile::~ThemeFile()
{
  delete m_stream;
  delete m_locale;
}

bool ThemeFile::open()
{
  bool result = false;

  close();

  if(m_zipTheme)
  {
    ZipFile zf(m_file, m_theme);
    m_ba = zf.data();
    if(m_ba.size() > 0)
    {
      m_stream = new QTextStream(m_ba, IO_ReadOnly);
      result = true;
    }
  }
  else
  {
    m_fl.setName(m_file);

    if(m_fl.open(IO_ReadOnly|IO_Translate))
    {
      m_stream = new QTextStream(&m_fl);        // use a text stream
      result = true;
    }
  }
  return result;
}

bool ThemeFile::nextLine(LineParser& parser)
{
  parser.set("");

  if(m_stream)
  {
    QString result = m_stream->readLine();

    if(result.isNull())
      return false;
    parser.set(result);
    return true;
  }
  return false;
}

bool ThemeFile::close()
{
  if(m_stream)
  {
    delete m_stream;
    m_stream = 0;
    m_fl.close();
    m_ba.resize(0);
    return true;
  }
  return false;
}

bool ThemeFile::isValid() const
{
  return (exists() && !m_name.isEmpty() && !m_theme.isEmpty());
}

bool ThemeFile::exists() const
{
  QFileInfo file(m_file);
  return file.exists();
}

QPixmap ThemeFile::icon() const
{
  return QPixmap(readThemeFile(m_icon));
}

bool ThemeFile::set(const KURL &url)
{
  if(!url.isLocalFile() && !url.protocol().isEmpty())
  {
    if(KMessageBox::questionYesNo(kapp->activeWindow(),
       i18n("You are about to install and run %1 SuperKaramba theme. Since "
            "themes can contain executable code you should only install themes "
            "from sources that you trust. Continue?")
           .arg(url.prettyURL()))
       == KMessageBox::No)
    {
      return false;
    }

    QDir themeDir(locateLocal("appdata", "themes/", true));
    QFileInfo localFile = themeDir.filePath(url.fileName());

    if(localFile.exists())
    {
      if(KMessageBox::questionYesNo(kapp->activeWindow(),
         i18n("%1 already exists. Do you want to overwrite it?")
             .arg(localFile.filePath()))
         == KMessageBox::No)
      {
        return false;
      }
    }
    if(!KIO::NetAccess::file_copy(url, localFile.filePath(), -1, true,
      false, kapp->mainWidget()))
    {
      return false;
    }
    m_file = localFile.filePath();
  }
  else
  {
    if(url.directory().isEmpty() or url.directory() == "/")
      m_file = canonicalFile(QDir::current().filePath(url.fileName()));
    else
      m_file = canonicalFile(url.path());
    if(!exists())
      return false;
  }

  QFileInfo fi(m_file);

  m_name = fi.baseName();
  m_theme = m_name + ".theme";
  m_python = m_name;
  m_id = m_name;

  if(isZipFile(m_file))
  {
    m_path = m_file;
    m_zipTheme = true;
  }
  else
  {
    m_path = fi.dirPath(true) + "/";
    m_zipTheme = false;
  }
  parseXml();

  QFileInfo fimo(m_python);
  if(m_python.isEmpty())
    fimo.setFile(m_theme);
  else
    fimo.setFile(m_python);
  m_mo = fimo.baseName();

  m_locale = new ThemeLocale(this);
  return isValid();
}

void ThemeFile::parseXml()
{
  if(!fileExists("maindata.xml"))
    return;
  QByteArray ba = readThemeFile("maindata.xml");
  QDomDocument doc("superkaramba_theme");
  doc.setContent(ba);
  QDomElement element = doc.documentElement();

  QDomNode n = element.firstChild();
  while(!n.isNull())
  {
    QDomElement e = n.toElement();
    if(!e.isNull())
    {
      if(e.tagName() == "name")
        m_name = e.text();
      else if(e.tagName() == "themefile")
        m_theme = e.text();
      else if(e.tagName() == "python_module")
      {
        m_python = e.text();
        if(m_python.right(3).lower() == ".py")
          m_python.remove(m_python.length() - 3, 3);
      }
      else if(e.tagName() == "description")
        m_description = e.text();
      else if(e.tagName() == "author")
        m_author = e.text();
      else if(e.tagName() == "author_email")
        m_authorEmail = e.text();
      else if(e.tagName() == "homepage")
        m_homepage = e.text();
      else if(e.tagName() == "icon")
        m_icon = e.text();
      else if(e.tagName() == "version")
        m_version = e.text();
      else if(e.tagName() == "license")
        m_license = e.text();
    }
    n = n.nextSibling();
  }
}

bool ThemeFile::isThemeFile(const QString& filename) const
{
  QFileInfo fileInfo(filename);

  return fileInfo.isRelative();
}

bool ThemeFile::fileExists(const QString& filename) const
{
  if(isThemeFile(filename))
  {
    if(isZipTheme())
    {
      ZipFile zf(m_file, filename);
      return zf.exists();
    }
    else
      return QFileInfo(path() + "/" + filename).exists();
  }
  else
    return QFileInfo(filename).exists();
}

QByteArray ThemeFile::readThemeFile(const QString& filename) const
{
  QByteArray ba;

  if(isZipTheme())
  {
    ZipFile zf(m_file, filename);
    ba = zf.data();
  }
  else
  {
    QFile file(path() + "/" + filename);

    if(file.open(IO_ReadOnly))
    {
      ba = file.readAll();
      file.close();
    }
  }
  return ba;
}

bool ThemeFile::isZipFile(const QString& filename)
{
  QFile file(filename);

  if(file.open(IO_ReadOnly))
  {
    unsigned char buf[5];

    if(file.readBlock((char*)buf, 4) == 4)
    {
      if(buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4)
        return true;
    }
  }
  return false;
}

bool ThemeFile::pythonModuleExists() const
{
  return (!m_python.isEmpty() && fileExists(m_python + ".py"));
}

QString ThemeFile::canonicalFile(const QString& file)
{
  // Get absolute path with NO symlinks
  QFileInfo fi(file);
  return QDir(fi.dir().canonicalPath()).filePath(fi.fileName());
}
<commit_msg>kdereview reviewed for Yes/No buttons<commit_after>/****************************************************************************
*  themefile.cpp - Theme file handling
*
*  Copyright (C) 2003 Hans Karlsson <karlsson.h@home.se>
*  Copyright (C) 2003-2004 Adam Geitgey <adam@rootnode.org>
*  Copyright (c) 2004 Petri Damst� <damu@iki.fi>
*
*  This file is part of SuperKaramba.
*
*  SuperKaramba is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  SuperKaramba is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with SuperKaramba; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************/
#include "themefile.h"
#include "lineparser.h"
#include "themelocale.h"
#include <kdebug.h>
#include <kurl.h>
#include <kzip.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <qtextstream.h>
#include <qfileinfo.h>
#include <qdom.h>
#include <qdir.h>

class ZipFile
{
  public:
    ZipFile(const QString& zipfile, const QString& filename) :
      m_zip(0), m_file(0), m_filename(filename)
    {
      if(filename.isEmpty())
        return;

      const KArchiveDirectory* dir;
      const KArchiveEntry* entry;

      m_zip = new KZip(zipfile);

      if(!m_zip->open(IO_ReadOnly))
      {
        qDebug("Unable to open '%s' for reading.", zipfile.ascii());
        return;
      }
      dir = m_zip->directory();
      if(dir == 0)
      {
        qDebug("Error reading directory contents of file %s", zipfile.ascii());
        return;
      }

      entry = dir->entry(filename);
      if(entry == 0 || !entry->isFile())
        return;

      m_file = static_cast<const KArchiveFile*>(entry);
    }

    virtual ~ZipFile()
    {
      if(m_zip)
      {
        m_zip->close();
        delete  m_zip;
      }
    }

    QByteArray data()
    {
      if(m_file)
        return m_file->data();
      else
      {
        if(!m_filename.isEmpty())
          qDebug("Error reading file %s from zip", m_filename.ascii());
        return QByteArray();
      }
    }

    bool exists()
    {
      return (m_file != 0);
    }

  private:
    KZip* m_zip;
    const KArchiveFile* m_file;
    QString m_filename;
};

ThemeFile::ThemeFile(const KURL& url)
  : m_stream(0), m_locale(0)
{
  if(url.isValid())
    set(url);
}

ThemeFile::~ThemeFile()
{
  delete m_stream;
  delete m_locale;
}

bool ThemeFile::open()
{
  bool result = false;

  close();

  if(m_zipTheme)
  {
    ZipFile zf(m_file, m_theme);
    m_ba = zf.data();
    if(m_ba.size() > 0)
    {
      m_stream = new QTextStream(m_ba, IO_ReadOnly);
      result = true;
    }
  }
  else
  {
    m_fl.setName(m_file);

    if(m_fl.open(IO_ReadOnly|IO_Translate))
    {
      m_stream = new QTextStream(&m_fl);        // use a text stream
      result = true;
    }
  }
  return result;
}

bool ThemeFile::nextLine(LineParser& parser)
{
  parser.set("");

  if(m_stream)
  {
    QString result = m_stream->readLine();

    if(result.isNull())
      return false;
    parser.set(result);
    return true;
  }
  return false;
}

bool ThemeFile::close()
{
  if(m_stream)
  {
    delete m_stream;
    m_stream = 0;
    m_fl.close();
    m_ba.resize(0);
    return true;
  }
  return false;
}

bool ThemeFile::isValid() const
{
  return (exists() && !m_name.isEmpty() && !m_theme.isEmpty());
}

bool ThemeFile::exists() const
{
  QFileInfo file(m_file);
  return file.exists();
}

QPixmap ThemeFile::icon() const
{
  return QPixmap(readThemeFile(m_icon));
}

bool ThemeFile::set(const KURL &url)
{
  if(!url.isLocalFile() && !url.protocol().isEmpty())
  {
    if(KMessageBox::warningContinueCancel(kapp->activeWindow(),
       i18n("You are about to install and run %1 SuperKaramba theme. Since "
            "themes can contain executable code you should only install themes "
            "from sources that you trust. Continue?"), i18n("Executable Code Warning"), i18n("Install")
           .arg(url.prettyURL()))
       == KMessageBox::Cancel)
    {
      return false;
    }

    QDir themeDir(locateLocal("appdata", "themes/", true));
    QFileInfo localFile = themeDir.filePath(url.fileName());

    if(localFile.exists())
    {
      if(KMessageBox::warningContinueCancel(kapp->activeWindow(),
         i18n("%1 already exists. Do you want to overwrite it?")
             .arg(localFile.filePath()),i18n("File Exists"),i18n("Overwrite"))
         == KMessageBox::Cancel)
      {
        return false;
      }
    }
    if(!KIO::NetAccess::file_copy(url, localFile.filePath(), -1, true,
      false, kapp->mainWidget()))
    {
      return false;
    }
    m_file = localFile.filePath();
  }
  else
  {
    if(url.directory().isEmpty() or url.directory() == "/")
      m_file = canonicalFile(QDir::current().filePath(url.fileName()));
    else
      m_file = canonicalFile(url.path());
    if(!exists())
      return false;
  }

  QFileInfo fi(m_file);

  m_name = fi.baseName();
  m_theme = m_name + ".theme";
  m_python = m_name;
  m_id = m_name;

  if(isZipFile(m_file))
  {
    m_path = m_file;
    m_zipTheme = true;
  }
  else
  {
    m_path = fi.dirPath(true) + "/";
    m_zipTheme = false;
  }
  parseXml();

  QFileInfo fimo(m_python);
  if(m_python.isEmpty())
    fimo.setFile(m_theme);
  else
    fimo.setFile(m_python);
  m_mo = fimo.baseName();

  m_locale = new ThemeLocale(this);
  return isValid();
}

void ThemeFile::parseXml()
{
  if(!fileExists("maindata.xml"))
    return;
  QByteArray ba = readThemeFile("maindata.xml");
  QDomDocument doc("superkaramba_theme");
  doc.setContent(ba);
  QDomElement element = doc.documentElement();

  QDomNode n = element.firstChild();
  while(!n.isNull())
  {
    QDomElement e = n.toElement();
    if(!e.isNull())
    {
      if(e.tagName() == "name")
        m_name = e.text();
      else if(e.tagName() == "themefile")
        m_theme = e.text();
      else if(e.tagName() == "python_module")
      {
        m_python = e.text();
        if(m_python.right(3).lower() == ".py")
          m_python.remove(m_python.length() - 3, 3);
      }
      else if(e.tagName() == "description")
        m_description = e.text();
      else if(e.tagName() == "author")
        m_author = e.text();
      else if(e.tagName() == "author_email")
        m_authorEmail = e.text();
      else if(e.tagName() == "homepage")
        m_homepage = e.text();
      else if(e.tagName() == "icon")
        m_icon = e.text();
      else if(e.tagName() == "version")
        m_version = e.text();
      else if(e.tagName() == "license")
        m_license = e.text();
    }
    n = n.nextSibling();
  }
}

bool ThemeFile::isThemeFile(const QString& filename) const
{
  QFileInfo fileInfo(filename);

  return fileInfo.isRelative();
}

bool ThemeFile::fileExists(const QString& filename) const
{
  if(isThemeFile(filename))
  {
    if(isZipTheme())
    {
      ZipFile zf(m_file, filename);
      return zf.exists();
    }
    else
      return QFileInfo(path() + "/" + filename).exists();
  }
  else
    return QFileInfo(filename).exists();
}

QByteArray ThemeFile::readThemeFile(const QString& filename) const
{
  QByteArray ba;

  if(isZipTheme())
  {
    ZipFile zf(m_file, filename);
    ba = zf.data();
  }
  else
  {
    QFile file(path() + "/" + filename);

    if(file.open(IO_ReadOnly))
    {
      ba = file.readAll();
      file.close();
    }
  }
  return ba;
}

bool ThemeFile::isZipFile(const QString& filename)
{
  QFile file(filename);

  if(file.open(IO_ReadOnly))
  {
    unsigned char buf[5];

    if(file.readBlock((char*)buf, 4) == 4)
    {
      if(buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4)
        return true;
    }
  }
  return false;
}

bool ThemeFile::pythonModuleExists() const
{
  return (!m_python.isEmpty() && fileExists(m_python + ".py"));
}

QString ThemeFile::canonicalFile(const QString& file)
{
  // Get absolute path with NO symlinks
  QFileInfo fi(file);
  return QDir(fi.dir().canonicalPath()).filePath(fi.fileName());
}
<|endoftext|>


<commit_before>#include <time.h>
#include <random>

#include <gtest/gtest.h>

#include <u/vector.h>
#include <u/math.h>

#define VECTOR_DUMP(n) "vector[size='" << ds_size(v ## n) << "', capacity='" << ds_cap(v ## n) << "']"
#define ASSERT_CAPACITY(_q0, _q1, _q2, _q3, _q4) \
  ASSERT_EQ(_q0, ds_cap(v0)) << _q0 << " => " << VECTOR_DUMP(0); \
  ASSERT_EQ(_q1, ds_cap(v1)) << _q1 << " => " << VECTOR_DUMP(1); \
  ASSERT_EQ(_q2, ds_cap(v2)) << _q2 << " => " << VECTOR_DUMP(2); \
  ASSERT_EQ(_q3, ds_cap(v3)) << _q3 << " => " << VECTOR_DUMP(3); \
  ASSERT_EQ(_q4, ds_cap(v4)) << _q4 << " => " << VECTOR_DUMP(4)
#define ASSERT_SIZE(_s0, _s1, _s2, _s3, _s4) \
  ASSERT_EQ(_s0, ds_size(v0)) << _s0 << " => " << VECTOR_DUMP(0); \
  ASSERT_EQ(_s1, ds_size(v1)) << _s1 << " => " << VECTOR_DUMP(1); \
  ASSERT_EQ(_s2, ds_size(v2)) << _s2 << " => " << VECTOR_DUMP(2); \
  ASSERT_EQ(_s3, ds_size(v3)) << _s3 << " => " << VECTOR_DUMP(3); \
  ASSERT_EQ(_s4, ds_size(v4)) << _s4 << " => " << VECTOR_DUMP(4)

struct VectorTest : public ::testing::Test {
  virtual void SetUp() {
    std::random_device rd;
    std::mt19937 eng(rd());

    std::uniform_int_distribution<> dist0(0, 10);
    std::uniform_int_distribution<> dist1(10, 100);
    std::uniform_int_distribution<> dist2(100, 1000);
    std::uniform_int_distribution<> dist3(1000, 10000);
    std::uniform_int_distribution<> dist4(10000, 100000);

    s0 = (size_t) dist0(eng);
    s1 = (size_t) dist1(eng);
    s2 = (size_t) dist2(eng);
    s3 = (size_t) dist3(eng);
    s4 = (size_t) dist4(eng);

    qRoundUp32();
  }

  virtual void TearDown() {
    vec_dtor(v0);
    vec_dtor(v1);
    vec_dtor(v2);
    vec_dtor(v3);
    vec_dtor(v4);
  }

  void qRoundUp32() {
    q0 = roundup32(s0);
    q1 = roundup32(s1);
    q2 = roundup32(s2);
    q3 = roundup32(s3);
    q4 = roundup32(s4);

    if (q0 && q0 < UVEC_MIN_CAPACITY) q0 = UVEC_MIN_CAPACITY;
  }

  struct Point {
    long long x, y;
  };

  size_t s0, q0;
  size_t s1, q1;
  size_t s2, q2;
  size_t s3, q3;
  size_t s4, q4;

  vec_of(int) v0 = {0};
  vec_of(size_t) v1 = {0};
  vec_of(struct { int x; int y; }) v2 = {0};
  vec_of(Point) v3 = {0};
  vec_of(void *) v4 = {0};
};

TEST_F(VectorTest, grow) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, s0);
  vec_grow(v1, s1);
  vec_grow(v2, s2);
  vec_grow(v3, s3);
  vec_grow(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  s0 *= 2;
  s1 *= 2;
  s2 *= 2;
  s3 *= 2;
  s4 *= 2;

  vec_grow(v0, s0);
  vec_grow(v1, s1);
  vec_grow(v2, s2);
  vec_grow(v3, s3);
  vec_grow(v4, s4);

  qRoundUp32();

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, -(s0/2));
  vec_grow(v1, -(s1/2));
  vec_grow(v2, -(s2/2));
  vec_grow(v3, -(s3/2));
  vec_grow(v4, -(s4/2));

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, -s0);
  vec_grow(v1, -s1);
  vec_grow(v2, -s2);
  vec_grow(v3, -s3);
  vec_grow(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, 1);
  vec_grow(v1, 1);
  vec_grow(v2, 1);
  vec_grow(v3, 1);
  vec_grow(v4, 1);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, reserve) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_reserve(v0, s0);
  vec_reserve(v1, s1);
  vec_reserve(v2, s2);
  vec_reserve(v3, s3);
  vec_reserve(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  s0 *= 6;
  s1 *= 5;
  s2 *= 4;
  s3 *= 3;
  s4 *= 2;

  qRoundUp32();

  vec_reserve(v0, s0);
  vec_reserve(v1, s1);
  vec_reserve(v2, s2);
  vec_reserve(v3, s3);
  vec_reserve(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_reserve(v0, -s0);
  vec_reserve(v1, -s1);
  vec_reserve(v2, -s2);
  vec_reserve(v3, -s3);
  vec_reserve(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, resize) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, s0);
  vec_resize(v1, s1);
  vec_resize(v2, s2);
  vec_resize(v3, s3);
  vec_resize(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(s0, s1, s2, s3, s4);

  vec_resize(v0, -s0);
  vec_resize(v1, -s1);
  vec_resize(v2, -s2);
  vec_resize(v3, -s3);
  vec_resize(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, -s0);
  vec_resize(v1, -s1);
  vec_resize(v2, -s2);
  vec_resize(v3, -s3);
  vec_resize(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, 1);
  vec_resize(v1, 1);
  vec_resize(v2, 1);
  vec_resize(v3, 1);
  vec_resize(v4, 1);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(1, 1, 1, 1, 1);

  vec_resize(v0, 0);
  vec_resize(v1, 0);
  vec_resize(v2, 0);
  vec_resize(v3, 0);
  vec_resize(v4, 0);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, push) {

}
<commit_msg>msvc: list initialization inside member initializer<commit_after>#include <time.h>
#include <random>

#include <gtest/gtest.h>

#include <u/vector.h>
#include <u/math.h>

#define VECTOR_DUMP(n) "vector[size='" << ds_size(v ## n) << "', capacity='" << ds_cap(v ## n) << "']"
#define ASSERT_CAPACITY(_q0, _q1, _q2, _q3, _q4) \
  ASSERT_EQ(_q0, ds_cap(v0)) << _q0 << " => " << VECTOR_DUMP(0); \
  ASSERT_EQ(_q1, ds_cap(v1)) << _q1 << " => " << VECTOR_DUMP(1); \
  ASSERT_EQ(_q2, ds_cap(v2)) << _q2 << " => " << VECTOR_DUMP(2); \
  ASSERT_EQ(_q3, ds_cap(v3)) << _q3 << " => " << VECTOR_DUMP(3); \
  ASSERT_EQ(_q4, ds_cap(v4)) << _q4 << " => " << VECTOR_DUMP(4)
#define ASSERT_SIZE(_s0, _s1, _s2, _s3, _s4) \
  ASSERT_EQ(_s0, ds_size(v0)) << _s0 << " => " << VECTOR_DUMP(0); \
  ASSERT_EQ(_s1, ds_size(v1)) << _s1 << " => " << VECTOR_DUMP(1); \
  ASSERT_EQ(_s2, ds_size(v2)) << _s2 << " => " << VECTOR_DUMP(2); \
  ASSERT_EQ(_s3, ds_size(v3)) << _s3 << " => " << VECTOR_DUMP(3); \
  ASSERT_EQ(_s4, ds_size(v4)) << _s4 << " => " << VECTOR_DUMP(4)

struct VectorTest : public ::testing::Test {
  virtual void SetUp() {
    std::random_device rd;
    std::mt19937 eng(rd());

    std::uniform_int_distribution<> dist0(0, 10);
    std::uniform_int_distribution<> dist1(10, 100);
    std::uniform_int_distribution<> dist2(100, 1000);
    std::uniform_int_distribution<> dist3(1000, 10000);
    std::uniform_int_distribution<> dist4(10000, 100000);

    s0 = (size_t) dist0(eng);
    s1 = (size_t) dist1(eng);
    s2 = (size_t) dist2(eng);
    s3 = (size_t) dist3(eng);
    s4 = (size_t) dist4(eng);

    qRoundUp32();

    v0 = {0};
    v1 = {0};
    v2 = {0};
    v3 = {0};
    v4 = {0};
  }

  virtual void TearDown() {
    vec_dtor(v0);
    vec_dtor(v1);
    vec_dtor(v2);
    vec_dtor(v3);
    vec_dtor(v4);
  }

  void qRoundUp32() {
    q0 = roundup32(s0);
    q1 = roundup32(s1);
    q2 = roundup32(s2);
    q3 = roundup32(s3);
    q4 = roundup32(s4);

    if (q0 && q0 < UVEC_MIN_CAPACITY) q0 = UVEC_MIN_CAPACITY;
  }

  struct Point {
    long long x, y;
  };

  size_t s0, q0;
  size_t s1, q1;
  size_t s2, q2;
  size_t s3, q3;
  size_t s4, q4;

  vec_of(int) v0;
  vec_of(size_t) v1;
  vec_of(struct { int x; int y; }) v2;
  vec_of(Point) v3;
  vec_of(void *) v4;
};

TEST_F(VectorTest, grow) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, s0);
  vec_grow(v1, s1);
  vec_grow(v2, s2);
  vec_grow(v3, s3);
  vec_grow(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  s0 *= 2;
  s1 *= 2;
  s2 *= 2;
  s3 *= 2;
  s4 *= 2;

  vec_grow(v0, s0);
  vec_grow(v1, s1);
  vec_grow(v2, s2);
  vec_grow(v3, s3);
  vec_grow(v4, s4);

  qRoundUp32();

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, -(s0/2));
  vec_grow(v1, -(s1/2));
  vec_grow(v2, -(s2/2));
  vec_grow(v3, -(s3/2));
  vec_grow(v4, -(s4/2));

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, -s0);
  vec_grow(v1, -s1);
  vec_grow(v2, -s2);
  vec_grow(v3, -s3);
  vec_grow(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_grow(v0, 1);
  vec_grow(v1, 1);
  vec_grow(v2, 1);
  vec_grow(v3, 1);
  vec_grow(v4, 1);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, reserve) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_reserve(v0, s0);
  vec_reserve(v1, s1);
  vec_reserve(v2, s2);
  vec_reserve(v3, s3);
  vec_reserve(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  s0 *= 6;
  s1 *= 5;
  s2 *= 4;
  s3 *= 3;
  s4 *= 2;

  qRoundUp32();

  vec_reserve(v0, s0);
  vec_reserve(v1, s1);
  vec_reserve(v2, s2);
  vec_reserve(v3, s3);
  vec_reserve(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_reserve(v0, -s0);
  vec_reserve(v1, -s1);
  vec_reserve(v2, -s2);
  vec_reserve(v3, -s3);
  vec_reserve(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, resize) {
  ASSERT_CAPACITY(0, 0, 0, 0, 0);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, s0);
  vec_resize(v1, s1);
  vec_resize(v2, s2);
  vec_resize(v3, s3);
  vec_resize(v4, s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(s0, s1, s2, s3, s4);

  vec_resize(v0, -s0);
  vec_resize(v1, -s1);
  vec_resize(v2, -s2);
  vec_resize(v3, -s3);
  vec_resize(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, -s0);
  vec_resize(v1, -s1);
  vec_resize(v2, -s2);
  vec_resize(v3, -s3);
  vec_resize(v4, -s4);

  ASSERT_CAPACITY(q0, q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);

  vec_resize(v0, 1);
  vec_resize(v1, 1);
  vec_resize(v2, 1);
  vec_resize(v3, 1);
  vec_resize(v4, 1);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(1, 1, 1, 1, 1);

  vec_resize(v0, 0);
  vec_resize(v1, 0);
  vec_resize(v2, 0);
  vec_resize(v3, 0);
  vec_resize(v4, 0);

  ASSERT_CAPACITY((q0 ? q0 : UVEC_MIN_CAPACITY), q1, q2, q3, q4);
  ASSERT_SIZE(0, 0, 0, 0, 0);
}

TEST_F(VectorTest, push) {

}
<|endoftext|>


<commit_before>#include "core/os.h"
#include "core/stringutils.h"

#include <dirent.h>
#include <iostream>

////////////////////////////////////////////////////////////////////////////////
// copied from https://stackoverflow.com/a/145309/180307

#include <cstdio> /* defines FILENAME_MAX */
#include <utility>
#ifdef _MSC_VER
#include <direct.h>
#define GET_CURRENT_DIR _getcwd
#else
#include <unistd.h>
#include <vector>

#define GET_CURRENT_DIR getcwd
#endif

std::string
GetCurrentDirectory()
{
  char current_directory[FILENAME_MAX];

  if(!GET_CURRENT_DIR(
         static_cast<char*>(current_directory), sizeof(current_directory)))
  {
    return "";
  }

  current_directory[sizeof(current_directory) - 1] = 0;

  const std::string ret = static_cast<char*>(current_directory);
  return ret;
}

////////////////////////////////////////////////////////////////////////////////

DirectoryList
ListDirectory(const std::string& path)
{
  DIR*           dir;
  struct dirent* ent;
  dir = opendir(path.c_str());
  if(dir != nullptr)
  {
    DirectoryList ret;
    ret.valid = true;

    /* print all the files and directories within directory */
    while((ent = readdir(dir)) != nullptr)
    {
      const std::string name = ent->d_name;
      if(ent->d_type == DT_REG)
      {
        ret.files.emplace_back(name);
      }
      else if(ent->d_type == DT_DIR)
      {
        if(name == "." || name == "..")
        {
        }
        else
        {
          ret.directories.emplace_back(name);
        }
      }
    }

    closedir(dir);
    return ret;
  }
  else
  {
    DirectoryList ret;
    ret.valid = false;
    return ret;
  }
}

bool
EndsWith(const std::string& str, char c)
{
  const auto l = str.length();

  if(l == 0)
  {
    return false;
  }

  return str[l - 1] == c;
}

std::string
JoinPath(const std::string& left, const std::string& right)
{
  if(EndsWith(left, PATH_SEPARATOR))
  {
    return left + right;
  }
  else
  {
    return left + PATH_SEPARATOR + right;
  }
}

std::string
GetExtension(const std::string& path)
{
  return LastStrings(path, '.').second;
}

std::string
GetFileNameIncludingExtension(const std::string& path)
{
  const auto r = LastStrings(path, PATH_SEPARATOR).second;
  if(r.empty())
  {
    return r;
  }
  else
  {
    // skip leading path_separator
    return r.substr(1);
  }
}

std::string
GetFileNameWithoutExtension(const std::string& path)
{
  return LastStrings(GetFileNameIncludingExtension(path), '.').first;
}
<commit_msg>added stackoverflow link<commit_after>#include "core/os.h"
#include "core/stringutils.h"

// https://stackoverflow.com/questions/612097/how-can-i-get-the-list-of-files-in-a-directory-using-c-or-c
#include <dirent.h>
#include <iostream>

////////////////////////////////////////////////////////////////////////////////
// copied from https://stackoverflow.com/a/145309/180307

#include <cstdio> /* defines FILENAME_MAX */
#include <utility>
#ifdef _MSC_VER
#include <direct.h>
#define GET_CURRENT_DIR _getcwd
#else
#include <unistd.h>
#include <vector>

#define GET_CURRENT_DIR getcwd
#endif

std::string
GetCurrentDirectory()
{
  char current_directory[FILENAME_MAX];

  if(!GET_CURRENT_DIR(
         static_cast<char*>(current_directory), sizeof(current_directory)))
  {
    return "";
  }

  current_directory[sizeof(current_directory) - 1] = 0;

  const std::string ret = static_cast<char*>(current_directory);
  return ret;
}

////////////////////////////////////////////////////////////////////////////////

DirectoryList
ListDirectory(const std::string& path)
{
  DIR*           dir;
  struct dirent* ent;
  dir = opendir(path.c_str());
  if(dir != nullptr)
  {
    DirectoryList ret;
    ret.valid = true;

    /* print all the files and directories within directory */
    while((ent = readdir(dir)) != nullptr)
    {
      const std::string name = ent->d_name;
      if(ent->d_type == DT_REG)
      {
        ret.files.emplace_back(name);
      }
      else if(ent->d_type == DT_DIR)
      {
        if(name == "." || name == "..")
        {
        }
        else
        {
          ret.directories.emplace_back(name);
        }
      }
    }

    closedir(dir);
    return ret;
  }
  else
  {
    DirectoryList ret;
    ret.valid = false;
    return ret;
  }
}

bool
EndsWith(const std::string& str, char c)
{
  const auto l = str.length();

  if(l == 0)
  {
    return false;
  }

  return str[l - 1] == c;
}

std::string
JoinPath(const std::string& left, const std::string& right)
{
  if(EndsWith(left, PATH_SEPARATOR))
  {
    return left + right;
  }
  else
  {
    return left + PATH_SEPARATOR + right;
  }
}

std::string
GetExtension(const std::string& path)
{
  return LastStrings(path, '.').second;
}

std::string
GetFileNameIncludingExtension(const std::string& path)
{
  const auto r = LastStrings(path, PATH_SEPARATOR).second;
  if(r.empty())
  {
    return r;
  }
  else
  {
    // skip leading path_separator
    return r.substr(1);
  }
}

std::string
GetFileNameWithoutExtension(const std::string& path)
{
  return LastStrings(GetFileNameIncludingExtension(path), '.').first;
}
<|endoftext|>


<commit_before>/*
 * Clever language
 * Copyright (c) 2010 Clever Team
 *
 * 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.
 *
 * $Id: parser.y 67 2010-12-22 18:55:54Z felipensp $
 */

#include <cstdlib>
#include <iostream>
#include "opcodes.h"
#include "vm.h"

namespace clever {

/*
 * Destroy the opcodes data
 */
VM::~VM(void) {
	OpcodeList::iterator it = m_opcodes->begin();

	while (it < m_opcodes->end()) {
		if ((*it)->get_op1()) {
			(*it)->get_op1()->delRef();
		}
		if ((*it)->get_op2()) {
			(*it)->get_op2()->delRef();
		}
		if ((*it)->get_result()) {
			(*it)->get_result()->delRef();
		}
		delete *it;
		++it;
	}
}

/*
 * Displays an error message
 */
void VM::error(const char* message) const {
	std::cout << "Runtime error: " << message << std::endl;
	exit(1);
}

/*
 * Execute the collected opcodes
 */
void VM::run(void) {
	unsigned int next_op, last_op = m_opcodes->size();

	m_symbols.pushVarMap(SymbolTable::var_map());

	// std::cout << "Opcodes: " << last_op << std::endl;

	for (next_op = 0; next_op < last_op; ++next_op) {
		Opcode* opcode = (*m_opcodes)[next_op];

		(this->*(opcode->get_handler()))(&next_op, opcode);
		// std::cout << "next: " << next_op+1 << std::endl;
	}

	m_symbols.popVarMap();
}

/*
 * echo statemenet
 */
void VM::echo_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());

	std::cout << op1->toString() << std::endl;
}

/*
 * x + y
 */
void VM::plus_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				opcode->set_result(new ConstantValue(CSTRING(op1->getString() + op2->getString())));
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() + op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() + op2->getDouble()));
				break;
		}
	}
}

/*
 * x / y
 */
void VM::div_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() / op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() / op2->getDouble()));
				break;
		}
	}
}

/*
 * x - y
 */
void VM::minus_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() - op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() - op2->getDouble()));
				break;
		}
	}
}

/*
 * x * y
 */
void VM::mult_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() * op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() * op2->getDouble()));
				break;
		}
	}
}

/*
 * x & y
 */
void VM::bw_and_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() & op2->getInteger()));
				break;
		}
	}
}

/*
 * x ^ y
 */
void VM::bw_xor_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() ^ op2->getInteger()));
				break;
		}
	}
}

/*
 * x | y
 */
void VM::bw_or_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() | op2->getInteger()));
				break;
		}
	}
}

/*
 * {
 */
void VM::new_scope_handler(CLEVER_VM_HANDLER_ARGS) {
	m_symbols.pushVarMap(SymbolTable::var_map());
}

/*
 * }
 */
void VM::end_scope_handler(CLEVER_VM_HANDLER_ARGS) {
	m_symbols.popVarMap();
}

/*
 * Type var
 */
void VM::var_decl_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op2());

	/* TODO: Make the type initialization here */
	if (!value) {
		error("Uninitialized variable!");
	}
	value->addRef();

	m_symbols.register_var(opcode->get_op1()->toString(), value);
}

/*
 * ++x
 */
void VM::pre_inc_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				value->setInteger(value->getInteger()+1);
				opcode->set_result(new ConstantValue(value->getInteger()));
				break;
			case Value::DOUBLE:
				value->setDouble(value->getDouble()+1);
				opcode->set_result(new ConstantValue(value->getDouble()));
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * x++
 */
void VM::pos_inc_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(value->getInteger()));
				value->setInteger(value->getInteger()+1);
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(value->getDouble()));
				value->setDouble(value->getDouble()+1);
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * --x
 */
void VM::pre_dec_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				value->setInteger(value->getInteger()-1);
				opcode->set_result(new ConstantValue(value->getInteger()));
				break;
			case Value::DOUBLE:
				value->setDouble(value->getDouble()-1);
				opcode->set_result(new ConstantValue(value->getDouble()));
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * x--
 */
void VM::pos_dec_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(value->getInteger()));
				value->setInteger(value->getInteger()-1);
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(value->getDouble()));
				value->setDouble(value->getDouble()-1);
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * JMPZ
 */
void VM::jmpz_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				if (value->getInteger() == 0) {
					// std::cout << "jmp to " << opcode->get_jmp_addr1() << std::endl;
					VM_GOTO(opcode->get_jmp_addr1());
				}
				break;
		}
	}
}

/*
 * JMP
 */
void VM::jmp_handler(CLEVER_VM_HANDLER_ARGS) {
	// std::cout << "> jmp to " << opcode->get_jmp_addr2()-1 <<  std::endl;
	VM_GOTO(opcode->get_jmp_addr2());
}

} // clever
<commit_msg>- Removed unnecessary "new ConstatValue"<commit_after>/*
 * Clever language
 * Copyright (c) 2010 Clever Team
 *
 * 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.
 *
 * $Id: parser.y 67 2010-12-22 18:55:54Z felipensp $
 */

#include <cstdlib>
#include <iostream>
#include "opcodes.h"
#include "vm.h"

namespace clever {

/*
 * Destroy the opcodes data
 */
VM::~VM(void) {
	OpcodeList::iterator it = m_opcodes->begin();

	while (it < m_opcodes->end()) {
		if ((*it)->get_op1()) {
			(*it)->get_op1()->delRef();
		}
		if ((*it)->get_op2()) {
			(*it)->get_op2()->delRef();
		}
		if ((*it)->get_result()) {
			(*it)->get_result()->delRef();
		}
		delete *it;
		++it;
	}
}

/*
 * Displays an error message
 */
void VM::error(const char* message) const {
	std::cout << "Runtime error: " << message << std::endl;
	exit(1);
}

/*
 * Execute the collected opcodes
 */
void VM::run(void) {
	unsigned int next_op, last_op = m_opcodes->size();

	m_symbols.pushVarMap(SymbolTable::var_map());

	// std::cout << "Opcodes: " << last_op << std::endl;

	for (next_op = 0; next_op < last_op; ++next_op) {
		Opcode* opcode = (*m_opcodes)[next_op];

		(this->*(opcode->get_handler()))(&next_op, opcode);
		// std::cout << "next: " << next_op+1 << std::endl;
	}

	m_symbols.popVarMap();
}

/*
 * echo statemenet
 */
void VM::echo_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());

	std::cout << op1->toString() << std::endl;
}

/*
 * x + y
 */
void VM::plus_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				opcode->set_result(new ConstantValue(CSTRING(op1->getString() + op2->getString())));
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() + op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() + op2->getDouble()));
				break;
		}
	}
}

/*
 * x / y
 */
void VM::div_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() / op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() / op2->getDouble()));
				break;
		}
	}
}

/*
 * x - y
 */
void VM::minus_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() - op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() - op2->getDouble()));
				break;
		}
	}
}

/*
 * x * y
 */
void VM::mult_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
				error("Operation not allow in strings!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() * op2->getInteger()));
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(op1->getDouble() * op2->getDouble()));
				break;
		}
	}
}

/*
 * x & y
 */
void VM::bw_and_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() & op2->getInteger()));
				break;
		}
	}
}

/*
 * x ^ y
 */
void VM::bw_xor_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() ^ op2->getInteger()));
				break;
		}
	}
}

/*
 * x | y
 */
void VM::bw_or_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* op1 = getValue(opcode->get_op1());
	Value* op2 = getValue(opcode->get_op2());

	if (op1->isConst() && op1->hasSameKind(op2)) {
		if (!op1->hasSameType(op2)) {
			error("Type mismatch!");
		}
		switch (op1->get_type()) {
			case Value::STRING:
			case Value::DOUBLE:
				error("Operation not allow for such type!");
				break;
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(op1->getInteger() | op2->getInteger()));
				break;
		}
	}
}

/*
 * {
 */
void VM::new_scope_handler(CLEVER_VM_HANDLER_ARGS) {
	m_symbols.pushVarMap(SymbolTable::var_map());
}

/*
 * }
 */
void VM::end_scope_handler(CLEVER_VM_HANDLER_ARGS) {
	m_symbols.popVarMap();
}

/*
 * Type var
 */
void VM::var_decl_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op2());

	/* TODO: Make the type initialization here */
	if (!value) {
		error("Uninitialized variable!");
	}
	value->addRef();

	m_symbols.register_var(opcode->get_op1()->toString(), value);
}

/*
 * ++x
 */
void VM::pre_inc_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				value->setInteger(value->getInteger()+1);
				opcode->set_result(value);
				value->addRef();
				break;
			case Value::DOUBLE:
				value->setDouble(value->getDouble()+1);
				opcode->set_result(value);
				value->addRef();
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * x++
 */
void VM::pos_inc_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(value->getInteger()));
				value->setInteger(value->getInteger()+1);
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(value->getDouble()));
				value->setDouble(value->getDouble()+1);
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * --x
 */
void VM::pre_dec_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				value->setInteger(value->getInteger()-1);
				opcode->set_result(value);
				value->addRef();
				break;
			case Value::DOUBLE:
				value->setDouble(value->getDouble()-1);
				opcode->set_result(value);
				value->addRef();
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * x--
 */
void VM::pos_dec_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				opcode->set_result(new ConstantValue(value->getInteger()));
				value->setInteger(value->getInteger()-1);
				break;
			case Value::DOUBLE:
				opcode->set_result(new ConstantValue(value->getDouble()));
				value->setDouble(value->getDouble()-1);
				break;
			default:
				error("Operation unsupported for such type");
				break;
		}
	}
}

/*
 * JMPZ
 */
void VM::jmpz_handler(CLEVER_VM_HANDLER_ARGS) {
	Value* value = getValue(opcode->get_op1());

	if (value->isConst()) {
		switch (value->get_type()) {
			case Value::INTEGER:
				if (value->getInteger() == 0) {
					// std::cout << "jmp to " << opcode->get_jmp_addr1() << std::endl;
					VM_GOTO(opcode->get_jmp_addr1());
				}
				break;
		}
	}
}

/*
 * JMP
 */
void VM::jmp_handler(CLEVER_VM_HANDLER_ARGS) {
	// std::cout << "> jmp to " << opcode->get_jmp_addr2()-1 <<  std::endl;
	VM_GOTO(opcode->get_jmp_addr2());
}

} // clever
<|endoftext|>