aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Artist.h3
-rw-r--r--CMakeLists.txt7
-rw-r--r--CSVParser.cpp82
-rw-r--r--CSVParser.h12
-rw-r--r--Canvas.cpp14
-rw-r--r--Canvas.h12
-rw-r--r--Deserializer.cpp32
-rw-r--r--Deserializer.h17
-rw-r--r--LocalFile.cpp34
-rw-r--r--LocalFile.h3
-rw-r--r--Museum.h2
-rw-r--r--Parser.cpp32
-rw-r--r--Parser.h8
-rw-r--r--ParserStrategy.h4
-rw-r--r--People.h2
-rw-r--r--TXTParser.cpp16
-rw-r--r--TXTParser.h12
-rw-r--r--Tile.cpp6
-rw-r--r--Tile.h4
-rw-r--r--TileAppearance.h7
-rw-r--r--TileBehavior.h4
-rw-r--r--XMLParser.cpp29
-rw-r--r--XMLParser.h12
-rw-r--r--main.cpp26
24 files changed, 345 insertions, 35 deletions
diff --git a/Artist.h b/Artist.h
index c14785b..8f5ba2e 100644
--- a/Artist.h
+++ b/Artist.h
@@ -6,7 +6,8 @@ class Artist {
public:
void update();
-private:
+public:
ArtistData data;
+
};
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df8908f..6e47625 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,13 @@ add_executable(main
LocalFile.cpp
Exception.cpp
FileReader.cpp
+ Canvas.cpp
+ Parser.cpp
+ CSVParser.cpp
+ XMLParser.cpp
+ # TXTParser.cpp
+ Deserializer.cpp
+ Tile.cpp
)
target_link_libraries(main
diff --git a/CSVParser.cpp b/CSVParser.cpp
new file mode 100644
index 0000000..3fbe804
--- /dev/null
+++ b/CSVParser.cpp
@@ -0,0 +1,82 @@
+#include <cstdlib>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+
+#include "CSVParser.h"
+#include "Exception.h"
+#include "Parser.h"
+
+using namespace std;
+
+CSVParser CSVParser::instance {};
+CSVParser::CSVParser() {
+ Parser::register_strategy(this);
+}
+
+unsigned int CSVParser::heuristic(File & f) {
+ const string content = f.read();
+ int global_columns = 0;
+ int columns = 1;
+ int rows = 0;
+ int penalty = 1;
+ for (char c : content) {
+ if (c == ',') columns++;
+ if (c == '\n') {
+ rows++;
+ if (global_columns == 0) global_columns = columns;
+ penalty += abs(global_columns - columns);
+ columns = 1;
+ }
+ }
+ if (global_columns == 1) penalty += 1000;
+ return (rows + global_columns) / penalty;
+}
+
+static size_t header_idx(vector<string> header, string field) {
+ auto iter = find(header.begin(), header.end(), field);
+ if (iter == header.end())
+ throw Exception("CSV file is missing \"%s\" column", field.c_str());
+ return iter - header.begin();
+}
+
+void CSVParser::parse(File & f, Deserializer & d) {
+ vector<vector<string>> table = {};
+
+ istringstream rows(f.read());
+ string row;
+ while (getline(rows, row)) {
+ // ignore windows line endings
+ if (row.back() == '\r') row.pop_back();
+ istringstream columns(row);
+ string column;
+
+ vector<string> table_row = {};
+ while (getline(columns, column, ',')) {
+ table_row.push_back(column);
+ }
+ table.push_back(table_row);
+ }
+
+ if (table.size() < 1)
+ throw Exception("not enough data rows in CSV file");
+
+ vector<string> table_header = table[0];
+ table.erase(table.begin());
+
+ size_t x_idx = header_idx(table_header, "x");
+ size_t y_idx = header_idx(table_header, "y");
+ size_t vx_idx = header_idx(table_header, "vx");
+ size_t vy_idx = header_idx(table_header, "vy");
+
+ for (vector<string> row : table) {
+ d.add_artist({
+ .x = stof(row[x_idx]),
+ .y = stof(row[y_idx]),
+ .vx = stof(row[vx_idx]),
+ .vy = stof(row[vy_idx]),
+ });
+ }
+}
+
diff --git a/CSVParser.h b/CSVParser.h
index 3f59c93..aa091a7 100644
--- a/CSVParser.h
+++ b/CSVParser.h
@@ -1,2 +1,14 @@
#pragma once
+#include "ParserStrategy.h"
+
+class CSVParser : public ParserStrategy {
+public:
+ virtual void parse(File & f, Deserializer & d);
+ virtual unsigned int heuristic(File & f);
+
+private:
+ static CSVParser instance;
+ CSVParser();
+};
+
diff --git a/Canvas.cpp b/Canvas.cpp
new file mode 100644
index 0000000..63dbe74
--- /dev/null
+++ b/Canvas.cpp
@@ -0,0 +1,14 @@
+#include "Canvas.h"
+
+Tile & Canvas::get_tile(unsigned x, unsigned y) {
+ return this->tiles[this->pos_to_index(x, y)];
+}
+
+void Canvas::set_tile(unsigned x, unsigned y, TileData t) {
+ this->tiles[this->pos_to_index(x, y)] = Tile(t);
+}
+
+size_t Canvas::pos_to_index(unsigned x, unsigned y) {
+ return y * this->data.columns + x;
+}
+
diff --git a/Canvas.h b/Canvas.h
index e4dc65a..4c959f6 100644
--- a/Canvas.h
+++ b/Canvas.h
@@ -1,7 +1,6 @@
#pragma once
#include <vector>
-#include <memory>
#include "CanvasData.h"
#include "Tile.h"
@@ -9,10 +8,15 @@
class Canvas {
public:
virtual Tile & get_tile(unsigned x, unsigned y);
- virtual void set_tile(unsigned x, unsigned y, std::unique_ptr<TileData> t);
+ virtual void set_tile(unsigned x, unsigned y, TileData data);
-private:
+public:
CanvasData data;
- std::vector<Tile> tiles;
+
+private:
+ std::vector<Tile> tiles = {};
+
+private:
+ size_t pos_to_index(unsigned x, unsigned y);
};
diff --git a/Deserializer.cpp b/Deserializer.cpp
new file mode 100644
index 0000000..ecadbbe
--- /dev/null
+++ b/Deserializer.cpp
@@ -0,0 +1,32 @@
+#include "Deserializer.h"
+#include "Exception.h"
+
+void Deserializer::set_target(Museum * museum) {
+ this->museum = museum;
+}
+
+Museum & Deserializer::get_target() {
+ if (this->museum == nullptr)
+ throw Exception("no museum given to Deserializer");
+
+ return *this->museum;
+}
+
+void Deserializer::add_artist(ArtistData data) {
+ Museum & museum = this->get_target();
+ // museum.people.add_artist(data);
+ printf("add artist(%1.2f, %1.2f)...\n", data.x, data.y);
+}
+
+void Deserializer::set_canvas(CanvasData data) {
+ Museum & museum = this->get_target();
+ // museum.canvas.data = data;
+ printf("set canvas(%dx%d)...\n", data.rows, data.columns);
+}
+
+void Deserializer::add_tile(unsigned int x, unsigned int y, TileData data) {
+ Museum & museum = this->get_target();
+ // museum.canvas.set_tile(x, y, data);
+ printf("add tile(%d,%d) data(%s)...\n", x, y, data.type.c_str());
+}
+
diff --git a/Deserializer.h b/Deserializer.h
index 5123cc9..78b7920 100644
--- a/Deserializer.h
+++ b/Deserializer.h
@@ -1,20 +1,25 @@
#pragma once
#include <string>
-#include <memory>
#include "Museum.h"
#include "ArtistData.h"
#include "TileData.h"
+#include "CanvasData.h"
#include "Color.h"
class Deserializer {
public:
- void set_target(Museum & m);
- void add_artist(std::unique_ptr<ArtistData>);
- void set_rows(unsigned int);
- void set_cols(unsigned int);
+ void set_target(Museum * m);
void add_type(std::string, Color, unsigned int);
- void add_tile(unsigned int x, unsigned int y, std::unique_ptr<TileData>);
+
+ void set_canvas(CanvasData);
+
+ void add_tile(unsigned int x, unsigned int y, TileData);
+ void add_artist(ArtistData);
+
+private:
+ Museum & get_target();
+ Museum * museum = nullptr;
};
diff --git a/LocalFile.cpp b/LocalFile.cpp
index 1ff595a..ee5bf74 100644
--- a/LocalFile.cpp
+++ b/LocalFile.cpp
@@ -11,37 +11,47 @@ void LocalFile::open(const std::string url) {
if (path.starts_with(protocol))
path = path.substr(protocol.size());
- _file = new std::ifstream(path, std::ios::in);
- if (_file->fail() || !_file->is_open())
+ this->file = new std::ifstream(path, std::ios::in);
+ if (this->file->fail() || !this->file->is_open())
throw Exception("Cannot open file://%s\n", path.c_str());
}
void LocalFile::close() {
- if (_file == nullptr) return;
+ if (this->file == nullptr) return;
- if (_file->is_open())
- _file->close();
+ if (this->file->is_open())
+ this->file->close();
}
const std::string LocalFile::read() {
- if (_file == nullptr)
+ if (this->content != nullptr)
+ return *this->content;
+
+ if (this->file == nullptr)
throw Exception("File read after destructor\n");
- if (!_file->is_open())
+ if (!this->file->is_open())
throw Exception("File read after close\n");
- return std::string(
- std::istreambuf_iterator<char>(*_file),
+ this->content = new std::string(
+ std::istreambuf_iterator<char>(*this->file),
std::istreambuf_iterator<char>()
);
+
+ return *this->content;
}
LocalFile::~LocalFile() {
close();
- if (_file != nullptr) {
- delete _file;
- _file = nullptr;
+ if (this->file != nullptr) {
+ delete this->file;
+ this->file = nullptr;
+ }
+
+ if (this->content != nullptr) {
+ delete this->content;
+ this->content = nullptr;
}
}
diff --git a/LocalFile.h b/LocalFile.h
index df9a479..5a67dab 100644
--- a/LocalFile.h
+++ b/LocalFile.h
@@ -24,6 +24,7 @@ private:
static LocalFile instance;
private:
- std::ifstream * _file = nullptr;
+ std::ifstream * file = nullptr;
+ std::string * content = nullptr;
};
diff --git a/Museum.h b/Museum.h
index f15a2fe..d7ff57b 100644
--- a/Museum.h
+++ b/Museum.h
@@ -4,7 +4,7 @@
#include "Canvas.h"
class Museum {
-private:
+public:
People people;
Canvas canvas;
};
diff --git a/Parser.cpp b/Parser.cpp
new file mode 100644
index 0000000..8317216
--- /dev/null
+++ b/Parser.cpp
@@ -0,0 +1,32 @@
+#include <algorithm>
+
+#include "Parser.h"
+#include "Exception.h"
+
+void Parser::parse(File & file, Deserializer & deserializer) {
+ auto & col = Parser::get_collection();
+ if (col.size() < 1)
+ throw Exception("no parsers registered");
+
+ unsigned int best_score = 0;
+ ParserStrategy * best_strategy = nullptr;
+ for (ParserStrategy * strategy : col) {
+ unsigned int score = strategy->heuristic(file);
+ if (score <= best_score) continue;
+
+ best_score = score;
+ best_strategy = strategy;
+ }
+
+ if (best_strategy == nullptr)
+ throw Exception("unknown file type");
+
+ best_strategy->parse(file, deserializer);
+}
+
+void Parser::register_strategy(ParserStrategy * ps) {
+ auto & col = Parser::get_collection();
+ if (std::find(col.begin(), col.end(), ps) != col.end()) return;
+ col.push_back(ps);
+}
+
diff --git a/Parser.h b/Parser.h
index c867f9e..5ed68f6 100644
--- a/Parser.h
+++ b/Parser.h
@@ -5,10 +5,16 @@
#include "ParserStrategy.h"
class Parser {
+ typedef std::vector<ParserStrategy*> ParserCollection;
+
public:
static void parse(File & f, Deserializer & d);
+ static void register_strategy(ParserStrategy * p);
private:
- static void register_strategy(ParserStrategy & p);
+ static ParserCollection & get_collection() {
+ static ParserCollection c = {};
+ return c;
+ }
};
diff --git a/ParserStrategy.h b/ParserStrategy.h
index c9f9eff..54e853a 100644
--- a/ParserStrategy.h
+++ b/ParserStrategy.h
@@ -5,10 +5,6 @@
class ParserStrategy {
public:
- ParserStrategy() = default;
- virtual ~ParserStrategy() = 0;
-
-public:
virtual void parse(File & f, Deserializer & d) = 0;
virtual unsigned int heuristic(File & f) = 0;
};
diff --git a/People.h b/People.h
index ff30595..e4490f7 100644
--- a/People.h
+++ b/People.h
@@ -8,7 +8,7 @@
class People {
public:
- void add_artist(std::unique_ptr<ArtistData> data);
+ void add_artist(ArtistData data);
private:
std::vector<Artist> artists;
diff --git a/TXTParser.cpp b/TXTParser.cpp
new file mode 100644
index 0000000..c9de4ca
--- /dev/null
+++ b/TXTParser.cpp
@@ -0,0 +1,16 @@
+#include "TXTParser.h"
+#include "Parser.h"
+
+TXTParser TXTParser::instance {};
+TXTParser::TXTParser() {
+ Parser::register_strategy(this);
+}
+
+unsigned int TXTParser::heuristic(File & f) {
+ return 0;
+}
+
+void TXTParser::parse(File & f, Deserializer & d) {
+ printf("%s\n", __PRETTY_FUNCTION__);
+}
+
diff --git a/TXTParser.h b/TXTParser.h
index 3f59c93..1db9e9d 100644
--- a/TXTParser.h
+++ b/TXTParser.h
@@ -1,2 +1,14 @@
#pragma once
+#include "ParserStrategy.h"
+
+class TXTParser : public ParserStrategy {
+public:
+ virtual void parse(File & f, Deserializer & d);
+ virtual unsigned int heuristic(File & f);
+
+private:
+ static TXTParser instance;
+ TXTParser();
+};
+
diff --git a/Tile.cpp b/Tile.cpp
new file mode 100644
index 0000000..b461bdf
--- /dev/null
+++ b/Tile.cpp
@@ -0,0 +1,6 @@
+#include "Tile.h"
+
+Tile::Tile(TileData data) {
+ this->data = data;
+}
+
diff --git a/Tile.h b/Tile.h
index d4977de..954709f 100644
--- a/Tile.h
+++ b/Tile.h
@@ -6,6 +6,10 @@
class Tile {
public:
+ Tile();
+ Tile(TileData data);
+
+public:
TileData data;
private:
diff --git a/TileAppearance.h b/TileAppearance.h
index 3f59c93..25db909 100644
--- a/TileAppearance.h
+++ b/TileAppearance.h
@@ -1,2 +1,9 @@
#pragma once
+#include "Color.h"
+
+class TileAppearance {
+public:
+ Color color;
+};
+
diff --git a/TileBehavior.h b/TileBehavior.h
index 3f59c93..e46c0cf 100644
--- a/TileBehavior.h
+++ b/TileBehavior.h
@@ -1,2 +1,6 @@
#pragma once
+class TileBehavior {
+
+};
+
diff --git a/XMLParser.cpp b/XMLParser.cpp
new file mode 100644
index 0000000..779f51f
--- /dev/null
+++ b/XMLParser.cpp
@@ -0,0 +1,29 @@
+#include <cstdlib>
+
+#include "XMLParser.h"
+#include "Parser.h"
+
+using namespace std;
+
+XMLParser XMLParser::instance {};
+XMLParser::XMLParser() {
+ Parser::register_strategy(this);
+}
+
+unsigned int XMLParser::heuristic(File & f) {
+ const string content = f.read();
+ int open_backets = 0;
+ int close_brackets = 0;
+ for (char c : content) {
+ if (c == '<') open_backets++;
+ if (c == '>') close_brackets++;
+ }
+ int balance = abs(open_backets - close_brackets);
+ int penalty = 1 + balance * 10;
+ return (open_backets + close_brackets) / penalty;
+}
+
+void XMLParser::parse(File & f, Deserializer & d) {
+ printf("%s\n", __PRETTY_FUNCTION__);
+}
+
diff --git a/XMLParser.h b/XMLParser.h
index 3f59c93..7e3ff09 100644
--- a/XMLParser.h
+++ b/XMLParser.h
@@ -1,2 +1,14 @@
#pragma once
+#include "ParserStrategy.h"
+
+class XMLParser : public ParserStrategy {
+public:
+ virtual void parse(File & f, Deserializer & d);
+ virtual unsigned int heuristic(File & f);
+
+private:
+ static XMLParser instance;
+ XMLParser();
+};
+
diff --git a/main.cpp b/main.cpp
index 9e11e5b..b258a49 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,6 @@
#include <cstdio>
+#include "Exception.h"
#include "FileReader.h"
#include "Museum.h"
#include "Deserializer.h"
@@ -9,12 +10,29 @@ int main(int argc, char** argv) {
Museum m {};
Deserializer d {};
+ d.set_target(&m);
+
for (int i = 1; i < argc; i++) {
- File & f = FileReader::open(argv[i]);
- Parser::parse(f, d);
- f.close();
+ char * url = argv[i];
+ File * f = nullptr;
+
+ try {
+ f = &FileReader::open(url);
+ } catch (Exception & e) {
+ printf("File open error: %s\n", e.what());
+ return EXIT_FAILURE;
+ }
+
+ try {
+ Parser::parse(*f, d);
+ } catch (Exception & e) {
+ printf("Parser error: %s (%s)\n", e.what(), url);
+ return EXIT_FAILURE;
+ }
+
+ f->close();
}
- return 0;
+ return EXIT_SUCCESS;
}