Spirit parser to load simple 2D maps.

This commit is contained in:
King_DuckZ 2014-12-13 04:50:23 +01:00
parent bd241bbbd2
commit e17f77ae05
5 changed files with 111 additions and 4 deletions

View file

@ -6,6 +6,14 @@
#include <vector>
#include <algorithm>
#include <memory>
#include <iterator>
//This code might need to be removed, but for now it's handy to read a simple
//ascii file into a vector without worrying too much about details.
//TODO: remove along with the code in the constructor
#include "implem/asciimap_parser.hpp"
#include <iomanip>
#include <stdexcept>
namespace dk {
template <typename T, size_t D>
@ -22,9 +30,12 @@ namespace dk {
TileStreamer& operator= ( const TileStreamer& ) = delete;
void copy ( std::vector<T>& parDest, const coords& parFrom, const coords& parTo );
const coords& tilesCount ( void ) const { return m_count; }
private:
StreamPtr m_stream;
coords m_count;
std::vector<T> m_wholedata;
};
} //namespace dk

View file

@ -0,0 +1,56 @@
#ifndef idB6D0694FDF6B4902A244C7A51C9727FE
#define idB6D0694FDF6B4902A244C7A51C9727FE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
namespace dk { namespace implem {
struct get_line_f {
template <typename> struct result { typedef size_t type; };
template <typename I> size_t operator()(const I& parStart, const I& parPosIter) const {
return boost::spirit::get_column(parStart, parPosIter) - 1;
}
};
template <typename I, typename T>
struct AsciiMapGrammar : boost::spirit::qi::grammar<I, std::vector<T>()> {
explicit AsciiMapGrammar ( const I& parItStart );
boost::spirit::qi::rule<I, std::vector<T>()> start;
std::vector<int> lengths;
boost::phoenix::function<get_line_f> getline;
boost::spirit::qi::int_parser<T, 10, 1, 1> digit_int;
};
template <typename I, typename T>
AsciiMapGrammar<I, T>::AsciiMapGrammar (const I& parItStart) :
AsciiMapGrammar::base_type(start)
{
using boost::phoenix::push_back;
using boost::spirit::qi::_1;
using boost::spirit::qi::eol;
using boost::spirit::qi::eoi;
using boost::spirit::qi::raw;
using boost::phoenix::begin;
using boost::spirit::qi::int_parser;
start %= *digit_int %
raw[
eol
][push_back(boost::phoenix::ref(lengths), getline(boost::phoenix::val(parItStart), begin(_1)))]
;
}
}} //namespace dk::implem
#undef BOOST_SPIRIT_USE_PHOENIX_V3
#endif

View file

@ -31,6 +31,8 @@ namespace dk {
m_streamer(std::move(parStreamer)),
m_activeViewport(*this)
{
DK_ASSERT(m_streamer.tilesCount() == this->m_count);
setActiveViewport(coords(0), parCount);
}
///--------------------------------------------------------------------------
@ -45,7 +47,7 @@ namespace dk {
template <typename T, size_t D>
void Layer<T, D>::setActiveViewport (const coords& parFrom, const coords& parCount) {
m_tiles.clear();
const auto area = implem::area(parCount);
const auto area = implem::area<D>(parCount);
m_tiles.reserve(area);
m_streamer.copy(m_tiles, parFrom, parFrom + parCount);
m_activeViewport.setFrom(parFrom);

View file

@ -3,5 +3,38 @@ namespace dk {
TileStreamer<T, D>::TileStreamer (StreamPtr&& parStream) :
m_stream(std::move(parStream))
{
//TODO: this loader /only/ works with 2D tilesets, remove it asap
typedef std::istream_iterator<char> DataIterator;
typedef boost::spirit::multi_pass<DataIterator> WrappedIterator;
*m_stream >> std::noskipws;
auto first = WrappedIterator(DataIterator(*m_stream));
auto last = WrappedIterator(DataIterator());
implem::AsciiMapGrammar<WrappedIterator, T> grammar(first);
const bool p = boost::spirit::qi::parse(
first,
last,
grammar,
m_wholedata
);
if (not p or last != first) {
throw std::runtime_error("Invalid data: can't parse file");
}
//Only look at the front. Besides a bug in spirit makes the other counts
//invalid, see
//http://boost.2283326.n4.nabble.com/Possible-bug-in-line-pos-iterator-td4636592.html
m_count.x() = grammar.lengths.front();
m_count.y() = m_wholedata.size() / m_count.x();
}
template <typename T, size_t D>
void TileStreamer<T, D>::copy (std::vector<T>& parDest, const coords& /*parFrom*/, const coords& /*parTo*/) {
parDest.clear();
parDest.reserve(m_wholedata.size());
std::copy(m_wholedata.begin(), m_wholedata.end(), std::back_inserter(parDest));
}
} //namespace dk

View file

@ -8,10 +8,15 @@ int main() {
typedef dk::Tyler<2> Tiler;
typedef std::unique_ptr<std::ifstream> ifstreamptr;
Tiler tiler(Tiler::coords(8, 6), Tiler::coords(64));
Tiler tiler(Tiler::coords(10, 6), Tiler::coords(64));
auto bottom_layer = &tiler.push_layer<int>(dk::Layer<int, 2>::streamer_type(ifstreamptr(new std::ifstream(DATA_PATH"test.map"))));
tiler.push_layer<char>(dk::Layer<char, 2>::streamer_type(ifstreamptr(new std::ifstream(DATA_PATH"test_2.map"))));
const std::string map1(DATA_PATH"/test.map");
const std::string map2(DATA_PATH"/test_2.map");
std::cout << "Loading " << map1 << '\n';
auto bottom_layer = &tiler.push_layer<int>(dk::Layer<int, 2>::streamer_type(ifstreamptr(new std::ifstream(map1))));
std::cout << "Loading " << map2 << '\n';
tiler.push_layer<char>(dk::Layer<char, 2>::streamer_type(ifstreamptr(new std::ifstream(map2))), dk::Vector<int, 2>(2));
{
auto ittest = bottom_layer->begin();