Refactoring.

This commit is contained in:
Sergey Magidovich 2015-10-17 19:26:25 +03:00
parent 11f242465b
commit b8970aa481
7 changed files with 736 additions and 680 deletions

View file

@ -0,0 +1,45 @@
#include "osm_time_range.hpp"
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::Time,
(uint8_t, hours)
(uint8_t, minutes)
(uint8_t, flags)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::TimeSpan,
(osmoh::Time, from)
(osmoh::Time, to)
(uint8_t, flags)
(osmoh::Time, period)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::Weekday,
(uint8_t, weekdays)
(uint16_t, nth)
(int32_t, offset)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::State,
(uint8_t, state)
(std::string, comment)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::TimeRule,
(osmoh::TWeekdays, weekdays)
(osmoh::TTimeSpans, timespan)
(osmoh::State, state)
(uint8_t, int_flags)
)

View file

@ -14,4 +14,6 @@ ROOT_DIR = ../..
include($$ROOT_DIR/common.pri)
SOURCES += osm_time_range.cpp
HEADERS += osm_time_range.hpp
HEADERS += osm_time_range.hpp \
osm_parsers.hpp \
adapted_structs.hpp

View file

@ -1,4 +1,3 @@
TARGET = opening_hours_tests
CONFIG += console worn_off
CONFIG -= app_bundle
@ -9,7 +8,10 @@ DEPENDENCIES += opening_hours \
include($$ROOT_DIR/common.pri)
INCLUDEPATH += $$ROOT_DIR/3party/opening_hours
OPENING_HOURS_INCLUDE = $$ROOT_DIR/3party/opening_hours
INCLUDEPATH += $$OPENING_HOURS_INCLUDE
SOURCES += osm_time_range_tests.cpp
SOURCES += ../osm_time_range.hpp
HEADERS += $$OPENING_HOURS_INCLUDE/osm_time_range.hpp \
$$OPENING_HOURS_INCLUDE/osm_parsers.hpp
$$OPENING_HOURS_INCLUDE/adopted_structs.hpp

View file

