home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / IDIOMS.ZIP / 5-13.C < prev    next >
C/C++ Source or Header  |  1991-12-04  |  5KB  |  195 lines

  1. /* Copyright (c) 1992 by AT&T Bell Laboratories. */
  2. /* Advanced C++ Programming Styles and Idioms */
  3. /* James O. Coplien */
  4. /* All rights reserved. */
  5.  
  6. #include <stddef.h>
  7. #include <memory.h>
  8.  
  9. class LAPD {
  10. friend class LAPDMemoryManager;
  11. public:
  12.     virtual int size() { return 0; }
  13.     void *operator new(size_t);
  14.     void operator delete(void *);
  15.     LAPD(char *const);
  16. protected:
  17.     LAPD() { /* no-op */ }
  18. private:
  19.     int:8;
  20.     union {
  21.         struct {
  22.             unsigned char flag;
  23.             unsigned int sapi:6;
  24.         unsigned int commandResponse:1;
  25.         unsigned int zero:1;
  26.         unsigned int tei:7;
  27.         unsigned int ext:1;
  28.             unsigned char control;
  29.         } header;
  30.         struct {
  31.             LAPD *linkf, *linkb;
  32.             unsigned short size;
  33.         } minfo;
  34.     };
  35.     unsigned char tag;   // minfo system allocated tag
  36.     int performCRCCheck() { /* . . . */ }
  37. };
  38.  
  39. #define round(a,b) (((a+b-1)/b)*b)
  40.  
  41. class LAPDMemoryManager {
  42. friend LAPD;
  43. private:
  44.     enum { MessageBufSize=4096, Log2MessageBufSize=13 };
  45.     unsigned char availBuf[
  46.        (1+Log2MessageBufSize)*round(sizeof(LAPD),4)];
  47.     LAPD *avail;
  48.     unsigned char buf[MessageBufSize];
  49.     LAPD *buddy(int k, LAPD *l) {
  50.         char *cp = (char *) l;
  51.         return (LAPD*)(long(cp) ^ (1<<(k+1)));
  52.     }
  53. public:
  54.     LAPDMemoryManager() {
  55.         LAPD* buf = (LAPD*)this->buf;
  56.         avail = (LAPD*)availBuf;
  57.         avail[Log2MessageBufSize].minfo.linkf = 0;
  58.         avail[Log2MessageBufSize].minfo.linkb = 0;
  59.         buf[0].minfo.linkf = buf[0].minfo.linkb =
  60.                               &avail[Log2MessageBufSize];
  61.         buf[0].tag = 1;
  62.         buf[0].minfo.size = Log2MessageBufSize;
  63.         for (int k = 0; k < Log2MessageBufSize; k++) {
  64.             avail[k].minfo.linkf = avail[k].minfo.linkb =
  65.                                         (LAPD*)&avail[k];
  66.         }
  67.     }
  68.     int savej;
  69.     LAPD *largestBlock() {
  70.         for (int k = Log2MessageBufSize; k >= 0; --k) {
  71.             if (avail[k].minfo.linkf != &avail[k]) {
  72.                 savej = k;
  73.                 return avail[k].minfo.linkf;
  74.             }
  75.         }
  76.         return 0;
  77.     }
  78.     void allocateResizeBlock(int ktemp) {
  79.         int k, j = savej;
  80.         // Round up to next 2**n
  81.         for (int i = 1; i < Log2MessageBufSize; i++) {
  82.             k = 1 << i;
  83.             if (k > ktemp) break;
  84.         }
  85.         LAPD *l = avail[j].minfo.linkf;
  86.         avail[j].minfo.linkf = l->minfo.linkf;
  87.         l->minfo.linkf->minfo.linkb = &avail[j];
  88.         for(l->tag = 0; j - k; ) {
  89.             --j;
  90.             LAPD *p = (LAPD*)(((char *)l) + (1 << j));
  91.             p->tag = 1;
  92.             p->minfo.size = j;
  93.             p->minfo.linkf = &avail[j];
  94.             p->minfo.linkb = &avail[j];
  95.             avail[j].minfo.linkf = p;
  96.             avail[j].minfo.linkb = p;
  97.         }
  98.     }
  99.     void deallocateBlock(LAPD *l, int k) {
  100.         for(;;) {
  101.             LAPD *p = buddy(k,l);
  102.             if (k==Log2MessageBufSize || p->tag == 0 ||
  103.                                     p->minfo.size != k) {
  104.                 break;
  105.             }
  106.             p->minfo.linkb->minfo.linkf = p->minfo.linkf;
  107.             p->minfo.linkf->minfo.linkb = p->minfo.linkb;
  108.             ++k;
  109.             if (p < l) l = p;
  110.         }
  111.         l->tag = 1;
  112.         l->minfo.linkf = avail[k].minfo.linkf;
  113.         avail[k].minfo.linkb = l;
  114.         l->minfo.size = k;
  115.         l->minfo.linkb = &avail[k];
  116.         avail[k].minfo.linkf = l;
  117.     }
  118. };
  119.  
  120. static LAPDMemoryManager manager;
  121.  
  122. // this operator allows one object in the LAPD
  123. // hierarchy to overlay itself with an instance
  124. // of one of its derived classes
  125.  
  126. inline void *operator new(size_t, LAPD* l) { return l; }
  127.  
  128. class X25: public LAPD {
  129. friend LAPD;
  130. private:
  131.     struct X25PacketBody {
  132.            unsigned char rep[4096];
  133.     };
  134.     int size() { return sizeof(X25); }
  135.     X25(char *const m): LAPD() {
  136.         manager.allocateResizeBlock( size() );
  137.         ::memcpy(&body, m, sizeof(body));
  138.     }
  139.     X25PacketBody body;
  140. };
  141.  
  142. class EIN: public LAPD {
  143. friend LAPD;
  144. private:
  145.     struct EINPacketBody {
  146.        unsigned char rep[4096];
  147.     };
  148.     int size() { return sizeof(EIN); }
  149.     EIN(char *const m): LAPD() {
  150.         manager.allocateResizeBlock( size() );
  151.         ::memcpy(&body, m, sizeof(body));
  152.     }
  153.     EINPacketBody body;
  154. };
  155.  
  156. void *
  157. LAPD::operator new(size_t /* unused */) {
  158.     return manager.largestBlock();
  159. }
  160.  
  161. void
  162. LAPD::operator delete(void *l) {
  163.     manager.deallocateBlock((LAPD*)l, ((LAPD*)l)->size());
  164. }
  165.  
  166. LAPD::LAPD(char *const bits) {
  167.     ::memcpy(&header, bits, sizeof(header));
  168.     performCRCCheck();
  169.  
  170.     // Determine type of message based on address
  171.     switch(bits[0]) {
  172.     case 'a':
  173.         (void) ::new(this) X25(bits); break;
  174.     case 'b':
  175.         (void) ::new(this) EIN(bits); break;
  176.     default:
  177.         // error("invalid message"); break;
  178.         ;
  179.     }
  180. }
  181.  
  182. int main() {
  183.     LAPD *m, *n, *o, *p;
  184.     m = new LAPD("abcdefg");
  185.     n = new LAPD("badfljk;adsflkj;asldf");
  186.     delete n;
  187.     n = new LAPD("aadflkj;sadf");
  188.     o = new LAPD("aad;sflkj;lsdf");
  189.     p = new LAPD("bb");
  190.     delete p;
  191.     delete m;
  192.     delete n;
  193.     delete o;
  194. }
  195.