From 104db9da8cefb061cada69ba4101e1528b03e9e2 Mon Sep 17 00:00:00 2001 From: RowanG077 Date: Mon, 12 Nov 2018 15:31:23 +0100 Subject: [PATCH] Revised graph to have adjacency matrix instead of list for way more efficient allocation --- include/BoxNesting/Algorithm.hpp | 26 +++++---- include/BoxNesting/Box.hpp | 4 +- include/Graph/AdjacencyMatrix.hpp | 84 +++++++++++++++++++++++++++ include/Graph/BipartiteGraph.hpp | 96 +++++++++++++++++++++++++++++++ include/Graph/BipartiteGraph.ipp | 48 ++++++++++++++++ include/Graph/Graph.hpp | 80 -------------------------- include/Graph/Graph.ipp | 62 -------------------- src/Algorithm.cpp | 55 ++++++++---------- src/Parser.cpp | 9 +-- test/Algorithm.cpp | 21 ++++--- test/BipartiteGraph.cpp | 42 ++++++++++++++ test/CMakeLists.txt | 2 +- test/Graph.cpp | 42 -------------- test/Parser.cpp | 9 ++- 14 files changed, 332 insertions(+), 248 deletions(-) create mode 100644 include/Graph/AdjacencyMatrix.hpp create mode 100644 include/Graph/BipartiteGraph.hpp create mode 100644 include/Graph/BipartiteGraph.ipp delete mode 100644 include/Graph/Graph.hpp delete mode 100644 include/Graph/Graph.ipp create mode 100644 test/BipartiteGraph.cpp delete mode 100644 test/Graph.cpp diff --git a/include/BoxNesting/Algorithm.hpp b/include/BoxNesting/Algorithm.hpp index 09cdc57..482a76f 100644 --- a/include/BoxNesting/Algorithm.hpp +++ b/include/BoxNesting/Algorithm.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include /** * @brief Contains code for the boxnesting problem @@ -14,11 +14,6 @@ namespace BoxNesting class Algorithm { public: - /** - * @brief Construct a new Algorithm object with the default constructor - */ - Algorithm() = default; - /** * @brief function that runs the boxNesting algorithm and returns the number * of visible boxes @@ -38,9 +33,9 @@ class Algorithm * * @param boxes the set of boxes that will be used to create the graph * - * @return Graph::Graph the graph of type BoxNesting::Box + * @return the graph of type BoxNesting::Box */ - [[nodiscard]] Graph::Graph createGraphFromBoxes(const std::vector& boxes) const; + [[nodiscard]] Graph::BipartiteGraph createGraphFromBoxes(const std::vector& boxes) const; private: /** @@ -53,8 +48,19 @@ class Algorithm * * @return Whether pairs could be made */ - bool kuhn( - const Graph::Graph& graph, uint16_t vertex, std::vector& used, std::vector& pairs) const; + bool kuhn(uint16_t vertex) const; + +private: + /** + * @brief Graph generated by the boxes + */ + mutable Graph::BipartiteGraph graph; + + /** + * @brief Contains + */ + mutable std::vector used; + mutable std::vector pairs; }; } // namespace BoxNesting \ No newline at end of file diff --git a/include/BoxNesting/Box.hpp b/include/BoxNesting/Box.hpp index c2999d1..1d24a45 100644 --- a/include/BoxNesting/Box.hpp +++ b/include/BoxNesting/Box.hpp @@ -71,9 +71,7 @@ class Box * * @return array containing the side lengths ordered from smallest to largest */ - [[nodiscard]] const std::array& getSideLengths() const { - return this->sideLengths; - } + [[nodiscard]] const std::array& getSideLengths() const { return this->sideLengths; } /** * @brief The minimum length that a side of a box may have diff --git a/include/Graph/AdjacencyMatrix.hpp b/include/Graph/AdjacencyMatrix.hpp new file mode 100644 index 0000000..d82772a --- /dev/null +++ b/include/Graph/AdjacencyMatrix.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +/** + * @brief Contains generic code that represents a graph and its properties + */ +namespace Graph +{ +/** + * @brief Class that can be used to store a 2d array continously in memory + * + * @tparam T The type to store in the array + */ +template class AdjacencyMatrix +{ +public: + /** + * @brief Construct a new empty AdjacencyMatrix object + */ + AdjacencyMatrix() : data(0) + { + + } + + /** + * @brief Construct a new AdjacencyMatrix object + * + * @param l The amount of left vertices + * @param r The amount of right vertices + */ + AdjacencyMatrix(size_t l, size_t r) : data(l * r), leftCount(l), rightCount(r) + { + + } + + /** + * @brief Get element at specified indices + * + * @param l The left vertex index + * @param r The right vertex index + * + * @throws std::out_of_range if index is out of range + * + * @return Value at that index + */ + [[nodiscard]] T& at(size_t l, size_t r) + { + return this->data.at(l * this->rightCount + r); + } + + /** + * @brief Get const element at specified indices + * + * @param l The left vertex index + * @param r The right vertex index + * + * @throws std::out_of_range if index is out of range + * + * @return Const value at that index + */ + [[nodiscard]] const T& at(size_t l, size_t r) const { + return this->data.at(l * this->rightCount + r); + } + +private: + /** + * @brief Contains the data of the adjacencyMatrix + */ + std::vector data; + + /** + * @brief Contains the amount of left vertices + */ + size_t leftCount = 0; + + /** + * @brief Contains the amount of right vertices + */ + size_t rightCount = 0; +}; + +} // namespace Graph diff --git a/include/Graph/BipartiteGraph.hpp b/include/Graph/BipartiteGraph.hpp new file mode 100644 index 0000000..aa22e4e --- /dev/null +++ b/include/Graph/BipartiteGraph.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +#include + +/** + * @brief Contains generic code that represents a graph and its properties + */ +namespace Graph +{ +/** + * @brief template class representing a Bipartite graph + * + * @tparam T The type of the value to contain in the vertices. + */ +template class BipartiteGraph +{ +public: + /** + * @brief Construct a new empty bipartite graph + */ + BipartiteGraph() = default; + + /** + * @brief Construct a new Bipartite Graph object from two sets of vertices + * + * @param leftVertices The left part of the bipartite graph + * @param rightVertices The right aprt of the bipartite graph + */ + BipartiteGraph(std::vector> leftVertices, std::vector> rightVertices); + + /** + * @brief function that adds an edge to the graph + * + * @throw std::logic_error If v1 or v2 are vertices that are not in the graph. + * + * @param v1 source vertex index of the edge must be in the left vertices + * @param v2 destination vertex index of the edge must be in the right vertices + */ + void addEdge(uint16_t v1, uint16_t v2); + + /** + * @brief function that checks if there is an edge between two vertices. + * + * @throw std::logic_error If v1 or v2 are vertices that are not in the graph. + * + * @param v1 the source vertex index of the edge must be in the left vertices + * @param v2 the destination vertex index of the edge must be in the left vertices + * @return true if there is an edge + * @return false if there is no edge + */ + [[nodiscard]] bool isEdgeBetween(uint16_t v1, uint16_t v2) const; + + /** + * @brief Getter for the adjacency list object + * + * @return The adjacency list by reference + */ + [[nodiscard]] const AdjacencyMatrix& getAdjacencyMatrix() const noexcept; + + /** + * @brief Get the left Vertices of the bipartite graph + * + * @return The left vertices of the bipartite graph + */ + [[nodiscard]] const std::vector>& getLeftVertices() const noexcept; + /** + * @brief Get the rigt Vertices of the bipartite graph + * + * @return The right vertices of the bipartite graph + */ + [[nodiscard]] const std::vector>& getRightVertices() const noexcept; + +private: + /** + * @brief Contains the left vertices of the graph + */ + std::vector> leftVertices; + + /** + * @brief Contains the rights vertices of the graph + */ + std::vector> rightVertices; + + /** + * @brief Contains the edges between the left and right vertices + * The vector specialization of bool is broken so we use uint8_t instead of bool + */ + AdjacencyMatrix adjacencyMatrix; +}; + +} // namespace Graph + +#include diff --git a/include/Graph/BipartiteGraph.ipp b/include/Graph/BipartiteGraph.ipp new file mode 100644 index 0000000..62e5eea --- /dev/null +++ b/include/Graph/BipartiteGraph.ipp @@ -0,0 +1,48 @@ +#include + +#include +#include + +namespace Graph +{ + +template +BipartiteGraph::BipartiteGraph(std::vector> leftVertices, std::vector> rightVertices) + : leftVertices(std::move(leftVertices)), + rightVertices(std::move(rightVertices)), + adjacencyMatrix(AdjacencyMatrix(this->leftVertices.size(), this->rightVertices.size())) +{ + +} + +template +void BipartiteGraph::addEdge(uint16_t v1, uint16_t v2) +{ + this->adjacencyMatrix.at(v1, v2) = true; +} + +template +bool BipartiteGraph::isEdgeBetween(uint16_t v1, uint16_t v2) const +{ + return this->adjacencyMatrix.at(v1, v2); +} + +template +const AdjacencyMatrix& BipartiteGraph::getAdjacencyMatrix() const noexcept +{ + return this->adjacencyMatrix; +} + +template +const std::vector>& BipartiteGraph::getLeftVertices() const noexcept +{ + return this->leftVertices; +} + +template +const std::vector>& BipartiteGraph::getRightVertices() const noexcept +{ + return this->rightVertices; +} + +} // namespace Graph \ No newline at end of file diff --git a/include/Graph/Graph.hpp b/include/Graph/Graph.hpp deleted file mode 100644 index 324878a..0000000 --- a/include/Graph/Graph.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include - -#include - -/** - * @brief Contains generic code that represents a graph and its properties - */ -namespace Graph -{ -/** - * @brief Data structure to represent AdjacencyList of the graph - * - * @tparam T The type of the value to contain in the vertices. - */ -template struct AdjacencyList -{ - /** - * @brief The vertex for this adjacencyList - */ - Vertex vertex; - - /** - * @brief The vertices the head vertex can travel to via an edge. - */ - std::vector edges; -}; - -/** - * @brief template class representing a graph - * - * @tparam T The type of the value to contain in the vertices. - */ -template class Graph -{ -public: - /** - * @brief function that adds a vertex to the graph - * - * @param vertex the vertex to be added to the graph - */ - void addVertex(const Vertex& vertex); - - /** - * @brief function that adds an edge to the graph - * - * @throw std::logic_error If v1 or v2 are vertices that are not in the graph. - * - * @param v1 source of the edge - * @param v2 destination of the edge - */ - void addEdge(const Vertex& v1, const Vertex& v2); - - /** - * @brief function that checks if there is an edge between two vertices. - * - * @throw std::logic_error If v1 or v2 are vertices that are not in the graph. - * - * @param v1 the source vertex of the edge - * @param v2 the destination vertex of the edge - * @return true if there is an edge - * @return false if there is no edge - */ - bool isEdgeBetween(const Vertex& v1, const Vertex& v2) const; - - /** - * @brief Getter for the adjacency list object - * - * @return The adjacency list by reference - */ - const std::vector>& getAdjacencyList() const noexcept; - -private: - std::vector> adjacencyList; -}; - -} // namespace Graph - -#include diff --git a/include/Graph/Graph.ipp b/include/Graph/Graph.ipp deleted file mode 100644 index 32fb816..0000000 --- a/include/Graph/Graph.ipp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include -#include - -namespace Graph -{ - -template -void Graph::addVertex(const Vertex& vertex) -{ - this->adjacencyList.emplace_back(AdjacencyList{vertex, std::vector()}); -} - -template -void Graph::addEdge(const Vertex& v1, const Vertex& v2) -{ - auto e1 = std::find_if(this->adjacencyList.begin(), this->adjacencyList.end(), - [&](const AdjacencyList& e) { return e.vertex == v1; }); - auto e2 = std::find_if(this->adjacencyList.begin(), this->adjacencyList.end(), - [&](const AdjacencyList& e) { return e.vertex == v2; }); - - if (e1 == this->adjacencyList.end()) { - throw std::logic_error("addEdge, v1 vertex does not exist in adjacency list of graph."); - } - if (e2 == this->adjacencyList.end()) { - throw std::logic_error("addEdge, v2 vertex does not exist in adjacency list of graph."); - } - - e1->edges.emplace_back(e2 - this->adjacencyList.begin()); - e2->edges.emplace_back(e1 - this->adjacencyList.begin()); -} - -template -bool Graph::isEdgeBetween(const Vertex &v1, const Vertex &v2) const -{ - auto e1 = std::find_if(this->adjacencyList.begin(), this->adjacencyList.end(), - [&](const AdjacencyList& e) { return e.vertex == v1; }); - auto e2 = std::find_if(this->adjacencyList.begin(), this->adjacencyList.end(), - [&](const AdjacencyList& e) { return e.vertex == v2; }); - - if (e1 == this->adjacencyList.end()) { - throw std::logic_error("isEdgeBetween, v1 vertex does not exist in adjacency list of graph."); - } - if (e2 == this->adjacencyList.end()) { - throw std::logic_error("isEdgeBetween, v2 vertex does not exist in adjacency list of graph."); - } - - auto requiredIndex = e2 - this->adjacencyList.begin(); - - const auto founditerator = std::find(e1->edges.begin(), e1->edges.end(), requiredIndex); - - return founditerator != e1->edges.end(); -} - -template -const std::vector>& Graph::getAdjacencyList() const noexcept -{ - return this->adjacencyList; -} - -} // namespace Graph \ No newline at end of file diff --git a/src/Algorithm.cpp b/src/Algorithm.cpp index d3afd18..60915de 100644 --- a/src/Algorithm.cpp +++ b/src/Algorithm.cpp @@ -10,51 +10,43 @@ namespace BoxNesting { uint16_t Algorithm::runAlgorithm(const std::vector& boxes) const { - const auto graph = createGraphFromBoxes(boxes); + this->graph = createGraphFromBoxes(boxes); // n is the amount of vertices in the left part and the right part - // of the bipartite graph. We know this is exactly the amount of vertices - // divided by two since we for each box we create one vertex - // in the left part of the graph and one in the right part of the graph + // of the bipartite graph. and k the amount of vertices in the right part + // of the graph. They are the same in our box case but could be different + // in other cases // since we know graph size doesn't exceed uint16_t we can cast here safely - auto n = static_cast(graph.getAdjacencyList().size() / 2); + auto n = static_cast(graph.getLeftVertices().size()); + auto k = static_cast(graph.getRightVertices().size()); - // contains indices of the vertices in right part of the graph - // on marked edges - std::vector pairs(n, -1); - // Contains whether a vertex - std::vector used(n, false); + this->pairs = std::vector(n, -1); + this->used = std::vector(k, false); // iterate through vertices of the left side // of the bipartate graph for (uint16_t i = 0; i < n; ++i) { fill(used.begin(), used.end(), false); - kuhn(graph, i, used, pairs); + kuhn(i); } return 0; } -bool Algorithm::kuhn( - const Graph::Graph& graph, uint16_t vertex, std::vector& used, std::vector& pairs) const +bool Algorithm::kuhn(uint16_t vertex) const { - if (used[vertex]) { + if (this->used[vertex]) { return false; } - used[vertex] = true; - const auto& neighbours = graph.getAdjacencyList().at(vertex).edges; - for (uint16_t i = 0; i < neighbours.size(); ++i) { - pairs[i] = 1; - } + this->used[vertex] = true; + this->pairs[vertex] = static_cast(graph.getLeftVertices().size()); return true; } -Graph::Graph Algorithm::createGraphFromBoxes(const std::vector& boxes) const +Graph::BipartiteGraph Algorithm::createGraphFromBoxes(const std::vector& boxes) const { - Graph::Graph graph; - std::vector> leftVertices; std::transform(boxes.begin(), boxes.end(), std::back_inserter(leftVertices), [](const auto& b) { return Graph::Vertex(b); }); @@ -69,20 +61,19 @@ Graph::Graph Algorithm::createGraphFromBoxes(const std::vector& boxes) // to the left side of the bipartite graph // and the second half of the adjacency list belongs // to the right side of the bipartite graph - for (const auto& v : leftVertices) { - graph.addVertex(v); - } - - for (const auto& v : rightVertices) { - graph.addVertex(v); - } + Graph::BipartiteGraph graph(leftVertices, rightVertices); // Create edges between left and right vertices if the left box can nest in // the right box - for (const auto& v1 : leftVertices) { - for (const auto& v2 : rightVertices) { + const auto& lv = graph.getLeftVertices(); + const auto& rv = graph.getRightVertices(); + for (uint16_t i = 0; i < lv.size(); ++i) { + for (uint16_t j = 0; j < rv.size(); ++j) { + auto& v1 = lv.at(i); + auto& v2 = rv.at(j); + if (v1.getContent().isNestable(v2.getContent())) { - graph.addEdge(v1, v2); + graph.addEdge(i, j); } } } diff --git a/src/Parser.cpp b/src/Parser.cpp index a43397c..0dda1f1 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -13,11 +13,12 @@ std::vector Parser::getBoxes(std::istream& inputStream) std::getline(inputStream, inputLine); uint16_t boxCount = 0; + static const auto max = std::numeric_limits::max(); try { auto tmp = std::stoi(inputLine); - if (tmp <= 0) { + if (tmp <= 0 || tmp > max) { std::stringstream ss; - ss << "Amount of boxes is smaller then 1. Got: \"" << tmp << "\""; + ss << "Amount of boxes is smaller then 1 or too large max allowed: " << max << ". Got: \"" << tmp << "\""; throw ParserError(ss.str()); } boxCount = static_cast(tmp); @@ -27,7 +28,7 @@ std::vector Parser::getBoxes(std::istream& inputStream) throw ParserError(ss.str(), e); } catch (const std::out_of_range& e) { std::stringstream ss; - ss << "Number of boxes is too large to handle for this program, max allowed: " << ULONG_MAX; + ss << "Number of boxes is too large to handle for this program, max allowed: " << max; throw ParserError(ss.str(), e); } diff --git a/test/Algorithm.cpp b/test/Algorithm.cpp index 21a710a..c81542d 100644 --- a/test/Algorithm.cpp +++ b/test/Algorithm.cpp @@ -7,11 +7,8 @@ SCENARIO("Running the 'graph creation from a set of boxes' function") { GIVEN("A set of boxes") { - std::vector boxes; - - boxes.emplace_back(BoxNesting::Box({0.6f, 0.6f, 0.6f})); - boxes.emplace_back(BoxNesting::Box({0.7f, 0.7f, 0.7f})); - boxes.emplace_back(BoxNesting::Box({0.8f, 0.8f, 0.8f})); + std::vector boxes{BoxNesting::Box({0.6f, 0.6f, 0.6f}), BoxNesting::Box({0.7f, 0.7f, 0.7f}), + BoxNesting::Box({0.8f, 0.8f, 0.8f})}; BoxNesting::Algorithm boxNestingAlgorithm; @@ -21,12 +18,14 @@ SCENARIO("Running the 'graph creation from a set of boxes' function") THEN("There can only be edges from vertex a to b if a nests inside b") { - for (const auto& list1 : graph.getAdjacencyList()) { - for (const auto& list2 : graph.getAdjacencyList()) { - // An edge means the box is nestable - auto& v1 = list1.vertex; - auto& v2 = list2.vertex; - if (graph.isEdgeBetween(v1, v2)) { + const auto& lv = graph.getLeftVertices(); + const auto& rv = graph.getRightVertices(); + for (uint16_t i = 0; i < lv.size(); ++i) { + for (uint16_t j = 0; j < rv.size(); ++j) { + if (graph.isEdgeBetween(i, j)) { + auto& v1 = lv.at(i); + auto& v2 = rv.at(j); + auto isNestable = v1.getContent().isNestable(v2.getContent()) || v2.getContent().isNestable(v1.getContent()); diff --git a/test/BipartiteGraph.cpp b/test/BipartiteGraph.cpp new file mode 100644 index 0000000..6bc9df1 --- /dev/null +++ b/test/BipartiteGraph.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +SCENARIO("A graph of boxes add edged and check if no vertex has an edge to itsself", "[Graph]") +{ + GIVEN("A basic set of boxes") + { + std::vector> leftVertices{ + Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.61f})), + Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.51f})), + Graph::Vertex(BoxNesting::Box({0.6f, 0.51f, 0.6f}))}; + + std::vector> rightVertices{ + Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.61f})), + Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.51f})), + Graph::Vertex(BoxNesting::Box({0.6f, 0.51f, 0.6f}))}; + + Graph::BipartiteGraph graph(leftVertices, rightVertices); + + WHEN("Adding some edges") + { + graph.addEdge(0, 1); + graph.addEdge(1, 2); + + THEN("Existing edges indeed exist") + { + REQUIRE(graph.isEdgeBetween(0, 1) == true); + REQUIRE(graph.isEdgeBetween(1, 2) == true); + REQUIRE(graph.isEdgeBetween(0, 2) == false); + REQUIRE(graph.isEdgeBetween(2, 0) == false); + } + + THEN("A vertex does not have an edge to itself") + { + REQUIRE(graph.isEdgeBetween(0, 0) == false); + REQUIRE(graph.isEdgeBetween(1, 1) == false); + REQUIRE(graph.isEdgeBetween(1, 1) == false); + } + } + } +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8de2f71..74f5369 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(test_obj OBJECT # add all tests on this level separately foreach(file - Box Parser Graph Algorithm) + Box Parser BipartiteGraph Algorithm) add_executable("test_${file}" "${file}.cpp" $ diff --git a/test/Graph.cpp b/test/Graph.cpp deleted file mode 100644 index 46651ee..0000000 --- a/test/Graph.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include - -SCENARIO("A graph of boxes add edged and check if no vertex has an edge to itsself", "[Graph]") -{ - GIVEN("A basic set of boxes") - { - Graph::Graph graph; - - auto a = Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.61f})); - auto b = Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.51f})); - auto c = Graph::Vertex(BoxNesting::Box({0.6f, 0.51f, 0.6f})); - - graph.addVertex(a); - graph.addVertex(b); - graph.addVertex(c); - - WHEN("Adding some edges") - { - graph.addEdge(a, b); - graph.addEdge(b, c); - - THEN("Existing edges indeed exist") - { - REQUIRE(graph.isEdgeBetween(a, b) == true); - REQUIRE(graph.isEdgeBetween(b, a) == true); - REQUIRE(graph.isEdgeBetween(b, c) == true); - REQUIRE(graph.isEdgeBetween(c, b) == true); - REQUIRE(graph.isEdgeBetween(a, c) == false); - REQUIRE(graph.isEdgeBetween(c, a) == false); - } - - THEN("A vertex does not have an edge to itsself") - { - REQUIRE(graph.isEdgeBetween(a, a) == false); - REQUIRE(graph.isEdgeBetween(b, b) == false); - REQUIRE(graph.isEdgeBetween(c, c) == false); - } - } - } -} \ No newline at end of file diff --git a/test/Parser.cpp b/test/Parser.cpp index 02a5046..6a2d531 100644 --- a/test/Parser.cpp +++ b/test/Parser.cpp @@ -51,9 +51,12 @@ SCENARIO("Parsing box specifcations from inputStream") WHEN("parsing the first line and a large number is present") { std::stringstream stream; - stream << "9" << std::numeric_limits::max() << std::endl; THEN("a ParserError is thrown") { + stream << (std::numeric_limits::max() + 1) << std::endl; + REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError); + stream.str(std::string()); + stream << std::numeric_limits::max() << std::endl; REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError); } } @@ -72,8 +75,8 @@ SCENARIO("Parsing box specifcations from inputStream") { std::stringstream stream; stream << "1" << std::endl - << std::fixed << "9" << std::numeric_limits::max() << " " << validLength << " " - << validLength << std::endl; + << std::fixed << "9" << std::numeric_limits::max() << " " << validLength << " " << validLength + << std::endl; THEN("a ParserError is thrown") {