-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMultiLoop.h
191 lines (167 loc) · 6.23 KB
/
MultiLoop.h
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/**
* ai-utils -- C++ Core utilities
*
* @file
* @brief Definition of class MultiLoop.
*
* @Copyright (C) 2011, 2017 Carlo Wood.
*
* pub dsa3072/C155A4EEE4E527A2 2018-08-16 Carlo Wood (CarloWood on Libera) <carlo@alinoe.com>
* fingerprint: 8020 B266 6305 EE2F D53E 6827 C155 A4EE E4E5 27A2
*
* This file is part of ai-utils.
*
* ai-utils 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 3 of the License, or
* (at your option) any later version.
*
* ai-utils 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 ai-utils. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstring>
#include <cassert>
#include <vector>
struct MultiLoopState
{
protected:
std::vector<int> M_counters;
int M_current_loop;
bool M_continued;
public:
// Uninitialized default construction. Call initialize or set_state before use.
MultiLoopState() = default;
void initialize(unsigned int n, int b)
{
M_counters.resize(n + 1);
M_current_loop = n > 0 ? 1 : 0;
M_continued = false;
M_counters[M_current_loop] = b;
}
void set_state(MultiLoopState const& initial_state)
{
*this = initial_state;
}
};
// Implements a variable number of loops inside eachother.
// Usage:
//
// // Have 23 nested for loops.
// for (MultiLoop ml(23); !ml.finished(); ml.next_loop())
// {
// // No code should go here!
// while (ml() < 3) // Each loops runs from 0 to 3 (in this case).
// {
// // Here we are at the top of loop *ml with value ml().
// // The values of (previous) loop counters are available through ml[0..*ml]
// // (ml() returns ml[*ml]).
//
// // Beginning of loop code (all loops).
// if (*ml == 7 && ml[5] == 2 && ml() == 1) // We're at the top of loop number 7 (the 8th loop),
// // the value of loop #5 is 2 and the current loop (loop 7)
// // has value 1.
// {
// if (...)
// {
// ml.breaks(0); // Normal continue (of current loop).
// break; // Return control to MultiLoop.
// }
// else if (...)
// {
// ml.breaks(1); // Normal break (of current loop).
// break; // Return control to MultiLoop.
// }
// if (...)
// {
// ml.breaks(5); // Break out of 5 loops.
// break; // Return control to MultiLoop.
// }
// }
//
// if (ml.inner_loop()) // Most inner loop.
// {
// // Inner loop body.
//
// if (...)
// {
// ml.breaks(0); // Normal continue of inner loop;
// break; // Return control to MultiLoop.
// }
// else if (...)
// //ml.breaks(1); // Allowed, but doesn't have any effect.
// break; // Normal break from inner loop.
//
// if (ml() == 1) // Value of loop *ml (inner loop here) equals 1.
// {
// ml.breaks(5); // break out of 5 loops.
// break; // Return control to MultiLoop.
// }
//
// // End of inner loop.
// }
// // Loop start values.
// ml.start_next_loop_at(ml()); // This causes each loop to begin at with the value of the previous loop.
// }
//
// if (int loop = ml.end_of_loop(); loop >= 0)
// {
// // End of loop code for loop 'loop'.
// }
// }
class MultiLoop : public MultiLoopState
{
public:
// Uninitialized MultiLoop object.
MultiLoop() = default;
// Construct a MultiLoop of n loops.
explicit MultiLoop(unsigned int n, int b = 0) { initialize(n, b); }
// Destructor.
~MultiLoop() = default;
// Accessor for the internal state of the MultiLoop.
MultiLoopState const& state() const { return *this; }
// (Re)initialize MultiLoop with internal state.
MultiLoop& operator=(MultiLoopState const& internal_state) { set_state(internal_state); return *this; }
// Return the current loop number (0 ... n-1).
unsigned int operator*() const { return M_current_loop - 1; }
// Return the value of counter number i.
int operator[](unsigned int i) const { assert((int)i < M_current_loop); return M_counters[i + 1]; }
// Return a reference to counter number i.
int& operator[](unsigned int i) { assert((int)i < M_current_loop); return M_counters[i + 1]; }
// Return the value of the counter for the n-th previous loop.
int operator()(unsigned int n = 0) const { assert((int)n < M_current_loop); return M_counters[M_current_loop - n]; }
// Set the loop counter to value n.
void operator=(int n) { M_counters[M_current_loop] = n; }
// Advance the counters. Start the next loop with value b.
void start_next_loop_at(int b);
// Break out of the current loop and increment previous loop.
void next_loop() { ++M_counters[--M_current_loop]; M_continued = false; }
// On the next call to start_next_loop_at(), break out of n loops.
// A value of n == 0 means a `continue` of the current loop.
void breaks(int n) { M_continued = !n; M_current_loop -= (n - 1); assert(M_current_loop > 0); }
// Return true when all loops are finished.
bool finished() const { return M_current_loop == 0; }
// Return true when we are in the inner loop.
bool inner_loop() const { return M_current_loop == (int)M_counters.size() - 1; }
// Return true when we're at the end of a loop (but not the inner loop).
int end_of_loop() const { return M_continued ? -1 : M_current_loop - 2; }
};
inline void MultiLoop::start_next_loop_at(int b)
{
// If we are not in the inner loop, start a next loop.
if (M_current_loop < (int)M_counters.size() - 1)
{
++M_current_loop;
M_counters[M_current_loop] = b;
}
else
{
// Increment current loop.
++M_counters[M_current_loop];
}
}