feisty meow concerns codebase  2.140
mailbox.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : mailbox *
4 * Author : Chris Koeritz *
5 * *
6 *******************************************************************************
7 * Copyright (c) 1998-$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 "letter.h"
16 #include "mailbox.h"
17 
18 #include <basis/astring.h>
19 #include <basis/functions.h>
20 #include <basis/guards.h>
21 #include <basis/mutex.h>
23 #include <structures/amorph.h>
24 #include <structures/int_hash.h>
25 #include <structures/unique_id.h>
26 #include <textual/parser_bits.h>
28 
29 using namespace basis;
30 using namespace loggers;
31 using namespace structures;
32 using namespace textual;
33 
34 namespace processes {
35 
36 const int MAILBOX_BITS = 9;
37  // we allow N bits in our table size, which means the table will have 2^N
38  // elements. careful with that increase...
39 
40 class mail_cabinet
41 {
42 public:
43  amorph<letter> _waiting;
44 
45  mail_cabinet() : _waiting(0) {}
46 
47  ~mail_cabinet() { _waiting.reset(); }
48 
49  mail_cabinet(mail_cabinet &formal(to_copy)) {
50  non_continuable_error("mail_cabinet", "copy constructor", "should never be called");
51  }
52 
53  mail_cabinet &operator =(mail_cabinet &formal(to_copy)) {
54  non_continuable_error("mail_cabinet", "assignment operator",
55  "should never be called");
56  return *this;
57  }
58 };
59 
61 
62 class mailbox_bank : public int_hash<mail_cabinet>
63 {
64 public:
65  mailbox_bank() : int_hash<mail_cabinet> (MAILBOX_BITS) {}
66  ~mailbox_bank() { reset(); }
67 
68  void get_ids(int_set &to_fill);
69  // returns the list of identifiers for people with mailboxes.
70 
71  void add_cabinet(const unique_int &id);
72  // creates a new mail receptacle for the "id".
73 
74  bool zap_cabinet(const unique_int &id);
75  // removes the cabinet for "id".
76 
77  void add_item(const unique_int &id, letter *to_add);
78  // stuffs an item "to_add" in for "id".
79 
80  bool get(const unique_int &id, letter * &to_receive);
81  // retrieves the next waiting package for "id" into "to_receive".
82 
83  void clean_up();
84  // gets rid of any cabinets without any packages.
85 };
86 
87 void mailbox_bank::clean_up()
88 {
89  int_set ids;
90  get_ids(ids);
91  for (int i = 0; i < ids.elements(); i++) {
92  mail_cabinet *entry = find(ids[i]);
93  // if the cabinet has zero elements, we zap it.
94  if (!entry->_waiting.elements()) zap(ids[i]);
95  }
96 }
97 
98 void mailbox_bank::get_ids(int_set &to_fill) { to_fill = ids(); }
99 
100 void mailbox_bank::add_cabinet(const unique_int &id)
101 {
102  if (find(id.raw_id())) return; // already exists.
103  mail_cabinet *to_add = new mail_cabinet;
104  add(id.raw_id(), to_add);
105 }
106 
107 bool mailbox_bank::zap_cabinet(const unique_int &id)
108 {
109  if (!find(id.raw_id())) return false; // doesn't exist.
110  return zap(id.raw_id());
111 }
112 
113 void mailbox_bank::add_item(const unique_int &id, letter *to_add)
114 {
115  mail_cabinet *found = find(id.raw_id());
116  if (!found) {
117  add_cabinet(id);
118  found = find(id.raw_id());
119  // there should never be a failure case that would prevent the new cabinet
120  // from being added (besides overall memory failure).
121  if (!found) {
122 //complain
123  return;
124  }
125  }
126  found->_waiting.append(to_add);
127 }
128 
129 bool mailbox_bank::get(const unique_int &id, letter * &to_receive)
130 {
131  mail_cabinet *found = find(id.raw_id());
132  if (!found) return false; // no cabinet, much less any mail.
133 
134  if (!found->_waiting.elements()) return false; // no mail waiting.
135  for (int i = 0; i < found->_waiting.elements(); i++) {
136  // check if its time is ripe...
137  if (!found->_waiting.borrow(i)->ready_to_send()) continue;
138  // get the waiting mail and remove its old slot.
139  to_receive = found->_waiting.acquire(i);
140  found->_waiting.zap(i, i);
141  return true;
142  }
143  return false;
144 }
145 
147 
148 mailbox::mailbox()
149 : _transaction_lock(new mutex),
150  _packages(new mailbox_bank)
151 {
152 }
153 
155 {
156  WHACK(_packages);
157  WHACK(_transaction_lock);
158 }
159 
160 void mailbox::get_ids(int_set &to_fill)
161 {
162  auto_synchronizer l(*_transaction_lock);
163  _packages->get_ids(to_fill);
164 }
165 
166 void mailbox::drop_off(const unique_int &id, letter *package)
167 {
168  auto_synchronizer l(*_transaction_lock);
169  _packages->add_item(id, package);
170 }
171 
173 {
174  auto_synchronizer l(*_transaction_lock);
175  _packages->clean_up();
176 }
177 
178 int mailbox::waiting(const unique_int &id) const
179 {
180  auto_synchronizer l(*_transaction_lock);
181  mail_cabinet *found = _packages->find(id.raw_id());
182  int to_return = 0; // if no cabinet, this is the proper count.
183  // if there is a cabinet, then get the size.
184  if (found)
185  to_return = found->_waiting.elements();
186  return to_return;
187 }
188 
189 bool mailbox::pick_up(const unique_int &id, letter * &package)
190 {
191  package = NULL_POINTER;
192  auto_synchronizer l(*_transaction_lock);
193  return _packages->get(id, package);
194 }
195 
197 {
198  auto_synchronizer l(*_transaction_lock);
199  bool ret = _packages->zap_cabinet(id);
200  return ret;
201 }
202 
203 void mailbox::show(astring &to_fill)
204 {
205  auto_synchronizer l(*_transaction_lock);
206  int_set ids;
207  _packages->get_ids(ids);
208  for (int i = 0; i < ids.elements(); i++) {
209  mail_cabinet &mc = *_packages->find(ids[i]);
210  to_fill += astring(astring::SPRINTF, "cabinet %d:", ids[i])
211  + parser_bits::platform_eol_to_chars();
212  for (int j = 0; j < mc._waiting.elements(); j++) {
213  letter &l = *mc._waiting.borrow(j);
214  astring text;
215  l.text_form(text);
216  to_fill += string_manipulation::indentation(4)
217  + astring(astring::SPRINTF, "%4ld: ", j + 1)
218  + text + parser_bits::platform_eol_to_chars();
219  }
220  }
221 }
222 
223 void mailbox::limit_boxes(int max_letters)
224 {
225  auto_synchronizer l(*_transaction_lock);
226  int_set ids;
227  _packages->get_ids(ids);
228  for (int i = 0; i < ids.elements(); i++) {
229  mail_cabinet &mc = *_packages->find(ids[i]);
230  if (mc._waiting.elements() > max_letters) {
231  // this one needs cleaning.
232  mc._waiting.zap(max_letters, mc._waiting.elements() - 1);
233  }
234  }
235 }
236 
237 void mailbox::apply(apply_function *to_apply, void *data_link)
238 {
239  auto_synchronizer l(*_transaction_lock);
240  int_set ids;
241  _packages->get_ids(ids);
242  for (int i = 0; i < ids.elements(); i++) {
243  mail_cabinet &mc = *_packages->find(ids[i]);
244  for (int j = 0; j < mc._waiting.elements(); j++) {
245  letter &l = *mc._waiting.borrow(j);
246  outcome ret = to_apply(l, ids[i], data_link);
247  if ( (ret == APPLY_WHACK) || (ret == APPLY_WHACK_STOP) ) {
248  // they wanted this node removed.
249  mc._waiting.zap(j, j);
250  j--; // skip back before missing guy so we don't omit anyone.
251  if (ret == APPLY_WHACK_STOP)
252  break; // they wanted to be done with it also.
253  } else if (ret == APPLY_STOP) {
254  break; // we hit the exit condition.
255  }
256  }
257  }
258 }
259 
260 } //namespace.
261 
262 
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
Outcomes describe the state of completion for an operation.
Definition: outcome.h:31
A virtual base class for pieces of "mail". Used by the mailbox object.
Definition: letter.h:25
virtual void text_form(basis::base_string &fill) const =0
derived letters must print a status blurb describing their contents.
void get_ids(structures::int_set &to_fill)
stuffs the set "to_fill" with the ids of all mailboxes present.
Definition: mailbox.cpp:160
void drop_off(const structures::unique_int &id, letter *package)
drops a "package" in the mailbox for "id".
Definition: mailbox.cpp:166
int waiting(const structures::unique_int &id) const
returns the number of items waiting for the "id" specified, if any.
Definition: mailbox.cpp:178
basis::outcome apply_function(letter &current, int uid, void *data_link)
the "apply_function" is what a user of apply() must provide.
Definition: mailbox.h:100
bool pick_up(const structures::unique_int &id, letter *&package)
returns true if the mailbox for "id" had a "package" to be delivered.
Definition: mailbox.cpp:189
virtual ~mailbox()
Definition: mailbox.cpp:154
bool close_out(const structures::unique_int &id)
dumps all packages stored for the "id" and shuts down its mailbox.
Definition: mailbox.cpp:196
void clean_up()
removes any empty mailboxes from our list.
Definition: mailbox.cpp:172
void show(basis::astring &to_fill)
provides a picture of what's waiting in the mailbox.
Definition: mailbox.cpp:203
void limit_boxes(int max_letters)
establishes a limit on the number of letters.
Definition: mailbox.cpp:223
void apply(apply_function *to_apply, void *data_link)
calls the "to_apply" function on possibly every letter in the mailbox.
Definition: mailbox.cpp:237
void reset()
cleans out all of the contents.
Definition: amorph.h:81
A hash table for storing integers.
Definition: int_hash.h:36
A simple object that wraps a templated set of ints.
Definition: set.h:156
int elements() const
Returns the number of elements in this set.
Definition: set.h:47
A unique identifier based on integers.
Definition: unique_id.h:97
#define non_continuable_error(c, f, i)
an extra piece of information used, if available, in bounds_halt below.
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
Definition: definitions.h:48
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
A logger that sends to the console screen using the standard output device.
const int MAILBOX_BITS
Definition: mailbox.cpp:36
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55