Merge branch 'master' of feistymeow.org:feisty_meow
[feisty_meow.git] / octopi / library / sockets / span_manager.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : span_manager                                                      *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *******************************************************************************
7 * Copyright (c) 1990-$now By Author.  This program is free software; you can  *
8 * redistribute it and/or modify it under the terms of the GNU General Public  *
9 * License as published by the Free Software Foundation; either version 2 of   *
10 * the License or (at your option) any later version.  This is online at:      *
11 *     http://www.fsf.org/copyleft/gpl.html                                    *
12 * Please send any updates to: fred@gruntose.com                               *
13 \*****************************************************************************/
14
15 #include "span_manager.h"
16
17 #include <basis/functions.h>
18 #include <basis/guards.h>
19 #include <basis/astring.h>
20 #include <structures/bit_vector.h>
21 #include <structures/set.h>
22
23 using namespace basis;
24 using namespace structures;
25 //using namespace basis;
26
27 namespace sockets {
28
29 span_manager::span_manager(int packs)
30 : _implementation(new bit_vector(packs))
31 {}
32
33 span_manager::span_manager(const span_manager &to_copy)
34 : _implementation(new bit_vector(*to_copy._implementation))
35 {}
36
37 span_manager::~span_manager() { WHACK(_implementation); }
38
39 span_manager &span_manager::operator =(const span_manager &to_copy)
40 {
41   if (this == &to_copy) return *this;
42   *_implementation = *to_copy._implementation;
43   return *this;
44 }
45
46 int span_manager::missing_sequence() const
47 { return _implementation->find_first(0); }
48
49 void span_manager::reset(int packs) { _implementation->resize(packs); }
50
51 const bit_vector &span_manager::vector() const { return *_implementation; }
52
53 bit_vector &span_manager::vector() { return *_implementation; }
54
55 int span_manager::received_sequence() const
56 {
57   int recd_to = _implementation->find_first(0);
58   if (negative(recd_to)) return _implementation->bits() - 1;
59   return recd_to - 1;
60 }
61
62 void span_manager::make_received_list(int_array &to_make, int max_spans) const
63 {
64   to_make.reset(0);
65   int zeros_start_at = _implementation->find_first(0);
66   if (negative(zeros_start_at)) {
67     // all bits are set in the vector, so the whole message is received.
68     to_make.concatenate(0);
69     to_make.concatenate(short(_implementation->bits() - 1));
70     return;
71   }
72   zeros_start_at--;
73   // the sequence of ones ends right before the first zero
74   if (zeros_start_at >= 0) {
75     to_make.concatenate(0);
76     to_make.concatenate(short(zeros_start_at));
77   }
78
79   int ones_to_here;  // keeps track of the position of the ones.
80
81   for (int outer_loop = zeros_start_at + 2;
82       outer_loop < _implementation->bits(); ) {
83     // the first zero is zeros_start_at + 1, so we start at the first
84     // unknown bit.
85     if (_implementation->on(outer_loop)) {
86       // the bit is a one, so we are in a one-gathering mode.
87       ones_to_here = outer_loop;
88       int inner_loop = outer_loop + 1;
89       while (inner_loop < _implementation->bits()) {
90         if (_implementation->on(inner_loop)) ones_to_here=inner_loop;
91         else break;  // a zero is found at this position, so leave loop.
92         inner_loop++;
93       }
94       // the stretch of ones is entered in the array.
95       to_make.concatenate(short(outer_loop));
96       to_make.concatenate(short(ones_to_here));
97       if ( (max_spans >= 0) && (to_make.length() >= 2 * max_spans) )
98         return;
99       outer_loop = ones_to_here + 1;
100     } else {
101       // the bit is a zero, so we are gathering zeros.
102       int inner_loop = outer_loop + 1;
103       ones_to_here = _implementation->bits();
104       while (inner_loop < _implementation->bits()) {
105         if (!_implementation->on(inner_loop)) inner_loop++;
106         else {
107           // ones_to_here is set to the first position of a one, actually.
108           ones_to_here = inner_loop;
109           break;
110         }
111       }
112       // the loop variable is set to the first unknown position again.
113       outer_loop = ones_to_here;
114     }
115   }
116 }
117
118 bool span_manager::update(const int_array &new_spans)
119 {
120   for (int i = 0; i < new_spans.length(); i += 2) {
121     if ( (new_spans.get(i) >= _implementation->bits())
122         || (new_spans.get(i+1) >= _implementation->bits()) )
123       return false;
124     for (int j = new_spans.get(i); j <= new_spans.get(i+1); j++)
125       _implementation->light(j);
126   }
127   return true;
128 }
129
130 void span_manager::make_missing_list(int_array &to_make, int max_spans) const
131 {
132   to_make.reset(0);
133   int ones_start_at = _implementation->find_first(1);
134   if (negative(ones_start_at)) {
135     // all bits are zero in the vector; no packets have been received.
136     to_make.concatenate(0);
137     to_make.concatenate(short(_implementation->bits() - 1));
138     return;
139   }
140   ones_start_at--;
141   // the sequence of zeros ends right before the first one
142   if (ones_start_at >= 0) {
143     to_make.concatenate(0);
144     to_make.concatenate(short(ones_start_at));
145   }
146
147   int zeros_to_here;
148   for (int outer_loop = ones_start_at + 2;
149       outer_loop < _implementation->bits(); ) {
150     int inner_loop;
151     // the first one is ones_start_at+1, so we start at the first unknown bit
152     if (!_implementation->on(outer_loop)) {
153       // the bit is a zero, so we are in a zero-gathering mode.
154       zeros_to_here = outer_loop;
155       int inner_loop = outer_loop + 1;
156       while (inner_loop < _implementation->bits()) {
157         if (!_implementation->on(inner_loop)) zeros_to_here=inner_loop;
158         else break;
159           // a one is found at this position, so leave loop.
160         inner_loop++;
161       }
162       // the stretch of zeros is entered in the array.
163       to_make.concatenate(short(outer_loop));
164       to_make.concatenate(short(zeros_to_here));
165       if ( (max_spans >= 0) && (to_make.length() >= 2 * max_spans) ) return;
166       outer_loop = zeros_to_here + 1;
167     } else {
168       // the bit is a one, so we are gathering ones.
169       inner_loop = outer_loop + 1;
170       zeros_to_here = _implementation->bits();
171       while (inner_loop < _implementation->bits()) {
172         if (_implementation->on(inner_loop))
173           inner_loop++;
174         else {
175           // zeros_to_here is set to the first position of a zero, actually.
176           zeros_to_here = inner_loop;
177           break;
178         }
179       }
180       // the loop variable is set to the first unknown position again.
181       outer_loop = zeros_to_here;
182     }
183   }
184 }
185
186 astring span_manager::funky_print(const int_array &to_spew, int rec_seq) const
187 {
188   astring to_return(astring::SPRINTF, "through %d, [", rec_seq);
189   for (int i = 0; i < to_spew.length(); i += 2) {
190     to_return += astring(astring::SPRINTF, " %d-%d", to_spew.get(i),
191         to_spew.get(i+1));
192   }
193   to_return += astring(" ] ");
194   return to_return;
195 }
196
197 astring span_manager::print_received_list() const
198 {
199   int_array hold_info;
200   make_received_list(hold_info);
201   astring to_return("received ");
202   to_return += funky_print(hold_info, received_sequence());
203   return to_return;
204 }
205
206 astring span_manager::print_missing_list() const
207 {
208   int_array hold_info;
209   make_missing_list(hold_info);
210   astring to_return("missing ");
211   to_return += funky_print(hold_info, received_sequence());
212   return to_return;
213 }
214
215 } //namespace.
216