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>
26#include <textual/parser_bits.h>
28
29using namespace basis;
30using namespace loggers;
31using namespace structures;
32using namespace textual;
33
34namespace processes {
35
36const 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
40class mail_cabinet
41{
42public:
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
62class mailbox_bank : public int_hash<mail_cabinet>
63{
64public:
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
87void 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
98void mailbox_bank::get_ids(int_set &to_fill) { to_fill = ids(); }
99
100void 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
107bool 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
113void 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
129bool 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
149: _transaction_lock(new mutex),
150 _packages(new mailbox_bank)
151{
152}
153
155{
156 WHACK(_packages);
157 WHACK(_transaction_lock);
158}
159
161{
162 auto_synchronizer l(*_transaction_lock);
163 _packages->get_ids(to_fill);
164}
165
166void 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
178int 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
189bool 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
203void 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])
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);
217 + astring(astring::SPRINTF, "%4ld: ", j + 1)
219 }
220 }
221}
222
223void 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
237void 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
void reset()
overrides base reset() and ensures that the id list stays up to date.
Definition int_hash.h:109
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
static const char * platform_eol_to_chars()
provides the characters that make up this platform's line ending.
static basis::astring indentation(int spaces)
Returns a string made of white space that is "spaces" long.
#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