labelRanges.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011 OpenFOAM Foundation
9  Copyright (C) 2017-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "labelRanges.H"
30 #include <numeric>
31 
32 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 
37 // Print range for debugging purposes
38 static Ostream& printRange(Ostream& os, const labelRange& range)
39 {
40  if (range.empty())
41  {
42  os << "empty";
43  }
44  else
45  {
46  os << range << " = " << range.min() << ':' << range.max();
47  }
48  return os;
49 }
50 
51 } // End namespace Foam
52 
53 
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 
56 void Foam::labelRanges::insertBefore
57 (
58  const label insert,
59  const labelRange& range
60 )
61 {
62  auto& list = ranges_;
63 
64  // Insert via copying up
65  label nElem = list.size();
66 
68  {
69  Info<< "before insert "
70  << nElem << " elements, insert at " << insert << nl
71  << list << endl;
72  }
73 
74  list.resize(nElem+1);
75 
77  {
78  Info<< "copy between " << nElem << " and " << insert << nl;
79  }
80 
81  for (label i = nElem-1; i >= insert; --i)
82  {
84  {
85  Info<< "copy from " << (i) << " to " << (i+1) << nl;
86  }
87 
88  list[i+1] = list[i];
89  }
90 
91  // Finally insert the range
93  {
94  Info<< "finally insert the range at " << insert << nl;
95  }
96 
97  list[insert] = range;
98 }
99 
100 
101 void Foam::labelRanges::purgeEmpty()
102 {
103  auto& list = ranges_;
104 
105  // Purge empty ranges by copying down
106  label nElem = 0;
107 
108  forAll(list, elemi)
109  {
110  if (!list[elemi].empty())
111  {
112  if (nElem != elemi)
113  {
114  list[nElem] = list[elemi];
115  }
116  ++nElem;
117  }
118  }
119 
120  // Truncate
121  list.resize(nElem);
122 }
123 
124 
125 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
126 
128 {
129  is >> *this;
130 }
131 
132 
133 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
134 
136 {
137  auto& list = ranges_;
138 
139  if (range.empty())
140  {
141  return false;
142  }
143  else if (list.empty())
144  {
145  list.push_back(range);
146  return true;
147  }
148 
149  // Find the correct place for insertion
150  forAll(list, elemi)
151  {
152  labelRange& currRange = list[elemi];
153 
154  if (currRange.overlaps(range, true))
155  {
156  // absorb into the existing (adjacent/overlapping) range
157  currRange.join(range);
158 
159  // Might connect with the next following range(s)
160  for (; elemi < list.size()-1; ++elemi)
161  {
162  labelRange& nextRange = list[elemi+1];
163  if (currRange.overlaps(nextRange, true))
164  {
165  currRange.join(nextRange);
166  nextRange.reset();
167  }
168  else
169  {
170  break;
171  }
172  }
173 
174  // Done - remove any empty ranges that might have been created
175  purgeEmpty();
176  return true;
177  break;
178  }
179  else if (range < currRange)
180  {
181  insertBefore(elemi, range);
182  return true;
183  break;
184  }
185  }
186 
187 
188  // not found: simply append
189  list.push_back(range);
190 
191  return true;
192 }
193 
194 
196 {
197  auto& list = ranges_;
198  bool status = false;
199 
200  if (range.empty() || list.empty())
201  {
202  return status;
203  }
204 
205  forAll(list, elemi)
206  {
207  labelRange& currRange = list[elemi];
208 
209  if (range.min() > currRange.min())
210  {
211  if (range.max() < currRange.max())
212  {
213  // Removal of range fragments of currRange
214 
215  if (labelRange::debug)
216  {
217  Info<< "Fragment removal ";
218  printRange(Info, range) << " from ";
219  printRange(Info, currRange) << endl;
220  }
221 
222  // left-hand-side fragment: insert before current range
223  label lower = currRange.min();
224  label upper = range.min() - 1;
225 
226  labelRange fragment(lower, upper - lower + 1);
227 
228  // right-hand-side fragment
229  lower = range.max() + 1;
230  upper = currRange.max();
231 
232  currRange.reset(lower, upper - lower + 1);
233  currRange.clampSize();
234  status = true;
235  insertBefore(elemi, fragment);
236 
237  if (labelRange::debug)
238  {
239  Info<< "fragment ";
240  printRange(Info, fragment) << endl;
241  Info<< "yields ";
242  printRange(Info, currRange) << endl;
243  }
244 
245  // fragmentation can only affect a single range
246  // thus we are done
247  break;
248  }
249  else if (range.min() <= currRange.max())
250  {
251  // keep left-hand-side, remove right-hand-side
252 
253  if (labelRange::debug)
254  {
255  Info<< "RHS removal ";
256  printRange(Info, range) << " from ";
257  printRange(Info, currRange) << endl;
258  }
259 
260  const label lower = currRange.min();
261  const label upper = range.min() - 1;
262 
263  currRange.reset(lower, upper - lower + 1);
264  currRange.clampSize();
265  status = true;
266 
267  if (labelRange::debug)
268  {
269  Info<< "yields ";
270  printRange(Info, currRange) << endl;
271  }
272  }
273  }
274  else if (range.min() <= currRange.min())
275  {
276  if (range.max() >= currRange.min())
277  {
278  // remove left-hand-side, keep right-hand-side
279 
280  if (labelRange::debug)
281  {
282  Info<< "LHS removal ";
283  printRange(Info, range) << " from ";
284  printRange(Info, currRange) << endl;
285  }
286 
287  const label lower = range.max() + 1;
288  const label upper = currRange.max();
289 
290  currRange.reset(lower, upper - lower + 1);
291  currRange.clampSize();
292  status = true;
293 
294  if (labelRange::debug)
295  {
296  Info<< "yields ";
297  printRange(Info, currRange) << endl;
298  }
299  }
300  }
301  }
303  purgeEmpty();
304 
305  return status;
306 }
307 
308 
310 {
311  label total = 0;
312  for (const labelRange& range : ranges_)
313  {
314  if (range.size() > 0) // Ignore negative size (paranoid)
315  {
316  total += range.size();
317  }
318  }
319 
320  if (!total)
321  {
322  // Skip this check?
323  return List<label>();
324  }
325 
326  List<label> result(total);
327 
328  auto* iter = result.begin();
329 
330  for (const labelRange& range : ranges_)
331  {
332  const label len = range.size();
333 
334  if (len > 0) // Ignore negative size (paranoid)
335  {
336  std::iota(iter, (iter + len), range.start());
337  iter += len;
338  }
339  }
341  return result;
342 }
343 
344 
345 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
346 
347 Foam::label Foam::labelRanges::operator[](const label i) const
348 {
349  if (i < 0) return -1;
350 
351  label subIdx = i;
352 
353  for (const labelRange& range : ranges_)
354  {
355  if (subIdx < range.size())
356  {
357  return (range.start() + subIdx);
358  }
359  else
360  {
361  subIdx -= range.size();
362  }
363  }
365  return -1; // Not found
366 }
367 
368 
369 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
370 
372 {
373  return ranges_.readList(is);
374 }
375 
376 
378 (
379  Ostream& os,
380  const label shortLen
381 ) const
382 {
383  return ranges_.writeList(os, shortLen);
384 }
385 
388 {
389  return list.readList(is);
390 }
391 
392 
393 Foam::Ostream& Foam::operator<<(Ostream& os, const labelRanges& list)
394 {
395  return list.writeList
396  (
397  os,
398  Detail::ListPolicy::short_length<labelRange>::value
399  );
400 }
401 
402 
403 // ************************************************************************* //
labelRanges()=default
Default construct.
label operator[](const label i) const
Return the value at linear index &#39;i&#39;, -1 for out-of-range.
Definition: labelRanges.C:340
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
srcOptions insert("case", fileName(rootDirSource/caseDirSource))
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1187
Istream & readList(Istream &is)
Read List of labelRange from Istream, discarding contents.
Definition: labelRanges.C:364
static int debug
Debugging.
Definition: labelRange.H:76
scalar range
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
bool add(const labelRange &range)
Add the range to the list.
Definition: labelRanges.C:128
Istream & operator>>(Istream &, directionInfo &)
List< label > labels() const
Return flattened list of all range labels.
Definition: labelRanges.C:302
bool remove(const labelRange &range)
Remove the range from the list.
Definition: labelRanges.C:188
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
static Ostream & printRange(Ostream &os, const labelRange &range)
Definition: labelRanges.C:31
OBJstream os(runTime.globalPath()/outputName)
Ostream & operator<<(Ostream &, const boundaryPatch &p)
Write boundaryPatch as dictionary entries (without surrounding braces)
Definition: boundaryPatch.C:77
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1171
messageStream Info
Information stream (stdout output on master, null elsewhere)
A list of labelRange with constrained list capabilities.
Definition: labelRanges.H:54
Ostream & writeList(Ostream &os, const label shortLen=0) const
Write List of labelRange, with line-breaks in ASCII when length exceeds shortLen. ...
Definition: labelRanges.C:371
Namespace for OpenFOAM.