mailbox.cpp

Go to the documentation of this file.
00001 #ifndef MAILBOX_IMPLEMENTATION_FILE
00002 #define MAILBOX_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : mailbox                                                           *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1998-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
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   // we allow N bits in our table size, which means the table will have 2^N
00033   // elements.  careful with that increase...
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     // returns the list of identifiers for people with mailboxes.
00065 
00066   void add_cabinet(const unique_int &id);
00067     // creates a new mail receptacle for the "id".
00068 
00069   bool zap_cabinet(const unique_int &id);
00070     // removes the cabinet for "id".
00071 
00072   void add_item(const unique_int &id, letter *to_add);
00073     // stuffs an item "to_add" in for "id".
00074 
00075   bool get(const unique_int &id, letter * &to_receive);
00076     // retrieves the next waiting package for "id" into "to_receive".
00077 
00078   void clean_up();
00079     // gets rid of any cabinets without any packages.
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     // if the cabinet has zero elements, we zap it.
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;  // already exists.
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;  // doesn't exist.
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     // there should never be a failure case that would prevent the new cabinet
00115     // from being added (besides overall memory failure).
00116     if (!found) {
00117 //complain
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;  // no cabinet, much less any mail.
00128 
00129   if (!found->_waiting.elements()) return false;  // no mail waiting.
00130   for (int i = 0; i < found->_waiting.elements(); i++) {
00131     // check if its time is ripe...
00132     if (!found->_waiting.borrow(i)->ready_to_send()) continue;
00133     // get the waiting mail and remove its old slot.
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;  // if no cabinet, this is the proper count.
00178   // if there is a cabinet, then get the size.
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       // this one needs cleaning.
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         // they wanted this node removed.
00242         mc._waiting.zap(j, j);
00243         j--;  // skip back before missing guy so we don't omit anyone.
00244         if (ret == APPLY_WHACK_STOP)
00245           break;  // they wanted to be done with it also.
00246       } else if (ret == APPLY_STOP) {
00247         break;  // we hit the exit condition.
00248       }
00249     }
00250   }
00251 }
00252 
00253 
00254 #endif //MAILBOX_IMPLEMENTATION_FILE
00255 

Generated on Sat Oct 11 04:28:52 2008 for HOOPLE Libraries by  doxygen 1.5.1