OpenDDS  Snapshot(2023/04/28-20:55)
DisjointSequence.h
Go to the documentation of this file.
1 /*
2  * Distributed under the OpenDDS License.
3  * See: http://www.opendds.org/license.html
4  */
5 
6 #ifndef OPENDDS_DCPS_DISJOINTSEQUENCE_H
7 #define OPENDDS_DCPS_DISJOINTSEQUENCE_H
8 
9 #include "dcps_export.h"
10 #include "Definitions.h"
11 #include "SequenceNumber.h"
12 #include "PoolAllocator.h"
13 
15 
16 namespace OpenDDS {
17 namespace DCPS {
18 
19 /// Data structure for a set of SequenceNumbers.
20 /// Sequence numbers can be inserted as single numbers, ranges,
21 /// or RTPS-style bitmaps. The DisjointSequence can then be queried for
22 /// contiguous ranges and internal gaps.
24 public:
25 
27  void reset();
28 
29  bool empty() const;
30 
31  /// Lowest SequenceNumber in the set.
32  /// Precondition: !empty()
33  SequenceNumber low() const;
34 
35  /// Highest SequenceNumber in the set.
36  /// Precondition: !empty()
37  SequenceNumber high() const;
38 
39  /// Gets the high end of the lowest contiguous range.
40  /// Named after the use case of tracking received messages (which may be
41  /// received out-of-order) and then determining the largest value that the
42  /// receiver is allowed to acknowledge (under a cumulative-acking protocol).
43  /// If empty(), returns SEQUENCENUMBER_UNKNOWN.
44  SequenceNumber cumulative_ack() const;
45 
46  /// Gets the low end of the highest contiguous range, may be thought of as
47  /// the inverse of cumulative_ack().
48  /// If empty(), returns SEQUENCENUMBER_UNKNOWN.
49  SequenceNumber last_ack() const;
50 
51  /// Objects with the disjoint() property have an internal gap in the inserted
52  /// SequenceNumbers.
53  bool disjoint() const;
54 
55  bool contains(SequenceNumber value) const;
56 
57  bool contains_any(const SequenceRange& range) const;
58 
59  /// All insert() methods return true upon modifying the set and false if
60  /// the set already contained the SequenceNumber(s) that were to be inserted.
61  /// This is the general form of insert() whereby the caller receives a list of
62  /// sub-ranges of 'range' that were not already in the DisjointSequence.
63  /// For example, given a DisjointSequence 'seq' containing (1, 2, 5, 9),
64  /// calling seq.insert(SequenceRange(4, 12), v) returns true
65  /// and yields v = [(4, 4), (6, 8), (10, 12)] and seq = (1, 2, 4, ..., 12).
66  bool insert(const SequenceRange& range, OPENDDS_VECTOR(SequenceRange)& added);
67 
68  /// Insert all numbers between range.first and range.second (both inclusive).
69  bool insert(const SequenceRange& range);
70 
71  /// Shorthand for "insert(SequenceRange(value, value))"
72  bool insert(SequenceNumber value);
73 
74  void erase(SequenceNumber value);
75 
76  /// Insert using the RTPS compact representation of a set. The three
77  /// parameters, taken together, describe a set with each 1 bit starting
78  /// at the msb of bits[0] and extending through num_bits (which are located at
79  /// the next least significant bits of bits[0] followed by the msb of bits[1],
80  /// etc.) indicating presence of the number (value + bit_index) in the set.
81  /// bit_index is 0-based.
82  /// Precondition: the array 'bits' has at least ceil(num_bits / 32) entries.
83  bool insert(SequenceNumber value,
84  ACE_CDR::ULong num_bits,
85  const ACE_CDR::Long bits[]);
86 
87  /// Insert the intersection of range and filter
88  bool insert_filtered(const SequenceRange& range, const DisjointSequence& filter);
89 
90  /// Inverse of insert(value, num_bits, bits). Populates array of
91  /// bitmap[length] with the bitmap of ranges above the cumulative_ack() value.
92  /// Sets the number of significant (used) bits in num_bits. The 'base' of the
93  /// bitmap is one larger than cumulative_ack(). Returns true if the entire
94  /// DisjointSequence was able to fit in bitmap[]. Returning false is not an
95  /// error, it's just that the higher-valued ranges didn't fit. If invert is
96  /// true, the 1's in the bitmap represent the missing_sequence_ranges()
97  /// instead of the present_sequence_ranges().
98  /// Precondition: the array 'bits' has 'length' entries allocated.
99  bool to_bitmap(ACE_CDR::Long bitmap[],
100  ACE_CDR::ULong length,
101  ACE_CDR::ULong& num_bits,
102  ACE_CDR::ULong& cumulative_bits_added,
103  bool invert = false) const;
104 
105  /// Returns missing ranges of SequenceNumbers (internal gaps in the sequence)
106  OPENDDS_VECTOR(SequenceRange) missing_sequence_ranges() const;
107 
108  /// Returns a representation of the members of the sequence as a list of
109  /// contiguous ranges (each Range is inclusive on both sides).
110  OPENDDS_VECTOR(SequenceRange) present_sequence_ranges() const;
111 
112  void dump() const;
113 
114  /// Core data structure of DisjointSequence:
115  /// Use a balanced binary tree (std::set) to store a list of ranges (std::pair of T).
116  /// Maintain invariants (in addition to those from std::set):
117  /// - For any element x of the set, x.second >= x.first
118  /// - No adjacent or overlapping ranges. Given two elements ordered "x before y", y.first > x.second + 1
119  /// Common non-mutating operations on the underlying set are public members of this class.
120  /// Note that due to this design, size() is the number of contiguous ranges, not individual values.
121  /// Some mutating operations on the underlying set that can't violate the invariants are also provided (like clear).
122  /// Type T needs to support value-initialization, construction from int, copying,
123  /// addition, subtraction, and comparison using == and <.
124  template <typename T>
126  public:
127  typedef std::pair<T, T> TPair;
128  typedef bool (*Compare)(const TPair&, const TPair&);
129  typedef OPENDDS_SET_CMP(TPair, Compare) Container;
130  typedef typename Container::size_type size_type;
131  typedef typename Container::const_iterator const_iterator;
132  typedef const_iterator iterator;
133  typedef typename Container::const_reverse_iterator const_reverse_iterator;
134  typedef const_reverse_iterator reverse_iterator;
135 
136  static bool range_less(const TPair& lhs, const TPair& rhs)
137  {
138  return lhs.second < rhs.second;
139  }
140 
142  : ranges_(range_less)
143  {}
144 
145  const_iterator begin() const { return ranges_.begin(); }
146  const_iterator cbegin() const { return ranges_.begin(); }
147 
148  const_iterator end() const { return ranges_.end(); }
149  const_iterator cend() const { return ranges_.end(); }
150 
151  const_reverse_iterator rbegin() const { return ranges_.rbegin(); }
152  const_reverse_iterator crbegin() const { return ranges_.rbegin(); }
153 
154  const_reverse_iterator rend() const { return ranges_.rend(); }
155  const_reverse_iterator crend() const { return ranges_.rend(); }
156 
157  bool empty() const { return ranges_.empty(); }
158  size_type size() const { return ranges_.size(); }
159  void clear() { ranges_.clear(); }
160 
161  void add(T lower, T upper)
162  {
163  OPENDDS_ASSERT(upper >= lower);
164  if (has(lower, upper)) {
165  return;
166  }
167 
168  const T above = upper + 1;
169  for (typename Container::iterator i = lower_bound_i(lower - 1);
170  i != ranges_.end() && (i->first <= above || i->second <= above);
171  /* iterate in loop because of removal */) {
172  lower = (std::min)(lower, i->first);
173  upper = (std::max)(upper, i->second);
174  ranges_.erase(i++);
175  }
176 
177  ranges_.insert(TPair(lower, upper));
178  }
179 
180  void add(T value)
181  {
182  add(value, value);
183  }
184 
185  void remove(T value)
186  {
187  const typename Container::iterator iter = lower_bound_i(value);
188  if (iter == end() || value < iter->first) {
189  return;
190  }
191  remove_i(iter, value);
192  }
193 
195  {
196  const T value = begin()->first;
197  remove_i(ranges_.begin(), value);
198  return value;
199  }
200 
201  bool has(T lower, T upper) const
202  {
203  const const_iterator iter = lower_bound(upper);
204  return iter != end() && !(lower < iter->first);
205  }
206 
207  bool has(const TPair& range) const
208  {
209  return has(range.first, range.second);
210  }
211 
212  bool has(T value) const
213  {
214  return has(value, value);
215  }
216 
217  bool has_any(T lower, T upper) const
218  {
219  const const_iterator iter = lower_bound(lower);
220  return iter != end() && !(upper < iter->first);
221  }
222 
223  bool has_any(const TPair& range) const
224  {
225  return has_any(range.first, range.second);
226  }
227 
228  template <typename Type> friend
229  bool operator==(const OrderedRanges<Type>& a, const OrderedRanges<Type>& b);
230 
231  private:
232  const_iterator lower_bound(const TPair& p) const { return ranges_.lower_bound(p); }
233 
234  const_iterator lower_bound(T t) const
235  {
236  return ranges_.lower_bound(TPair(T() /*ignored*/, t));
237  }
238 
239  // explicitly get a non-const iterator for use with methods like erase()
240  typename Container::iterator lower_bound_i(T t)
241  {
242  return ranges_.lower_bound(TPair(T() /*ignored*/, t));
243  }
244 
245  const_iterator upper_bound(const TPair& p) const { return ranges_.upper_bound(p); }
246 
247  const_iterator upper_bound(T t) const
248  {
249  return ranges_.upper_bound(TPair(T() /*ignored*/, t));
250  }
251 
252  // 'iter' must be a valid iterator to a range that contains 'value'
253  void remove_i(typename Container::iterator iter, T value)
254  {
255  const TPair orig = *iter;
256  ranges_.erase(iter);
257  if (value == orig.first) {
258  if (value < orig.second) {
259  ranges_.insert(TPair(value + T(1), orig.second));
260  }
261  } else if (value == orig.second) {
262  ranges_.insert(TPair(orig.first, value - T(1)));
263  } else {
264  ranges_.insert(TPair(orig.first, value - T(1)));
265  ranges_.insert(TPair(value + T(1), orig.second));
266  }
267  }
268 
269  friend class DisjointSequence;
270  Container ranges_;
271  };
272 
273 private:
275  RangeSet sequences_;
276 
277  // helper methods:
278 
279  bool insert_i(const SequenceRange& range,
280  OPENDDS_VECTOR(SequenceRange)* gaps = 0);
281 
282  bool insert_bitmap_range(RangeSet::Container::iterator& iter, const SequenceRange& sr);
283 
284 public:
285  /// Set the bits in range [low, high] in the bitmap, updating num_bits.
286  static bool fill_bitmap_range(ACE_CDR::ULong low, ACE_CDR::ULong high,
287  ACE_CDR::Long bitmap[], ACE_CDR::ULong length,
288  ACE_CDR::ULong& num_bits, ACE_CDR::ULong& cumulative_bits_added);
289 
290  /// Return the number of CORBA::Longs required for the bitmap representation of
291  /// sequence numbers between low and high, inclusive (maximum 8 longs).
292  static ACE_CDR::ULong bitmap_num_longs(const SequenceNumber& low, const SequenceNumber& high);
293 };
294 
295 template <typename T>
298 {
299  return a.ranges_ == b.ranges_;
300 }
301 
302 } // namespace DCPS
303 } // namespace OpenDDS
304 
306 
307 #ifdef __ACE_INLINE__
308 # include "DisjointSequence.inl"
309 #endif /* __ACE_INLINE__ */
310 
311 #endif /* DCPS_DISJOINTSEQUENCE_H */
const_iterator lower_bound(const TPair &p) const
const LogLevel::Value value
Definition: debug.cpp:61
OrderedRanges< SequenceNumber > RangeSet
#define OpenDDS_Dcps_Export
Definition: dcps_export.h:24
#define OPENDDS_ASSERT(C)
Definition: Definitions.h:72
Container::const_reverse_iterator const_reverse_iterator
bool operator==(const DisjointSequence::OrderedRanges< T > &a, const DisjointSequence::OrderedRanges< T > &b)
const_iterator upper_bound(const TPair &p) const
typedef OPENDDS_SET_CMP(GUID_t, GUID_tKeyLessThan) GuidSet
ACE_UINT32 ULong
ACE_INT32 Long
std::pair< SequenceNumber, SequenceNumber > SequenceRange
Sequence number abstraction. Only allows positive 64 bit values.
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
void remove_i(typename Container::iterator iter, T value)
int insert(Container &c, const ValueType &v)
Definition: Util.h:105
typedef OPENDDS_VECTOR(ActionConnectionRecord) ConnectionRecords
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
static bool range_less(const TPair &lhs, const TPair &rhs)