@ -21,9 +21,11 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "osm_time_range.hpp"
#include <osm_time_range.hpp>
#include <osm_parsers.hpp>
#include <iostream>
#include <sstream>
#include <fstream>
#include <map>
#include <locale>
@ -54,6 +56,41 @@ bool test(Char const * in, Parser const & p, bool full_match = true)
return boost::spirit::qi::parse(in, last, p) && (!full_match || (in == last));
}
template <template <typename> class Parser, typename Char>
std::basic_string<Char> ParseAndUnparse(Char const * input)
{
// we don't care about the result of the "what" function.
// we only care that all parsers have it:
using boost::spirit::qi::phrase_parse;
using boost::spirit::standard_wide::space;
// TODO move to template
osmoh::TTimeRules timeRules;
std::basic_string<Char> const str(input);
Parser<decltype(begin(str))> p;
boost::spirit::qi::what(p);
auto parsed = boost::spirit::qi::phrase_parse(
begin(str),
end(str),
p,
space,
timeRules);
if (!parsed)
return {};
std::basic_stringstream<Char> sstr;
for (auto it = begin(timeRules); it != end(timeRules); ++it)
{
sstr << (*it);
if (next(it) != end(timeRules))
sstr << ' ';
}
return sstr.str();
}
BOOST_AUTO_TEST_CASE(OpeningHours_Locale)
{
@ -199,13 +236,15 @@ BOOST_AUTO_TEST_CASE(OpeningHours_StaticSet)
{
{
// TODO(mgsergio) move validation from parsing
OSMTimeRange oh = OSMTimeRange::FromString("06:00-02:00/21:03");
BOOST_CHECK(oh.IsValid());
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-02:00/21:03");
// BOOST_CHECK(oh.IsValid());
auto const rule = "06:00-02:00/21:03";
BOOST_CHECK_EQUAL(ParseAndUnparse<osmoh::parsing::time_domain>(rule), rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-09:00/03");
BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(test_hard<osmoh::parsing::time_domain>("06:00-09:00/03"));
//BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-07:00/03");

View file

@ -0,0 +1,618 @@
#pragma once
#include "adapted_structs.hpp"
//#define BOOST_SPIRIT_DEBUG 1
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_subrule.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#pragma clang diagnostic pop
#else
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#endif
namespace osmoh
{
namespace phx = boost::phoenix;
class test_impl
{
public:
template <typename T>
struct result { typedef void type; };
template <typename Arg>
void operator() (const Arg & a) const
{
std::cout << a << " \t(" << typeid(a).name() << ")" << std::endl;
}
};
phx::function<test_impl> const test = test_impl();
inline boost::posix_time::time_period make_time_period(boost::gregorian::date const & d,
osmoh::TimeSpan const & ts)
{
using boost::posix_time::ptime;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
/// TODO(yershov@): Need create code for calculate real values
ptime sunrise(d, hours(6));
ptime sunset(d, hours(19));
ptime t1, t2;
if (ts.from.flags & osmoh::Time::eSunrise)
t1 = sunrise;
else if (ts.from.flags & osmoh::Time::eSunset)
t1 = sunset;
else
t1 = ptime(d, hours((ts.from.flags & osmoh::Time::eHours) ? ts.from.hours : 0) + minutes((ts.from.flags & osmoh::Time::eMinutes) ? ts.from.minutes : 0));
t2 = t1;
if (ts.to.flags & osmoh::Time::eSunrise)
t2 = sunrise;
else if (ts.to.flags & osmoh::Time::eSunset)
t2 = sunset;
else
{
t2 = ptime(d, hours((ts.to.flags & osmoh::Time::eHours) ? ts.to.hours : 24) + minutes((ts.to.flags & osmoh::Time::eMinutes) ? ts.to.minutes : 0));
if (t2 < t1)
t2 += hours(24);
}
return time_period(t1, t2);
}
namespace parsing
{
namespace qi = boost::spirit::qi;
namespace repo = boost::spirit::repository;
namespace charset = boost::spirit::standard_wide;
using space_type = charset::space_type;
class dash_ : public qi::symbols<wchar_t>
{
public:
dash_()
{
add
(L"-")
/* not standard */
(L"")(L"")(L"")(L"~")(L"")(L"")(L"to")(L"às")(L"ás")(L"as")(L"a")(L"ate")(L"bis")
;
}
} dash;
class event_ : public qi::symbols<wchar_t, uint8_t>
{
public:
event_()
{
add
(L"dawn", osmoh::Time::eSunrise)(L"sunrise", osmoh::Time::eSunrise)(L"sunset", osmoh::Time::eSunset)(L"dusk", osmoh::Time::eSunset)
;
}
} event;
struct wdays_ : qi::symbols<wchar_t, unsigned>
{
wdays_()
{
add
(L"mo", 0)(L"tu", 1)(L"we", 2)(L"th", 3)(L"fr", 4)(L"sa", 5)(L"su", 6) // en
(L"mon", 0)(L"tue", 1)(L"wed", 2)(L"thu", 3)(L"fri", 4)(L"sat", 5)(L"sun", 6) // en
(L"пн", 0)(L"вт", 1)(L"ср", 2)(L"чт", 3)(L"пт", 4)(L"сб", 5)(L"вс", 6) // ru
(L"пн.", 0)(L"вт.", 1)(L"ср.", 2)(L"чт.", 3)(L"пт.", 4)(L"сб.", 5)(L"вс.", 6) // ru
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"je", 3)(L"ve", 4)(L"sa", 5)(L"di", 6) // fr
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"gi", 3)(L"ve", 4)(L"sa", 5)(L"do", 6) // it
(L"lu", 0)(L"ma", 1)(L"mi", 2)(L"ju", 3)(L"vie", 4)(L"", 5)(L"do", 6) // sp
(L"週一", 0)(L"週二", 1)(L"週三", 2)(L"週四", 3)(L"週五", 4)(L"週六", 5)(L"週日", 6) // ch traditional
(L"senin", 0)(L"selasa", 1)(L"rabu", 2)(L"kamis", 3)(L"jum'at", 4)(L"sabtu", 5)(L"minggu", 6) // indonesian
(L"wd", 2)
;
}
} wdays;
struct month_ : qi::symbols<wchar_t, unsigned>
{
month_()
{
add
(L"jan", 1)(L"feb", 2)(L"mar", 3)(L"apr", 4)(L"may", 5)(L"jun", 6)
(L"jul", 7)(L"aug", 8)(L"sep", 9)(L"oct", 10)(L"nov", 11)(L"dec", 12)
;
}
} month;
struct hours_ : qi::symbols<char, uint8_t>
{
hours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)
;
}
} hours;
struct exthours_ : qi::symbols<char, uint8_t>
{
exthours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)
;
}
} exthours;
struct minutes_ : qi::symbols<char, uint8_t>
{
minutes_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)("49", 49)
("50", 50)("51", 51)("52", 52)("53", 53)("54", 54)("55", 55)("56", 56)("57", 57)("58", 58)("59", 59)
;
}
} minutes;
struct weeknum_ : qi::symbols<char, unsigned>
{
weeknum_()
{
add
( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)("49", 49)
("50", 50)("51", 51)("52", 52)("53", 53)
;
}
} weeknum;
struct daynum_ : qi::symbols<char, unsigned>
{
daynum_()
{
add
("1", 1)("2", 2)("3", 3)("4", 4)("5", 5)("6", 6)("7", 7)("8", 8)("9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)
;
}
} daynum;
template <class Iterator>
class year_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> year;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
year_selector() : year_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> _4digit = {};
year %= _4digit;
year_range %= (year >> dash >> year >> '/' >> uint_)
| (year >> dash >> year)
| year >> char_('+')
| year
;
main %= year_range % ',';
}
};
template <typename Iterator>
class week_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> week;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
week_selector() : week_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
week %= (weeknum >> dash >> weeknum >> '/' >> uint_)
| (weeknum >> dash >> weeknum)
| weeknum
;
main %= charset::no_case[lit("week")] >> week % ',';
}
};
template <typename Iterator>
class month_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> date;
qi::rule<Iterator, space_type> day_offset;
qi::rule<Iterator, space_type> date_with_offsets;
qi::rule<Iterator, space_type> monthday_range;
qi::rule<Iterator, space_type> month_range;
qi::rule<Iterator, space_type> main;
public:
month_selector() : month_selector::base_type(main)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> year = {};
day_offset %= (char_('+') | char_('-')) >> int_ >> charset::no_case[(lit("days") | lit("day"))];
date %= charset::no_case[(-year >> month >> daynum)]
| (-year >> charset::no_case[lit("easter")])
| daynum >> !(lit(':') >> qi::digit)
;
date_with_offsets %= date >> -((char_('+') | char_('-')) >> charset::no_case[wdays] >> qi::no_skip[qi::space]) >> -day_offset;
monthday_range %= (date_with_offsets >> dash >> date_with_offsets)
| (date_with_offsets >> '+')
| date_with_offsets
| charset::no_case[(-year >> month >> dash >> month >> '/' >> int_)]
| charset::no_case[(-year >> month >> dash >> month)]
| charset::no_case[(-year >> month)]
;
month_range %= charset::no_case[(month >> dash >> month)]
| charset::no_case[month]
;
main %= (monthday_range % ',') | (month_range % ',');
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(month_range);
BOOST_SPIRIT_DEBUG_NODE(monthday_range);
BOOST_SPIRIT_DEBUG_NODE(date_with_offsets);
BOOST_SPIRIT_DEBUG_NODE(date);
BOOST_SPIRIT_DEBUG_NODE(day_offset);
}
};
template <typename Iterator>
class weekday_selector : public qi::grammar<Iterator, osmoh::TWeekdays(), space_type>
{
protected:
qi::rule<Iterator, uint8_t(), space_type> nth;
qi::rule<Iterator, uint16_t(), space_type> nth_entry;
qi::rule<Iterator, int32_t(), space_type, qi::locals<int8_t>> day_offset;
qi::rule<Iterator, space_type> holyday;
qi::rule<Iterator, space_type> holiday_sequence;
qi::rule<Iterator, osmoh::Weekday(), space_type> weekday_range;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> weekday_sequence;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> main;
public:
weekday_selector() : weekday_selector::base_type(main)
{
using qi::_a;
using qi::_1;
using qi::_2;
using qi::_val;
using qi::lit;
using qi::ushort_;
using boost::phoenix::at_c;
nth %= ushort_(1) | ushort_(2) | ushort_(3) | ushort_(4) | ushort_(5);
nth_entry = (nth >> dash >> nth) [_val |= ((2 << ((_2-1)-(_1-1))) - 1) << (_1-1)]
| (lit('-') >> nth) [_val |= (0x0100 << (_1 - 1))]
| nth [_val |= (1 << (_1 - 1))]
;
day_offset = (lit('+')[_a = 1] | lit('-') [_a = -1]) >> ushort_[_val = _1*_a] >> charset::no_case[(lit(L"days") | lit(L"day"))];
holyday %= (charset::no_case[lit(L"SH")] >> -day_offset) | charset::no_case[lit(L"PH")];
holiday_sequence %= holyday % ',';
weekday_range = (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
>> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L','
>> L']' >> day_offset[at_c<2>(_val) = _1])
| (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)] >> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L',' >> L']')
| charset::no_case[(wdays >> dash >> wdays)] [at_c<0>(_val) |= ((2 << ((_2)-(_1))) - 1) << (_1)]
| charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
;
weekday_sequence %= (weekday_range % L',') >> !qi::no_skip[charset::alpha] >> -lit(L':');
main = (holiday_sequence >> -lit(L',') >> weekday_sequence[_val = _1])
| weekday_sequence[_val = _1] >> -(-lit(L',') >> holiday_sequence)
| holiday_sequence
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(weekday_sequence);
BOOST_SPIRIT_DEBUG_NODE(weekday_range);
BOOST_SPIRIT_DEBUG_NODE(holiday_sequence);
}
};
template <typename Iterator>
class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_type>
{
protected:
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> extended_hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type> variable_time;
qi::rule<Iterator, osmoh::Time(), space_type> extended_time;
qi::rule<Iterator, osmoh::Time(), space_type> time;
qi::rule<Iterator, osmoh::TimeSpan(), space_type> timespan;
qi::rule<Iterator, osmoh::TTimeSpans(), space_type> main;
class validate_timespan_impl
{
public:
template <typename T>
struct result { typedef bool type; };
bool operator() (osmoh::TimeSpan const & ts) const
{
using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
bool result = true;
if (ts.period.flags)
{
time_period tp = osmoh::make_time_period(boost::gregorian::day_clock::local_day(), ts);
result = (tp.length() >= time_duration(ts.period.hours, ts.period.minutes, 0 /* seconds */));
}
return result;
}
};
public:
time_selector() : time_selector::base_type(main)
{
using qi::int_;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_a;
using qi::_val;
using qi::lit;
using qi::_pass;
using charset::char_;
using boost::phoenix::at_c;
phx::function<validate_timespan_impl> const validate_timespan = validate_timespan_impl();
hour_minutes = hours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
;
extended_hour_minutes = exthours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
;
variable_time =
(lit('(')
>> charset::no_case[event][at_c<2>(_val) |= _1]
>> (
char_('+')[at_c<2>(_val) |= osmoh::Time::ePlus]
| char_('-')[at_c<2>(_val) |= osmoh::Time::eMinus]
)
>> hour_minutes[at_c<2>(_1) |= at_c<2>(_val), _val = _1]
>> lit(')')
)
| charset::no_case[event][at_c<2>(_val) |= _1]
;
extended_time %= extended_hour_minutes | variable_time;
time %= hour_minutes | variable_time;
timespan =
(time >> dash >> extended_time >> L'/' >> hour_minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<3>(_val) = _3]
| (time >> dash >> extended_time >> L'/' >> minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<1>(at_c<3>(_val)) = _3, at_c<2>(at_c<3>(_val)) = osmoh::Time::eMinutes]
| (time >> dash >> extended_time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::ePlus]
| (time >> dash >> extended_time)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2]
| (time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::ePlus]
| time [at_c<0>(_val) = _1]
;
main %= timespan[_pass = validate_timespan(_1)] % ',';
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(timespan);
BOOST_SPIRIT_DEBUG_NODE(time);
BOOST_SPIRIT_DEBUG_NODE(extended_time);
BOOST_SPIRIT_DEBUG_NODE(variable_time);
BOOST_SPIRIT_DEBUG_NODE(extended_hour_minutes);
}
};
template <typename Iterator>
class selectors : public qi::grammar<Iterator, osmoh::TimeRule(), space_type>
{
protected:
weekday_selector<Iterator> weekday_selector;
time_selector<Iterator> time_selector;
year_selector<Iterator> year_selector;
month_selector<Iterator> month_selector;
week_selector<Iterator> week_selector;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, osmoh::TimeRule(), space_type> small_range_selectors;
qi::rule<Iterator, space_type> wide_range_selectors;
qi::rule<Iterator, osmoh::TimeRule(), space_type> main;
public:
selectors() : selectors::base_type(main)
{
using qi::_1;
using qi::_val;
using qi::lit;
using qi::lexeme;
using charset::char_;
using boost::phoenix::at_c;
using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'];
wide_range_selectors = -year_selector >> -month_selector >> -week_selector >> -lit(':') | (comment >> ':');
small_range_selectors = -weekday_selector[at_c<0>(_val) = _1] >> -( lit("24/7") | time_selector[at_c<1>(_val) = _1]);
main =
(
lit(L"24/7")
| lit(L"24時間営業")
| lit(L"7/24")
| lit(L"24時間")
| charset::no_case[lit(L"daily 24/7")]
| charset::no_case[lit(L"24 hours")]
| charset::no_case[lit(L"24 horas")]
| charset::no_case[lit(L"круглосуточно")]
| charset::no_case[lit(L"24 часа")]
| charset::no_case[lit(L"24 hrs")]
| charset::no_case[lit(L"nonstop")]
| charset::no_case[lit(L"24hrs")]
| charset::no_case[lit(L"open 24 hours")]
| charset::no_case[lit(L"24 stunden")]
)[at_c<0>(at_c<2>(_val)) = State::eOpen]
| (-wide_range_selectors >> small_range_selectors[_val = _1, at_c<0>(at_c<2>(_val)) = State::eOpen])
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(small_range_selectors);
BOOST_SPIRIT_DEBUG_NODE(wide_range_selectors);
}
};
template <typename Iterator>
class time_domain : public qi::grammar<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>>
{
protected:
selectors<Iterator> selector_sequence;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, space_type> separator;
qi::rule<Iterator, space_type> base_separator;
qi::rule<Iterator, osmoh::TimeRule(), space_type> rule_sequence;
qi::rule<Iterator, osmoh::State(), space_type> rule_modifier;
qi::rule<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>> main;
public:
time_domain() : time_domain::base_type(main)
{
using qi::lit;
using qi::lexeme;
using qi::_1;
using qi::_a;
using qi::_val;
using charset::char_;
using boost::phoenix::at_c;
using qi::lazy;
using qi::eps;
using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['(' >> +(char_ - ')') >> ')'];
base_separator = lit(';') | lit("||");
separator = lit(';') | lit("||") | lit(',');
rule_modifier =
(charset::no_case[lit("open")][at_c<0>(_val) = State::eOpen] >> -comment[at_c<1>(_val) = _1])
| ((charset::no_case[lit("closed") | lit("off")])[at_c<0>(_val) = State::eClosed] >> -comment[at_c<1>(_val) = _1])
| (charset::no_case[lit("unknown")][at_c<0>(_val) = State::eUnknown] >> -comment[at_c<1>(_val) = _1])
| comment[at_c<0>(_val) = State::eUnknown, at_c<1>(_val) = _1]
;
rule_sequence = selector_sequence[_val = _1]
>> -rule_modifier[at_c<2>(_val) = _1, at_c<3>(_val) = 1];
main %= -(lit("opening_hours") >> lit('='))
>> rule_sequence[_a = phx::val(&base_separator),
phx::if_(at_c<3>(_1) || phx::size(at_c<1>(_1)))[_a = phx::val(&separator)]] % lazy(*_a);
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(rule_sequence);
BOOST_SPIRIT_DEBUG_NODE(rule_modifier);
}
};
template <typename Iterator>
inline bool parse_timerange(Iterator first, Iterator last, osmoh::TTimeRules & context)
{
using qi::phrase_parse;
using charset::space;
time_domain<Iterator> time_domain;
bool r = phrase_parse(
first, /* start iterator */
last, /* end iterator */
time_domain, /* the parser */
space, /* the skip-parser */
context /* result storage */
);
if (first != last) // fail if we did not get a full match
return false;
return r;
}
} // namespace parsing
} // namespace osmoh

