1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
/***************************************************************************
* Copyright (C) 2017-2018 by Hans-Peter Deifel *
* hpd@hpdeifel.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA. *
***************************************************************************/
#include "intervals.h"
#include <algorithm>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include "output.h"
// The interval container data structure could be much more sophisticated (e.g
// by using interval trees or even sorted lists), but as the number of intervals
// in typical use cases is small, this shouldn't make much difference and could
// actually be harmful.
//
// tl;dr Measure before you optimize
void IntervalContainer::addInterval(Interval i) {
intervals.push_back(i);
}
bool IntervalContainer::contains(int element) const {
// We interpret the empty container as one interval containing
// everything. This makes sense in the pdfgrep case: If the user doesn't
// restrict the intervals she want's all pages to be searched.
if (intervals.empty())
return true;
auto predicate = [=](const Interval &a) {return a.contains(element);};
return std::find_if(intervals.begin(), intervals.end(), predicate)
!= intervals.end();
}
static Interval parse_interval(const std::string str) {
size_t minus = str.find("-");
int from, to;
try {
// only one int, not a range
if (minus == std::string::npos) {
from = to = std::stoi(str);
} else {
auto from_str = str.substr(0, minus);
auto to_str = str.substr(minus+1, str.length()-minus);
from = std::stoi(from_str);
to = std::stoi(to_str);
}
} catch (std::invalid_argument e) {
err() << "Invalid page range \"" << str << "\". "
<< "Expected a single page or a range PAGE1-PAGE2." << std::endl;
exit(EXIT_ERROR);
}
if (from <= 0 || to <= 0) {
err() << "Invalid page range \"" << str << "\". "
<< "Page numbers must be positive." << std::endl;
exit(EXIT_ERROR);
}
if (to < from) {
err() << "warning: Page range is empty: " << str << std::endl;
}
return Interval(from, to);
}
IntervalContainer IntervalContainer::fromString(const std::string str) {
IntervalContainer c;
std::stringstream tokens(str);
std::string interval;
while (std::getline(tokens, interval, ',')) {
c.addInterval(parse_interval(interval));
}
return c;
}
|