Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Libraries
KOpeningHours
Commits
b4cbddb8
Commit
b4cbddb8
authored
Jan 01, 2022
by
David Faure
Browse files
Turn nthMask into a vector of entries, to preserve intervals and ordering
BUG: 445963
parent
9818afb3
Pipeline
#117379
passed with stage
in 1 minute and 10 seconds
Changes
7
Pipelines
3
Hide whitespace changes
Inline
Side-by-side
autotests/parsertest.cpp
View file @
b4cbddb8
...
...
@@ -95,6 +95,12 @@ private Q_SLOTS:
T
(
"Mar Su[1]-Oct Su[1]: 11:00-20:00; PH 11:00-20:00"
);
T2
(
"Mo 20:00-26:00"
,
"Mo 20:00-26:00"
);
// https://github.com/osm-fr/osmose-backend/issues/1344
// https://bugs.kde.org/show_bug.cgi?id=445963
T
(
"Th[1-2] 09:30-11:45"
);
T
(
"Th[1,2] 09:30-11:45"
);
T
(
"Mo[1,3,-1]"
);
// order as desired, -1 means last
T
(
"Mo[1,3,2]"
);
// currently not normalized
// from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Simple_examples
T
(
"Mo-Fr 08:00-17:30"
);
T
(
"Mo-Fr 08:00-12:00,13:00-17:30"
);
...
...
src/lib/consecutiveaccumulator_p.h
deleted
100644 → 0
View file @
9818afb3
/*
SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KOPENINGHOURS_CONSECUTIVEACCUMULATOR_P_H
#define KOPENINGHOURS_CONSECUTIVEACCUMULATOR_P_H
#include <functional>
#include <QByteArray>
// Input: 1,2,4,5,6,9
// Output: 1-2,4-6,9
class
ConsecutiveAccumulator
{
public:
// The std::function is usually QByteArray::number
// but it could be also 1->Mo, 2->Tu etc. if we need that one day.
explicit
ConsecutiveAccumulator
(
std
::
function
<
QByteArray
(
int
)
>
&&
f
)
:
func
(
std
::
move
(
f
))
{}
void
add
(
int
value
)
{
if
(
!
first
&&
value
==
cur
+
1
)
{
++
cur
;
}
else
{
flush
();
cur
=
value
;
start
=
value
;
first
=
false
;
}
}
QByteArray
result
()
{
// Finalize
flush
();
if
(
!
expr
.
isEmpty
())
{
expr
.
chop
(
1
);
}
return
expr
;
}
private:
void
flush
()
{
if
(
!
first
)
{
if
(
start
<
cur
)
{
if
(
cur
>=
0
)
{
expr
+=
func
(
start
)
+
'-'
+
func
(
cur
)
+
','
;
}
else
{
// don't generate -2--1
for
(
int
i
=
start
;
i
<=
cur
;
++
i
)
{
expr
+=
func
(
i
)
+
','
;
}
}
}
else
{
expr
+=
func
(
cur
)
+
','
;
}
}
}
bool
first
=
true
;
int
cur
=
0
;
int
start
=
0
;
QByteArray
expr
;
std
::
function
<
QByteArray
(
int
)
>
func
;
};
#endif
src/lib/evaluator.cpp
View file @
b4cbddb8
...
...
@@ -135,24 +135,27 @@ SelectorResult WeekdayRange::nextIntervalLocal(const Interval &interval, const Q
switch
(
holiday
)
{
case
NoHoliday
:
{
if
(
nthMask
>
0
)
{
for
(
int
i
=
1
;
i
<=
10
;
++
i
)
{
if
((
nthMask
&
(
1
<<
i
))
==
0
)
{
continue
;
if
(
nthSequence
)
{
qint64
smallestOffset
=
INT_MAX
;
for
(
const
NthEntry
&
entry
:
nthSequence
->
sequence
)
{
Q_ASSERT
(
entry
.
begin
<=
entry
.
end
);
for
(
int
n
=
entry
.
begin
;
n
<=
entry
.
end
;
++
n
)
{
const
auto
d
=
nthWeekdayInMonth
(
dt
.
date
().
addDays
(
-
offset
),
beginDay
,
n
);
if
(
!
d
.
isValid
()
||
d
.
addDays
(
offset
)
<
dt
.
date
())
{
continue
;
}
if
(
d
.
addDays
(
offset
)
==
dt
.
date
())
{
auto
i
=
interval
;
i
.
setBegin
(
QDateTime
(
d
.
addDays
(
offset
),
{
0
,
0
}));
i
.
setEnd
(
QDateTime
(
d
.
addDays
(
offset
+
1
),
{
0
,
0
}));
return
i
;
}
// d > dt.date()
smallestOffset
=
qMin
(
smallestOffset
,
dt
.
secsTo
(
QDateTime
(
d
.
addDays
(
offset
),
{
0
,
0
})));
}
const
auto
n
=
(
i
%
2
)
?
(
-
5
+
(
i
/
2
))
:
(
i
/
2
);
const
auto
d
=
nthWeekdayInMonth
(
dt
.
date
().
addDays
(
-
offset
),
beginDay
,
n
);
if
(
!
d
.
isValid
()
||
d
.
addDays
(
offset
)
<
dt
.
date
())
{
continue
;
}
if
(
d
.
addDays
(
offset
)
==
dt
.
date
())
{
auto
i
=
interval
;
i
.
setBegin
(
QDateTime
(
d
.
addDays
(
offset
),
{
0
,
0
}));
i
.
setEnd
(
QDateTime
(
d
.
addDays
(
offset
+
1
),
{
0
,
0
}));
return
i
;
}
// d > dt.date()
return
dt
.
secsTo
(
QDateTime
(
d
.
addDays
(
offset
),
{
0
,
0
}));
}
if
(
smallestOffset
<
INT_MAX
)
{
return
smallestOffset
;
}
// skip to next month
...
...
src/lib/openinghours.cpp
View file @
b4cbddb8
...
...
@@ -12,7 +12,6 @@
#include "interval.h"
#include "rule_p.h"
#include "logging.h"
#include "consecutiveaccumulator_p.h"
#include <QDateTime>
#include <QJsonArray>
...
...
src/lib/openinghoursparser.y
View file @
b4cbddb8
...
...
@@ -5,8 +5,8 @@
*/
#include "openinghours_p.h"
#include "openinghoursparser_p.h"
#include "openinghoursscanner_p.h"
#include "openinghoursparser_p.h"
// generated
#include "openinghoursscanner_p.h"
// generated
#include "logging.h"
using namespace KOpeningHours;
...
...
@@ -113,6 +113,8 @@ typedef void* yyscan_t;
Time time;
Selectors selectors;
Timespan *timespan;
NthEntry nthEntry;
NthSequence *nthSequence;
WeekdayRange *weekdayRange;
Week *week;
Date date;
...
...
@@ -189,8 +191,8 @@ typedef void* yyscan_t;
%type <weekdayRange> WeekdayRange
%type <weekdayRange> HolidaySequence
%type <weekdayRange> Holiday
%type <n
um
> NthSequence
%type <n
um
> NthEntry
%type <n
thSequence
> NthSequence
%type <n
thEntry
> NthEntry
%type <num> DayOffset
%type <dateOffset> DateOffset
%type <week> Week
...
...
@@ -212,6 +214,7 @@ typedef void* yyscan_t;
delete $$.yearSelector;
} <selectors>
%destructor { delete $$; } <timespan>
%destructor { delete $$; } <nthSequence>
%destructor { delete $$; } <weekdayRange>
%destructor { delete $$; } <week>
%destructor { delete $$; } <monthdayRange>
...
...
@@ -502,12 +505,12 @@ WeekdayRange:
| T_WEEKDAY[D] T_LBRACKET NthSequence[N] T_RBRACKET {
$$ = new WeekdayRange;
$$->beginDay = $$->endDay = $D;
$$->nth
Mask =
$N;
$$->nth
Sequence.reset(
$N
)
;
}
| T_WEEKDAY[D] T_LBRACKET NthSequence[N] T_RBRACKET DayOffset[O] {
$$ = new WeekdayRange;
$$->beginDay = $$->endDay = $D;
$$->nth
Mask =
$N;
$$->nth
Sequence.reset(
$N
)
;
$$->offset = $O;
}
;
...
...
@@ -534,24 +537,27 @@ Holiday:
;
NthSequence:
NthEntry[N] { $$ = $N; }
| NthSequence[N1] T_COMMA NthEntry[N2] { $$ = $N1 | $N2; }
NthEntry[N] {
$$ = new NthSequence;
$$->add($N);
}
| NthSequence[N1] T_COMMA NthEntry[N2] {
$N1->add($N2);
$$ = $N1;
}
NthEntry:
T_INTEGER[N] {
if ($N < 1 || $N > 5) { YYABORT; }
$$ =
(1 << (2 * $N))
;
$$ =
{$N,$N}
;
}
| T_INTEGER[N1] T_MINUS T_INTEGER[N2] {
if ($N1 < 1 || $N1 > 5 || $N2 < 1 || $N2 > 5 || $N2 <= $N1) { YYABORT; }
$$ = 0;
for (int i = $N1; i <= $N2; ++i) {
$$ |= (1 << (2 * i));
}
$$ = {$N1,$N2};
}
| T_MINUS T_INTEGER[N] {
if ($N < 1 || $N > 5) { YYABORT; }
$$ =
(1 << ((2 * (6 - $N)) - 1))
;
$$ =
{-$N,-$N}
;
}
;
...
...
src/lib/selectors.cpp
View file @
b4cbddb8
...
...
@@ -7,7 +7,6 @@
#include "selectors_p.h"
#include "logging.h"
#include "openinghours_p.h"
#include "consecutiveaccumulator_p.h"
#include <cstdlib>
#include <cassert>
...
...
@@ -153,13 +152,13 @@ bool Timespan::operator==(Timespan &other) const
int
WeekdayRange
::
requiredCapabilities
()
const
{
// only ranges or nth
Mask
are allowed, not both at the same time, enforced by parser
assert
(
beginDay
==
endDay
||
nth
Mask
==
0
);
// only ranges or nth
Sequence
are allowed, not both at the same time, enforced by parser
assert
(
beginDay
==
endDay
||
!
nth
Sequence
);
int
c
=
Capability
::
None
;
switch
(
holiday
)
{
case
NoHoliday
:
if
((
offset
>
0
&&
nth
Mask
==
0
))
{
if
((
offset
>
0
&&
!
nth
Sequence
))
{
c
|=
Capability
::
NotImplemented
;
}
break
;
...
...
@@ -201,21 +200,8 @@ QByteArray WeekdayRange::toExpression() const
expr
=
"SH"
;
break
;
}
if
(
nthMask
>
0
)
{
ConsecutiveAccumulator
accu
([](
int
i
)
{
return
QByteArray
::
number
(
i
);
});
// Negative numbers
for
(
int
i
=
1
;
i
<=
10
;
i
+=
2
)
{
if
((
nthMask
&
(
1
<<
i
))
!=
0
)
{
accu
.
add
(
-
5
+
(
i
/
2
));
}
}
// Positive numbers
for
(
int
i
=
2
;
i
<=
10
;
i
+=
2
)
{
if
((
nthMask
&
(
1
<<
i
))
!=
0
)
{
accu
.
add
(
i
/
2
);
}
}
expr
+=
'['
+
accu
.
result
()
+
']'
;
if
(
nthSequence
)
{
expr
+=
'['
+
nthSequence
->
toExpression
()
+
']'
;
}
if
(
offset
>
0
)
{
expr
+=
" +"
+
QByteArray
::
number
(
offset
)
+
' '
+
(
offset
>
1
?
"days"
:
"day"
);
...
...
@@ -237,7 +223,7 @@ void WeekdayRange::simplify()
std
::
fill
(
std
::
begin
(
seenDays
),
std
::
end
(
seenDays
),
false
);
for
(
WeekdayRange
*
selector
=
this
;
selector
;
selector
=
selector
->
next
.
get
())
{
// Ensure it's all just week days, no other features
if
(
selector
->
nth
Mask
||
selector
->
lhsAndSelector
||
selector
->
holiday
!=
NoHoliday
||
selector
->
offset
)
{
if
(
selector
->
nth
Sequence
||
selector
->
lhsAndSelector
||
selector
->
holiday
!=
NoHoliday
||
selector
->
offset
)
{
return
;
}
const
bool
wrap
=
selector
->
beginDay
>
selector
->
endDay
;
...
...
@@ -495,3 +481,26 @@ QByteArray YearRange::toExpression() const
}
return
expr
;
}
void
NthSequence
::
add
(
NthEntry
range
)
{
sequence
.
push_back
(
std
::
move
(
range
));
}
QByteArray
NthSequence
::
toExpression
()
const
{
QByteArray
ret
;
for
(
const
NthEntry
&
entry
:
sequence
)
{
if
(
!
ret
.
isEmpty
())
ret
+=
','
;
ret
+=
entry
.
toExpression
();
}
return
ret
;
}
QByteArray
NthEntry
::
toExpression
()
const
{
if
(
begin
==
end
)
return
QByteArray
::
number
(
begin
);
return
QByteArray
::
number
(
begin
)
+
'-'
+
QByteArray
::
number
(
end
);
}
src/lib/selectors_p.h
View file @
b4cbddb8
...
...
@@ -135,6 +135,21 @@ public:
std
::
unique_ptr
<
Timespan
>
next
;
};
struct
NthEntry
{
int
begin
;
int
end
;
QByteArray
toExpression
()
const
;
};
/** Nth week days, like 1-2,4,6-8 */
class
NthSequence
{
public:
void
add
(
NthEntry
range
);
QByteArray
toExpression
()
const
;
std
::
vector
<
NthEntry
>
sequence
;
};
/** Weekday range. */
class
WeekdayRange
{
...
...
@@ -147,7 +162,7 @@ public:
uint8_t
beginDay
=
0
;
// Mo=1, Tu=2, ..., Su=7
uint8_t
endDay
=
0
;
uint16_t
nthMask
=
0
;
std
::
unique_ptr
<
NthSequence
>
nthSequence
;
int16_t
offset
=
0
;
enum
Holiday
:
uint8_t
{
NoHoliday
=
0
,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment