Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
parse-int-range.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Parse a string containing number ranges.
4 *
5 * Authors:
6 * Martin Owens
7 * PBS <pbs3141@gmail.com>
8 *
9 * Copyright (C) 2024 Authors
10 *
11 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12 */
13
14#include "parse-int-range.h"
15
16#include <cassert>
17#include <charconv>
18
19#include <glibmm/regex.h>
20
21namespace Inkscape {
22namespace {
23
25std::string_view fetch(Glib::MatchInfo &m, int i)
26{
27 int a, b;
28 if (!m.fetch_pos(i, a, b)) {
29 return {}; // error
30 }
31 if (a == -1) {
32 return {}; // no match
33 }
34 auto const str = g_match_info_get_string(m.gobj());
35 return {str + a, static_cast<size_t>(b - a)};
36};
37
39template <typename T>
40T from_chars(std::string_view const &v)
41{
42 T result = 0;
43 std::from_chars(v.begin(), v.end(), result);
44 return result;
45};
46
47} // namespace
48
49std::set<unsigned> parseIntRange(std::string const &input, unsigned start, unsigned end)
50{
51 // Special word based translations go here:
52 if (input == "all") {
53 return parseIntRange("-", start, end);
54 }
55
56 auto valid = [&] (unsigned val) {
57 return start <= val && (!end || val <= end);
58 };
59
60 auto clamp_to_valid = [&] (unsigned val) {
61 val = std::max(val, start);
62 if (end) {
63 val = std::min(val, end);
64 }
65 return val;
66 };
67
68 std::set<unsigned> out;
69
70 auto add = [&] (unsigned val) {
71 out.insert(val);
72 };
73
74 auto add_if_valid = [&] (unsigned val) {
75 if (valid(val)) {
76 add(val);
77 }
78 };
79
80 static auto const regex = Glib::Regex::create("\\s*(((\\d*)\\s*-\\s*(\\d*))|(\\d+))\\s*,?", Glib::Regex::CompileFlags::OPTIMIZE | Glib::Regex::CompileFlags::ANCHORED);
81
82 auto pos = input.data();
83 Glib::MatchInfo m;
84
85 while (regex->match(pos, m)) {
86 if (auto const single = fetch(m, 5); !single.empty()) {
87 add_if_valid(from_chars<unsigned>(single));
88 } else if (auto const range = fetch(m, 2); !range.empty()) {
89 auto const first = fetch(m, 3);
90 auto const last = fetch(m, 4);
91 auto const first_num = first.empty() ? start : from_chars<unsigned>(first);
92 auto const last_num = last.empty() ? (end ? end : first_num) : from_chars<unsigned>(last);
93 auto const min = clamp_to_valid(std::min(first_num, last_num));
94 auto const max = clamp_to_valid(std::max(first_num, last_num));
95 for (auto i = min; i <= max; i++) {
96 add(i);
97 }
98 } else {
99 assert(false); // both groups above cannot be empty
100 break;
101 }
102 pos = fetch(m, 0).end();
103 }
104
105 return out;
106}
107
108} // namespace Inkscape
109
110/*
111 Local Variables:
112 mode:c++
113 c-file-style:"stroustrup"
114 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
115 indent-tabs-mode:nil
116 fill-column:99
117 End:
118*/
119// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Css & result
Geom::Point start
Geom::Point end
size_t v
Helper class to stream background task notifications as a series of messages.
std::set< unsigned > parseIntRange(std::string const &input, unsigned start, unsigned end)
Parse integer ranges out of a string.