View file

@ -22,37 +22,12 @@
THE SOFTWARE.
*/
#include "osm_time_range.hpp"
#include "osm_parsers.hpp"
#include <chrono>
#include <iomanip>
#include <ios>
#include <vector>
#include <codecvt>
//#define BOOST_SPIRIT_DEBUG 1
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_subrule.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#pragma clang diagnostic pop
#else
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#endif
namespace osmoh
{
@ -153,641 +128,29 @@ std::ostream & operator << (std::ostream & s, TimeRule const & w)
for (auto const & e : w.timespan)
s << e;
std::cout << "Weekdays size " << w.weekdays.size() <<
" Timespan size " << w.timespan.size() << std::endl;
return s << w.state;
}
} // namespace osmoh
boost::posix_time::time_period make_time_period(boost::gregorian::date const & d, osmoh::TimeSpan const & ts)
namespace
{
bool check_timespan(osmoh::TimeSpan const &ts, boost::gregorian::date const & d, boost::posix_time::ptime const & p)
{
using boost::gregorian::days;
using boost::posix_time::ptime;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
/// TODO(yershov@): Need create code for calculate real values
ptime sunrise(d, hours(6));
ptime sunset(d, hours(19));
ptime t1, t2;
if (ts.from.flags & osmoh::Time::eSunrise)
t1 = sunrise;
else if (ts.from.flags & osmoh::Time::eSunset)
t1 = sunset;
else
t1 = ptime(d, hours((ts.from.flags & osmoh::Time::eHours) ? ts.from.hours : 0) + minutes((ts.from.flags & osmoh::Time::eMinutes) ? ts.from.minutes : 0));
t2 = t1;
if (ts.to.flags & osmoh::Time::eSunrise)
t2 = sunrise;
else if (ts.to.flags & osmoh::Time::eSunset)
t2 = sunset;
else
{
t2 = ptime(d, hours((ts.to.flags & osmoh::Time::eHours) ? ts.to.hours : 24) + minutes((ts.to.flags & osmoh::Time::eMinutes) ? ts.to.minutes : 0));
if (t2 < t1)
t2 += hours(24);
}
return time_period(t1, t2);
}
} // namespace osmoh
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::Time,
(uint8_t, hours)
(uint8_t, minutes)
(uint8_t, flags)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::TimeSpan,
(osmoh::Time, from)
(osmoh::Time, to)
(uint8_t, flags)
(osmoh::Time, period)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::Weekday,
(uint8_t, weekdays)
(uint16_t, nth)
(int32_t, offset)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::State,
(uint8_t, state)
(std::string, comment)
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::TimeRule,
(osmoh::TWeekdays, weekdays)
(osmoh::TTimeSpans, timespan)
(osmoh::State, state)
(uint8_t, int_flags)
)
namespace
{
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace repo = boost::spirit::repository;
namespace charset = boost::spirit::standard_wide;
using space_type = charset::space_type;
class test_impl
{
public:
template <typename T>
struct result { typedef void type; };
template <typename Arg>
void operator() (const Arg & a) const
{
std::cout << a << " \t(" << typeid(a).name() << ")" << std::endl;
}
};
phx::function<test_impl> const test = test_impl();
class dash_ : public qi::symbols<wchar_t>
{
public:
dash_()
{
add
(L"-")
/* not standard */
(L"")(L"")(L"")(L"~")(L"")(L"")(L"to")(L"às")(L"ás")(L"as")(L"a")(L"ate")(L"bis")
;
}
} dash;
class event_ : public qi::symbols<wchar_t, uint8_t>
{
public:
event_()
{
add
(L"dawn", osmoh::Time::eSunrise)(L"sunrise", osmoh::Time::eSunrise)(L"sunset", osmoh::Time::eSunset)(L"dusk", osmoh::Time::eSunset)
;
}
} event;
struct wdays_ : qi::symbols<wchar_t, unsigned>
{
wdays_()
{
add
(L"mo", 0)(L"tu", 1)(L"we", 2)(L"th", 3)(L"fr", 4)(L"sa", 5)(L"su", 6) // en
(L"mon", 0)(L"tue", 1)(L"wed", 2)(L"thu", 3)(L"fri", 4)(L"sat", 5)(L"sun", 6) // en
(L"пн", 0)(L"вт", 1)(L"ср", 2)(L"чт", 3)(L"пт", 4)(L"сб", 5)(L"вс", 6) // ru
(L"пн.", 0)(L"вт.", 1)(L"ср.", 2)(L"чт.", 3)(L"пт.", 4)(L"сб.", 5)(L"вс.", 6) // ru
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"je", 3)(L"ve", 4)(L"sa", 5)(L"di", 6) // fr
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"gi", 3)(L"ve", 4)(L"sa", 5)(L"do", 6) // it
(L"lu", 0)(L"ma", 1)(L"mi", 2)(L"ju", 3)(L"vie", 4)(L"", 5)(L"do", 6) // sp
(L"週一", 0)(L"週二", 1)(L"週三", 2)(L"週四", 3)(L"週五", 4)(L"週六", 5)(L"週日", 6) // ch traditional
(L"senin", 0)(L"selasa", 1)(L"rabu", 2)(L"kamis", 3)(L"jum'at", 4)(L"sabtu", 5)(L"minggu", 6) // indonesian
(L"wd", 2)
;
}
} wdays;
struct month_ : qi::symbols<wchar_t, unsigned>
{
month_()
{
add
(L"jan", 1)(L"feb", 2)(L"mar", 3)(L"apr", 4)(L"may", 5)(L"jun", 6)
(L"jul", 7)(L"aug", 8)(L"sep", 9)(L"oct", 10)(L"nov", 11)(L"dec", 12)
;
}
} month;
struct hours_ : qi::symbols<char, uint8_t>
{
hours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)
;
}
} hours;
struct exthours_ : qi::symbols<char, uint8_t>
{
exthours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)
;
}
} exthours;
struct minutes_ : qi::symbols<char, uint8_t>
{
minutes_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)("49", 49)
("50", 50)("51", 51)("52", 52)("53", 53)("54", 54)("55", 55)("56", 56)("57", 57)("58", 58)("59", 59)
;
}
} minutes;
struct weeknum_ : qi::symbols<char, unsigned>
{
weeknum_()
{
add
( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)("49", 49)
("50", 50)("51", 51)("52", 52)("53", 53)
;
}
} weeknum;
struct daynum_ : qi::symbols<char, unsigned>
{
daynum_()
{
add
("1", 1)("2", 2)("3", 3)("4", 4)("5", 5)("6", 6)("7", 7)("8", 8)("9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)
;
}
} daynum;
template <class Iterator>
class year_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> year;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
year_selector() : year_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> _4digit = {};
year %= _4digit;
year_range %= (year >> dash >> year >> '/' >> uint_)
| (year >> dash >> year)
| year >> char_('+')
| year
;
main %= year_range % ',';
}
};
template <typename Iterator>
class week_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> week;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
week_selector() : week_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
week %= (weeknum >> dash >> weeknum >> '/' >> uint_)
| (weeknum >> dash >> weeknum)
| weeknum
;
main %= charset::no_case[lit("week")] >> week % ',';
}
};
template <typename Iterator>
class month_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> date;
qi::rule<Iterator, space_type> day_offset;
qi::rule<Iterator, space_type> date_with_offsets;
qi::rule<Iterator, space_type> monthday_range;
qi::rule<Iterator, space_type> month_range;
qi::rule<Iterator, space_type> main;
public:
month_selector() : month_selector::base_type(main)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> year = {};
day_offset %= (char_('+') | char_('-')) >> int_ >> charset::no_case[(lit("days") | lit("day"))];
date %= charset::no_case[(-year >> month >> daynum)]
| (-year >> charset::no_case[lit("easter")])
| daynum >> !(lit(':') >> qi::digit)
;
date_with_offsets %= date >> -((char_('+') | char_('-')) >> charset::no_case[wdays] >> qi::no_skip[qi::space]) >> -day_offset;
monthday_range %= (date_with_offsets >> dash >> date_with_offsets)
| (date_with_offsets >> '+')
| date_with_offsets
| charset::no_case[(-year >> month >> dash >> month >> '/' >> int_)]
| charset::no_case[(-year >> month >> dash >> month)]
| charset::no_case[(-year >> month)]
;
month_range %= charset::no_case[(month >> dash >> month)]
| charset::no_case[month]
;
main %= (monthday_range % ',') | (month_range % ',');
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(month_range);
BOOST_SPIRIT_DEBUG_NODE(monthday_range);
BOOST_SPIRIT_DEBUG_NODE(date_with_offsets);
BOOST_SPIRIT_DEBUG_NODE(date);
BOOST_SPIRIT_DEBUG_NODE(day_offset);
}
};
template <typename Iterator>
class weekday_selector : public qi::grammar<Iterator, osmoh::TWeekdays(), space_type>
{
protected:
qi::rule<Iterator, uint8_t(), space_type> nth;
qi::rule<Iterator, uint16_t(), space_type> nth_entry;
qi::rule<Iterator, int32_t(), space_type, qi::locals<int8_t>> day_offset;
qi::rule<Iterator, space_type> holyday;
qi::rule<Iterator, space_type> holiday_sequence;
qi::rule<Iterator, osmoh::Weekday(), space_type> weekday_range;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> weekday_sequence;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> main;
public:
weekday_selector() : weekday_selector::base_type(main)
{
using qi::_a;
using qi::_1;
using qi::_2;
using qi::_val;
using qi::lit;
using qi::ushort_;
using boost::phoenix::at_c;
nth %= ushort_(1) | ushort_(2) | ushort_(3) | ushort_(4) | ushort_(5);
nth_entry = (nth >> dash >> nth) [_val |= ((2 << ((_2-1)-(_1-1))) - 1) << (_1-1)]
| (lit('-') >> nth) [_val |= (0x0100 << (_1 - 1))]
| nth [_val |= (1 << (_1 - 1))]
;
day_offset = (lit('+')[_a = 1] | lit('-') [_a = -1]) >> ushort_[_val = _1*_a] >> charset::no_case[(lit(L"days") | lit(L"day"))];
holyday %= (charset::no_case[lit(L"SH")] >> -day_offset) | charset::no_case[lit(L"PH")];
holiday_sequence %= holyday % ',';
weekday_range = (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
>> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L','
>> L']' >> day_offset[at_c<2>(_val) = _1])
| (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)] >> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L',' >> L']')
| charset::no_case[(wdays >> dash >> wdays)] [at_c<0>(_val) |= ((2 << ((_2)-(_1))) - 1) << (_1)]
| charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
;
weekday_sequence %= (weekday_range % L',') >> !qi::no_skip[charset::alpha] >> -lit(L':');
main = (holiday_sequence >> -lit(L',') >> weekday_sequence[_val = _1])
| weekday_sequence[_val = _1] >> -(-lit(L',') >> holiday_sequence)
| holiday_sequence
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(weekday_sequence);
BOOST_SPIRIT_DEBUG_NODE(weekday_range);
BOOST_SPIRIT_DEBUG_NODE(holiday_sequence);
}
};
template <typename Iterator>
class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_type>
{
protected:
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> extended_hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type> variable_time;
qi::rule<Iterator, osmoh::Time(), space_type> extended_time;
qi::rule<Iterator, osmoh::Time(), space_type> time;
qi::rule<Iterator, osmoh::TimeSpan(), space_type> timespan;
qi::rule<Iterator, osmoh::TTimeSpans(), space_type> main;
class validate_timespan_impl
{
public:
template <typename T>
struct result { typedef bool type; };
bool operator() (osmoh::TimeSpan const & ts) const
{
using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
bool result = true;
if (ts.period.flags)
{
time_period tp = osmoh::make_time_period(boost::gregorian::day_clock::local_day(), ts);
result = (tp.length() >= time_duration(ts.period.hours, ts.period.minutes, 0 /* seconds */));
}
return result;
}
};
public:
time_selector() : time_selector::base_type(main)
{
using qi::int_;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_a;
using qi::_val;
using qi::lit;
using qi::_pass;
using charset::char_;
using boost::phoenix::at_c;
phx::function<validate_timespan_impl> const validate_timespan = validate_timespan_impl();
hour_minutes = hours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
;
extended_hour_minutes = exthours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
;
variable_time =
(lit('(')
>> charset::no_case[event][at_c<2>(_val) |= _1]
>> (
char_('+')[at_c<2>(_val) |= osmoh::Time::ePlus]
| char_('-')[at_c<2>(_val) |= osmoh::Time::eMinus]
)
>> hour_minutes[at_c<2>(_1) |= at_c<2>(_val), _val = _1]
>> lit(')')
)
| charset::no_case[event][at_c<2>(_val) |= _1]
;
extended_time %= extended_hour_minutes | variable_time;
time %= hour_minutes | variable_time;
timespan =
(time >> dash >> extended_time >> L'/' >> hour_minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<3>(_val) = _3]
| (time >> dash >> extended_time >> L'/' >> minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<1>(at_c<3>(_val)) = _3, at_c<2>(at_c<3>(_val)) = osmoh::Time::eMinutes]
| (time >> dash >> extended_time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::ePlus]
| (time >> dash >> extended_time)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2]
| (time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::ePlus]
| time [at_c<0>(_val) = _1]
;
main %= timespan[_pass = validate_timespan(_1)] % ',';
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(timespan);
BOOST_SPIRIT_DEBUG_NODE(time);
BOOST_SPIRIT_DEBUG_NODE(extended_time);
BOOST_SPIRIT_DEBUG_NODE(variable_time);
BOOST_SPIRIT_DEBUG_NODE(extended_hour_minutes);
}
};
template <typename Iterator>
class selectors : public qi::grammar<Iterator, osmoh::TimeRule(), space_type>
{
protected:
weekday_selector<Iterator> weekday_selector;
time_selector<Iterator> time_selector;
year_selector<Iterator> year_selector;
month_selector<Iterator> month_selector;
week_selector<Iterator> week_selector;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, osmoh::TimeRule(), space_type> small_range_selectors;
qi::rule<Iterator, space_type> wide_range_selectors;
qi::rule<Iterator, osmoh::TimeRule(), space_type> main;
public:
selectors() : selectors::base_type(main)
{
using qi::_1;
using qi::_val;
using qi::lit;
using qi::lexeme;
using charset::char_;
using boost::phoenix::at_c;
using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'];
wide_range_selectors = -year_selector >> -month_selector >> -week_selector >> -lit(':') | (comment >> ':');
small_range_selectors = -weekday_selector[at_c<0>(_val) = _1] >> -( lit("24/7") | time_selector[at_c<1>(_val) = _1]);
main =
(
lit(L"24/7")
| lit(L"24時間営業")
| lit(L"7/24")
| lit(L"24時間")
| charset::no_case[lit(L"daily 24/7")]
| charset::no_case[lit(L"24 hours")]
| charset::no_case[lit(L"24 horas")]
| charset::no_case[lit(L"круглосуточно")]
| charset::no_case[lit(L"24 часа")]
| charset::no_case[lit(L"24 hrs")]
| charset::no_case[lit(L"nonstop")]
| charset::no_case[lit(L"24hrs")]
| charset::no_case[lit(L"open 24 hours")]
| charset::no_case[lit(L"24 stunden")]
)[at_c<0>(at_c<2>(_val)) = State::eOpen]
| (-wide_range_selectors >> small_range_selectors[_val = _1, at_c<0>(at_c<2>(_val)) = State::eOpen])
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(small_range_selectors);
BOOST_SPIRIT_DEBUG_NODE(wide_range_selectors);
}
};
template <typename Iterator>
class time_domain : public qi::grammar<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>>
{
protected:
selectors<Iterator> selector_sequence;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, space_type> separator;
qi::rule<Iterator, space_type> base_separator;
qi::rule<Iterator, osmoh::TimeRule(), space_type> rule_sequence;
qi::rule<Iterator, osmoh::State(), space_type> rule_modifier;
qi::rule<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>> main;
public:
time_domain() : time_domain::base_type(main)
{
using qi::lit;
using qi::lexeme;
using qi::_1;
using qi::_a;
using qi::_val;
using charset::char_;
using boost::phoenix::at_c;
using qi::lazy;
using qi::eps;
using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['(' >> +(char_ - ')') >> ')'];
base_separator = lit(';') | lit("||");
separator = lit(';') | lit("||") | lit(',');
rule_modifier =
(charset::no_case[lit("open")][at_c<0>(_val) = State::eOpen] >> -comment[at_c<1>(_val) = _1])
| ((charset::no_case[lit("closed") | lit("off")])[at_c<0>(_val) = State::eClosed] >> -comment[at_c<1>(_val) = _1])
| (charset::no_case[lit("unknown")][at_c<0>(_val) = State::eUnknown] >> -comment[at_c<1>(_val) = _1])
| comment[at_c<0>(_val) = State::eUnknown, at_c<1>(_val) = _1]
;
rule_sequence = selector_sequence[_val = _1]
>> -rule_modifier[at_c<2>(_val) = _1, at_c<3>(_val) = 1];
main %= -(lit("opening_hours") >> lit('='))
>> rule_sequence[_a = phx::val(&base_separator),
phx::if_(at_c<3>(_1) || phx::size(at_c<1>(_1)))[_a = phx::val(&separator)]] % lazy(*_a);
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(rule_sequence);
BOOST_SPIRIT_DEBUG_NODE(rule_modifier);
}
};
template <typename Iterator>
bool parse_timerange(Iterator first, Iterator last, osmoh::TTimeRules & context)
{
using qi::phrase_parse;
using charset::space;
time_domain<Iterator> time_domain;
bool r = phrase_parse(
first, /* start iterator */
last, /* end iterator */
time_domain, /* the parser */
space, /* the skip-parser */
context /* result storage */
);
if (first != last) // fail if we did not get a full match
return false;
return r;
time_period tp1 = osmoh::make_time_period(d-days(1), ts);
time_period tp2 = osmoh::make_time_period(d, ts);
/* very useful in debug */
// std::cout << ts << "\t" << tp1 << "(" << p << ")" << (tp1.contains(p) ? " hit" : " miss") << std::endl;
// std::cout << ts << "\t" << tp2 << "(" << p << ")" << (tp2.contains(p) ? " hit" : " miss") << std::endl;
return tp1.contains(p) || tp2.contains(p);
}
bool check_weekday(osmoh::Weekday const & wd, boost::gregorian::date const & d)
@ -837,23 +200,8 @@ bool check_weekday(osmoh::Weekday const & wd, boost::gregorian::date const & d)
return hit;
}
bool check_timespan(osmoh::TimeSpan const &ts, boost::gregorian::date const & d, boost::posix_time::ptime const & p)
{
using boost::gregorian::days;
using boost::posix_time::ptime;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
time_period tp1 = osmoh::make_time_period(d-days(1), ts);
time_period tp2 = osmoh::make_time_period(d, ts);
/* very useful in debug */
// std::cout << ts << "\t" << tp1 << "(" << p << ")" << (tp1.contains(p) ? " hit" : " miss") << std::endl;
// std::cout << ts << "\t" << tp2 << "(" << p << ")" << (tp2.contains(p) ? " hit" : " miss") << std::endl;
return tp1.contains(p) || tp2.contains(p);
}
bool check_rule(osmoh::TimeRule const & r, std::tm const & stm, std::ostream * hitcontext = nullptr)
bool check_rule(osmoh::TimeRule const & r, std::tm const & stm,
std::ostream * hitcontext = nullptr)
{
bool next = false;
@ -896,7 +244,7 @@ OSMTimeRange OSMTimeRange::FromString(std::string const & rules)
OSMTimeRange timeRange;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; // could not work on android
std::wstring src = converter.from_bytes(rules); // rules should be wstring
timeRange.m_valid = parse_timerange(src.begin(), src.end(), timeRange.m_rules);
timeRange.m_valid = osmoh::parsing::parse_timerange(src.begin(), src.end(), timeRange.m_rules);
return timeRange;
}

View file

@ -113,9 +113,11 @@ class TimeRule
{
public:
TWeekdays weekdays;
TTimeSpans timespan;
TTimeSpans timespan; // TODO(mgsergio) rename to timespans
State state;
uint8_t int_flags = 0;
friend std::ostream & operator <<(std::ostream & s, TimeRule const & r);
};
} // namespace osmoh