00001 #ifndef MAILBOX_IMPLEMENTATION_FILE
00002 #define MAILBOX_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "letter.h"
00019 #include "mailbox.h"
00020
00021 #include <basis/function.h>
00022 #include <basis/guards.h>
00023 #include <basis/istring.h>
00024 #include <basis/log_base.h>
00025 #include <basis/mutex.h>
00026 #include <data_struct/amorph.cpp>
00027 #include <data_struct/int_hash.cpp>
00028 #include <data_struct/unique_id.h>
00029 #include <textual/string_manipulation.h>
00030
00031 const int MAILBOX_BITS = 9;
00032
00033
00034
00035 class mail_cabinet
00036 {
00037 public:
00038 amorph<letter> _waiting;
00039
00040 mail_cabinet() : _waiting(0) {}
00041
00042 ~mail_cabinet() { _waiting.reset(); }
00043
00044 mail_cabinet(mail_cabinet &formal(to_copy)) {
00045 non_continuable_error("mail_cabinet", "copy constructor", "should never be called");
00046 }
00047
00048 mail_cabinet &operator =(mail_cabinet &formal(to_copy)) {
00049 non_continuable_error("mail_cabinet", "assignment operator",
00050 "should never be called");
00051 return *this;
00052 }
00053 };
00054
00056
00057 class mailbox_bank : public int_hash<mail_cabinet>
00058 {
00059 public:
00060 mailbox_bank() : int_hash<mail_cabinet> (MAILBOX_BITS) {}
00061 ~mailbox_bank() { reset(); }
00062
00063 void get_ids(int_set &to_fill);
00064
00065
00066 void add_cabinet(const unique_int &id);
00067
00068
00069 bool zap_cabinet(const unique_int &id);
00070
00071
00072 void add_item(const unique_int &id, letter *to_add);
00073
00074
00075 bool get(const unique_int &id, letter * &to_receive);
00076
00077
00078 void clean_up();
00079
00080 };
00081
00082 void mailbox_bank::clean_up()
00083 {
00084 int_set ids;
00085 get_ids(ids);
00086 for (int i = 0; i < ids.elements(); i++) {
00087 mail_cabinet *entry = find(ids[i]);
00088
00089 if (!entry->_waiting.elements()) zap(ids[i]);
00090 }
00091 }
00092
00093 void mailbox_bank::get_ids(int_set &to_fill) { to_fill = ids(); }
00094
00095 void mailbox_bank::add_cabinet(const unique_int &id)
00096 {
00097 if (find(id.raw_id())) return;
00098 mail_cabinet *to_add = new mail_cabinet;
00099 add(id.raw_id(), to_add);
00100 }
00101
00102 bool mailbox_bank::zap_cabinet(const unique_int &id)
00103 {
00104 if (!find(id.raw_id())) return false;
00105 return zap(id.raw_id());
00106 }
00107
00108 void mailbox_bank::add_item(const unique_int &id, letter *to_add)
00109 {
00110 mail_cabinet *found = find(id.raw_id());
00111 if (!found) {
00112 add_cabinet(id);
00113 found = find(id.raw_id());
00114
00115
00116 if (!found) {
00117
00118 return;
00119 }
00120 }
00121 found->_waiting.append(to_add);
00122 }
00123
00124 bool mailbox_bank::get(const unique_int &id, letter * &to_receive)
00125 {
00126 mail_cabinet *found = find(id.raw_id());
00127 if (!found) return false;
00128
00129 if (!found->_waiting.elements()) return false;
00130 for (int i = 0; i < found->_waiting.elements(); i++) {
00131
00132 if (!found->_waiting.borrow(i)->ready_to_send()) continue;
00133
00134 to_receive = found->_waiting.acquire(i);
00135 found->_waiting.zap(i, i);
00136 return true;
00137 }
00138 return false;
00139 }
00140
00142
00143 mailbox::mailbox()
00144 : _transaction_lock(new mutex),
00145 _packages(new mailbox_bank)
00146 {
00147 }
00148
00149 mailbox::~mailbox()
00150 {
00151 WHACK(_packages);
00152 WHACK(_transaction_lock);
00153 }
00154
00155 void mailbox::get_ids(int_set &to_fill)
00156 {
00157 auto_synchronizer l(*_transaction_lock);
00158 _packages->get_ids(to_fill);
00159 }
00160
00161 void mailbox::drop_off(const unique_int &id, letter *package)
00162 {
00163 auto_synchronizer l(*_transaction_lock);
00164 _packages->add_item(id, package);
00165 }
00166
00167 void mailbox::clean_up()
00168 {
00169 auto_synchronizer l(*_transaction_lock);
00170 _packages->clean_up();
00171 }
00172
00173 int mailbox::waiting(const unique_int &id) const
00174 {
00175 auto_synchronizer l(*_transaction_lock);
00176 mail_cabinet *found = _packages->find(id.raw_id());
00177 int to_return = 0;
00178
00179 if (found)
00180 to_return = found->_waiting.elements();
00181 return to_return;
00182 }
00183
00184 bool mailbox::pick_up(const unique_int &id, letter * &package)
00185 {
00186 package = NIL;
00187 auto_synchronizer l(*_transaction_lock);
00188 return _packages->get(id, package);
00189 }
00190
00191 bool mailbox::close_out(const unique_int &id)
00192 {
00193 auto_synchronizer l(*_transaction_lock);
00194 bool ret = _packages->zap_cabinet(id);
00195 return ret;
00196 }
00197
00198 void mailbox::show(istring &to_fill)
00199 {
00200 auto_synchronizer l(*_transaction_lock);
00201 int_set ids;
00202 _packages->get_ids(ids);
00203 for (int i = 0; i < ids.elements(); i++) {
00204 mail_cabinet &mc = *_packages->find(ids[i]);
00205 to_fill += istring(istring::SPRINTF, "cabinet %d:", ids[i])
00206 + log_base::platform_ending();
00207 for (int j = 0; j < mc._waiting.elements(); j++) {
00208 letter &l = *mc._waiting.borrow(j);
00209 to_fill += string_manipulation::indentation(4)
00210 + istring(istring::SPRINTF, "%4ld: ", j + 1)
00211 + l.text_form() + log_base::platform_ending();
00212 }
00213 }
00214 }
00215
00216 void mailbox::limit_boxes(int max_letters)
00217 {
00218 auto_synchronizer l(*_transaction_lock);
00219 int_set ids;
00220 _packages->get_ids(ids);
00221 for (int i = 0; i < ids.elements(); i++) {
00222 mail_cabinet &mc = *_packages->find(ids[i]);
00223 if (mc._waiting.elements() > max_letters) {
00224
00225 mc._waiting.zap(max_letters, mc._waiting.elements() - 1);
00226 }
00227 }
00228 }
00229
00230 void mailbox::apply(apply_function *to_apply, void *data_link)
00231 {
00232 auto_synchronizer l(*_transaction_lock);
00233 int_set ids;
00234 _packages->get_ids(ids);
00235 for (int i = 0; i < ids.elements(); i++) {
00236 mail_cabinet &mc = *_packages->find(ids[i]);
00237 for (int j = 0; j < mc._waiting.elements(); j++) {
00238 letter &l = *mc._waiting.borrow(j);
00239 outcome ret = to_apply(l, ids[i], data_link);
00240 if ( (ret == APPLY_WHACK) || (ret == APPLY_WHACK_STOP) ) {
00241
00242 mc._waiting.zap(j, j);
00243 j--;
00244 if (ret == APPLY_WHACK_STOP)
00245 break;
00246 } else if (ret == APPLY_STOP) {
00247 break;
00248 }
00249 }
00250 }
00251 }
00252
00253
00254 #endif //MAILBOX_IMPLEMENTATION_FILE
00255