| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| #include "AccumulatedAck.h" |
| |
| #include <assert.h> |
| #include <iostream> |
| #include <boost/bind.hpp> |
| |
| using std::list; |
| using std::max; |
| using std::min; |
| using namespace qpid::framing; |
| |
| AccumulatedAck::AccumulatedAck(SequenceNumber r) : mark(r) {} |
| |
| void AccumulatedAck::update(SequenceNumber first, SequenceNumber last){ |
| assert(first <= last); |
| if (last < mark) return; |
| |
| |
| Range r(first, last); |
| bool handled = false; |
| bool markMerged = false; |
| list<Range>::iterator merged = ranges.end(); |
| if (r.mergeable(mark)) { |
| mark = r.end; |
| markMerged = true; |
| handled = true; |
| } else { |
| for (list<Range>::iterator i = ranges.begin(); i != ranges.end() && !handled; i++) { |
| if (i->merge(r)) { |
| merged = i; |
| handled = true; |
| } else if (r.start < i->start) { |
| ranges.insert(i, r); |
| handled = true; |
| } |
| } |
| } |
| if (!handled) { |
| ranges.push_back(r); |
| } else { |
| while (!ranges.empty() && ranges.front().end <= mark) { |
| ranges.pop_front(); |
| } |
| if (markMerged) { |
| //new range is incorporated, but may be possible to consolidate |
| merged = ranges.begin(); |
| while (merged != ranges.end() && merged->mergeable(mark)) { |
| mark = merged->end; |
| merged = ranges.erase(merged); |
| } |
| } |
| if (merged != ranges.end()) { |
| //consolidate ranges |
| list<Range>::iterator i = merged; |
| list<Range>::iterator j = i++; |
| while (i != ranges.end() && j->merge(*i)) { |
| j = i++; |
| } |
| } |
| } |
| } |
| |
| void AccumulatedAck::consolidate(){} |
| |
| void AccumulatedAck::clear(){ |
| mark = SequenceNumber(0);//not sure that this is valid when wraparound is a possibility |
| ranges.clear(); |
| } |
| |
| bool AccumulatedAck::covers(SequenceNumber tag) const{ |
| if (tag <= mark) return true; |
| for (list<Range>::const_iterator i = ranges.begin(); i != ranges.end(); i++) { |
| if (i->contains(tag)) return true; |
| } |
| return false; |
| } |
| |
| void AccumulatedAck::collectRanges(SequenceNumberSet& set) const |
| { |
| for (list<Range>::const_iterator i = ranges.begin(); i != ranges.end(); i++) { |
| set.push_back(i->start); |
| set.push_back(i->end); |
| } |
| } |
| |
| void AccumulatedAck::update(const SequenceNumber cumulative, const SequenceNumberSet& range) |
| { |
| update(mark, cumulative); |
| range.processRanges(*this); |
| } |
| |
| |
| bool Range::contains(SequenceNumber i) const |
| { |
| return i >= start && i <= end; |
| } |
| |
| bool Range::intersect(const Range& r) const |
| { |
| return r.contains(start) || r.contains(end) || contains(r.start) || contains(r.end); |
| } |
| |
| bool Range::merge(const Range& r) |
| { |
| if (intersect(r) || mergeable(r.end) || r.mergeable(end)) { |
| start = min(start, r.start); |
| end = max(end, r.end); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| bool Range::mergeable(const SequenceNumber& s) const |
| { |
| if (contains(s) || start - s == 1) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| Range::Range(SequenceNumber s, SequenceNumber e) : start(s), end(e) {} |
| |
| |
| namespace qpid{ |
| namespace framing{ |
| std::ostream& operator<<(std::ostream& out, const Range& r) |
| { |
| out << "[" << r.start.getValue() << "-" << r.end.getValue() << "]"; |
| return out; |
| } |
| |
| std::ostream& operator<<(std::ostream& out, const AccumulatedAck& a) |
| { |
| out << "{mark: " << a.mark.getValue() << ", ranges: ("; |
| for (list<Range>::const_iterator i = a.ranges.begin(); i != a.ranges.end(); i++) { |
| if (i != a.ranges.begin()) out << ", "; |
| out << *i; |
| } |
| out << ")]"; |
| return out; |
| } |
| }} |