object.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:31k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * object.cxx
  3.  *
  4.  * Global object support.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: object.cxx,v $
  30.  * Revision 1.44  2000/06/26 11:17:20  robertj
  31.  * Nucleus++ port (incomplete).
  32.  *
  33.  * Revision 1.43  2000/01/05 00:29:12  robertj
  34.  * Fixed alignment problems in memory checking debug functions.
  35.  *
  36.  * Revision 1.42  1999/11/01 00:17:20  robertj
  37.  * Added override of new functions for MSVC memory check code.
  38.  *
  39.  * Revision 1.41  1999/08/22 13:38:39  robertj
  40.  * Fixed termination hang up problem with memory check code under unix pthreads.
  41.  *
  42.  * Revision 1.40  1999/08/10 10:45:09  robertj
  43.  * Added mutex in memory check detection code.
  44.  *
  45.  * Revision 1.39  1999/07/18 15:08:48  robertj
  46.  * Fixed 64 bit compatibility
  47.  *
  48.  * Revision 1.38  1999/05/01 11:29:20  robertj
  49.  * Alpha linux port changes.
  50.  *
  51.  * Revision 1.37  1999/03/09 10:30:17  robertj
  52.  * Fixed ability to have PMEMORY_CHECK on/off on both debug/release versions.
  53.  *
  54.  * Revision 1.36  1999/02/22 10:48:14  robertj
  55.  * Fixed delete operator prototypes for MSVC6 and GNU compatibility.
  56.  *
  57.  * Revision 1.35  1998/12/22 10:24:17  robertj
  58.  * Fixed MSVC warnings caused by changes made in linux PPC support.
  59.  *
  60.  * Revision 1.34  1998/12/15 09:01:10  robertj
  61.  * Fixed 8 byte alignment problem in memory leak check code for sparc.
  62.  *
  63.  * Revision 1.33  1998/11/30 05:33:00  robertj
  64.  * Fixed duplicate debug stream class, ther can be only one.
  65.  *
  66.  * Revision 1.32  1998/11/03 03:11:53  robertj
  67.  * Fixed memory leak question so correctly detects leaks and can be ^C'd.
  68.  *
  69.  * Revision 1.31  1998/11/03 00:55:31  robertj
  70.  * Added allocation breakpoint variable.
  71.  *
  72.  * Revision 1.30  1998/10/15 07:48:56  robertj
  73.  * Added hex dump to memory leak.
  74.  * Added ability to ignore G++lib memory leaks.
  75.  *
  76.  * Revision 1.29  1998/10/15 01:53:35  robertj
  77.  * GNU compatibility.
  78.  *
  79.  * Revision 1.28  1998/10/13 14:06:26  robertj
  80.  * Complete rewrite of memory leak detection code.
  81.  *
  82.  * Revision 1.27  1998/09/23 06:22:22  robertj
  83.  * Added open source copyright license.
  84.  *
  85.  * Revision 1.26  1998/05/30 13:27:02  robertj
  86.  * Changed memory check code so global statics are not included in leak check.
  87.  *
  88.  * Revision 1.25  1997/07/08 13:07:07  robertj
  89.  * DLL support.
  90.  *
  91.  * Revision 1.24  1997/02/09 03:45:28  robertj
  92.  * Fixed unix/dos compatibility with include file.
  93.  *
  94.  * Revision 1.23  1997/02/05 11:54:12  robertj
  95.  * Fixed problems with memory check and leak detection.
  96.  *
  97.  * Revision 1.22  1996/08/08 10:08:46  robertj
  98.  * Directory structure changes for common files.
  99.  *
  100.  * Revision 1.21  1996/07/15 10:35:11  robertj
  101.  * Changed memory leak dump to use static class rather than atexit for better portability.
  102.  *
  103.  * Revision 1.20  1996/06/17 11:35:47  robertj
  104.  * Fixed display of memory leak info, needed flush and use of cin as getchar() does not work with services.
  105.  *
  106.  * Revision 1.19  1996/05/09 12:19:29  robertj
  107.  * Fixed up 64 bit integer class for Mac platform.
  108.  * Fixed incorrect use of memcmp/strcmp return value.
  109.  *
  110.  * Revision 1.18  1996/03/26 00:55:20  robertj
  111.  * Added keypress before dumping memory leaks.
  112.  *
  113.  * Revision 1.17  1996/01/28 02:50:27  robertj
  114.  * Added missing bit shift operators to 64 bit integer class.
  115.  * Added assert into all Compare functions to assure comparison between compatible objects.
  116.  *
  117.  * Revision 1.16  1996/01/23 13:15:52  robertj
  118.  * Mac Metrowerks compiler support.
  119.  *
  120.  * Revision 1.15  1996/01/02 12:52:02  robertj
  121.  * Mac OS compatibility changes.
  122.  *
  123.  * Revision 1.14  1995/11/21 11:51:54  robertj
  124.  * Improved streams compatibility.
  125.  *
  126.  * Revision 1.12  1995/04/25 11:30:34  robertj
  127.  * Fixed Borland compiler warnings.
  128.  * Fixed function hiding ancestors virtual.
  129.  *
  130.  * Revision 1.11  1995/03/12 04:59:53  robertj
  131.  * Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code.
  132.  * Used built-in equate for WIN32 API (_WIN32).
  133.  *
  134.  * Revision 1.10  1995/02/19  04:19:21  robertj
  135.  * Added dynamically linked command processing.
  136.  *
  137.  * Revision 1.9  1995/01/15  04:52:02  robertj
  138.  * Mac compatibility.
  139.  * Added memory stats function.
  140.  *
  141. // Revision 1.8  1995/01/09  12:38:07  robertj
  142. // Changed variable names around during documentation run.
  143. // Fixed smart pointer comparison.
  144. // Fixed serialisation stuff.
  145. //
  146. // Revision 1.7  1995/01/07  04:39:45  robertj
  147. // Redesigned font enumeration code and changed font styles.
  148. //
  149. // Revision 1.6  1995/01/04  10:57:08  robertj
  150. // Changed for HPUX and GNU2.6.x
  151. //
  152. // Revision 1.5  1995/01/03  09:39:10  robertj
  153. // Put standard malloc style memory allocation etc into memory check system.
  154. //
  155. // Revision 1.4  1994/12/21  11:43:29  robertj
  156. // Added extra memory stats.
  157. //
  158. // Revision 1.3  1994/12/13  11:54:54  robertj
  159. // Added some memory usage statistics.
  160. //
  161. // Revision 1.2  1994/12/12  10:08:32  robertj
  162. // Renamed PWrapper to PSmartPointer..
  163. //
  164. // Revision 1.1  1994/10/30  12:02:15  robertj
  165. // Initial revision
  166. //
  167.  */
  168. #include <ptlib.h>
  169. #include <ctype.h>
  170. #ifdef _WIN32
  171. #include <strstrea.h>
  172. #include <ptlib/debstrm.h>
  173. #elif defined(__NUCLEUS_PLUS__)
  174. #include <ptlib/NucleusDebstrm.h>
  175. #else
  176. #include <strstream.h>
  177. #include <signal.h>
  178. #endif
  179. void PAssertFunc(const char * file, int line, PStandardAssertMessage msg)
  180. {
  181.   static const char * const textmsg[PMaxStandardAssertMessage] = {
  182.     NULL,
  183.     "Out of memory",
  184.     "Null pointer reference",
  185.     "Invalid cast to non-descendant class",
  186.     "Invalid array index",
  187.     "Invalid array element",
  188.     "Stack empty",
  189.     "Unimplemented function",
  190.     "Invalid parameter",
  191.     "Operating System error",
  192.     "File not open",
  193.     "Unsupported feature",
  194.     "Invalid or closed operating system window"
  195.   };
  196.   const char * theMsg;
  197.   char msgbuf[20];
  198.   if (msg < PMaxStandardAssertMessage)
  199.     theMsg = textmsg[msg];
  200.   else {
  201.     sprintf(msgbuf, "Error code: %i", msg);
  202.     theMsg = msgbuf;
  203.   }
  204.   PAssertFunc(file, line, theMsg);
  205. }
  206. #if PMEMORY_CHECK
  207. #undef malloc
  208. #undef realloc
  209. #undef free
  210. void * operator new(size_t nSize)
  211. {
  212.   return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);
  213. }
  214. void * operator new[](size_t nSize)
  215. {
  216.   return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);
  217. }
  218. void operator delete(void * ptr)
  219. {
  220.   PMemoryHeap::Deallocate(ptr, NULL);
  221. }
  222. void operator delete[](void * ptr)
  223. {
  224.   PMemoryHeap::Deallocate(ptr, NULL);
  225. }
  226. DWORD PMemoryHeap::allocationBreakpoint;
  227. char PMemoryHeap::Header::GuardBytes[NumGuardBytes];
  228. PMemoryHeap::Wrapper::Wrapper()
  229. {
  230.   // The following is done like this to get over brain dead compilers that cannot
  231.   // guarentee that a static global is contructed before it is used.
  232.   static PMemoryHeap real_instance;
  233.   instance = &real_instance;
  234.   if (instance->isDestroyed)
  235.     return;
  236. #if defined(_WIN32)
  237.   EnterCriticalSection(&instance->mutex);
  238. #elif defined(P_PTHREADS)
  239.   pthread_mutex_lock(&instance->mutex);
  240. #endif
  241. }
  242. PMemoryHeap::Wrapper::~Wrapper()
  243. {
  244.   if (instance->isDestroyed)
  245.     return;
  246. #if defined(_WIN32)
  247.   LeaveCriticalSection(&instance->mutex);
  248. #elif defined(P_PTHREADS)
  249.   pthread_mutex_unlock(&instance->mutex);
  250. #endif
  251. }
  252. PMemoryHeap::PMemoryHeap()
  253. {
  254.   isDestroyed = FALSE;
  255.   listHead = NULL;
  256.   listTail = NULL;
  257.   allocationRequest = 1;
  258.   firstRealObject = 0;
  259.   flags = 0;
  260.   allocFillChar = 'x5A';
  261.   freeFillChar = 'xA5';
  262.   currentMemoryUsage = 0;
  263.   peakMemoryUsage = 0;
  264.   currentObjects = 0;
  265.   peakObjects = 0;
  266.   totalObjects = 0;
  267.   for (PINDEX i = 0; i < Header::NumGuardBytes; i++)
  268.     Header::GuardBytes[i] = (i&1) == 0 ? 'x55' : 'xaa';
  269. #if defined(_WIN32)
  270.   InitializeCriticalSection(&mutex);
  271.   static PDebugStream debug;
  272.   leakDumpStream = &debug;
  273. #else
  274. #if defined(P_PTHREADS)
  275.   pthread_mutex_init(&mutex, NULL);
  276. #endif
  277.   leakDumpStream = &cerr;
  278. #endif
  279. }
  280. PMemoryHeap::~PMemoryHeap()
  281. {
  282.   isDestroyed = TRUE;
  283.   if (leakDumpStream != NULL) {
  284.     DumpStatistics(*leakDumpStream);
  285. #if !defined(_WIN32)
  286.     if (listTail != NULL && listTail->request >= firstRealObject) {
  287. #if defined(P_PTHREADS)
  288.       sigset_t blockedSignals;
  289.       sigemptyset(&blockedSignals);
  290.       sigaddset(&blockedSignals, SIGINT);
  291.       sigaddset(&blockedSignals, SIGQUIT);
  292.       sigaddset(&blockedSignals, SIGTERM);
  293.       pthread_sigmask(SIG_UNBLOCK, &blockedSignals, NULL);
  294. #endif
  295.       ::signal(SIGINT, SIG_DFL);
  296.       ::signal(SIGQUIT, SIG_DFL);
  297.       ::signal(SIGTERM, SIG_DFL);
  298.       *leakDumpStream << "nMemory leaks detected, press Enter to display . . ." << flush;
  299.       cin.get();
  300.     }
  301. #endif
  302.     DumpObjectsSince(firstRealObject, *leakDumpStream);
  303.   }
  304. #if defined(_WIN32)
  305.   DeleteCriticalSection(&mutex);
  306.   extern void PWaitOnExitConsoleWindow();
  307.   PWaitOnExitConsoleWindow();
  308. #elif defined(P_PTHREADS)
  309.   pthread_mutex_destroy(&mutex);
  310. #endif
  311. }
  312. void * PMemoryHeap::Allocate(size_t nSize, const char * file, int line, const char * className)
  313. {
  314.   Wrapper mem;
  315.   return mem->InternalAllocate(nSize, file, line, className);
  316. }
  317. void * PMemoryHeap::Allocate(size_t count, size_t size, const char * file, int line)
  318. {
  319.   Wrapper mem;
  320.   char oldFill = mem->allocFillChar;
  321.   mem->allocFillChar = '';
  322.   void * data = mem->InternalAllocate(count*size, file, line, NULL);
  323.   mem->allocFillChar = oldFill;
  324.   return data;
  325. }
  326. void * PMemoryHeap::InternalAllocate(size_t nSize, const char * file, int line, const char * className)
  327. {
  328.   if (isDestroyed)
  329.     return malloc(nSize);
  330.   Header * obj = (Header *)malloc(sizeof(Header) + nSize + sizeof(Header::GuardBytes));
  331.   if (obj == NULL) {
  332.     PAssertAlways(POutOfMemory);
  333.     return NULL;
  334.   }
  335.   if (firstRealObject == 0 && file != NULL && line > 0)
  336.     firstRealObject = allocationRequest;
  337.   PAssert(allocationRequest != allocationBreakpoint, "Break on memory allocation.");
  338.   currentMemoryUsage += nSize;
  339.   if (currentMemoryUsage > peakMemoryUsage)
  340.     peakMemoryUsage = currentMemoryUsage;
  341.   currentObjects++;
  342.   if (currentObjects > peakObjects)
  343.     peakObjects = currentObjects;
  344.   totalObjects++;
  345.   char * data = (char *)&obj[1];
  346.   obj->prev      = listTail;
  347.   obj->next      = NULL;
  348.   obj->size      = nSize;
  349.   obj->fileName  = file;
  350.   obj->line      = (WORD)line;
  351.   obj->className = className;
  352.   obj->request   = allocationRequest++;
  353.   obj->flags     = flags;
  354.   memcpy(obj->guard, obj->GuardBytes, sizeof(obj->guard));
  355.   memset(data, allocFillChar, nSize);
  356.   memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard));
  357.   if (listTail != NULL)
  358.     listTail->next = obj;
  359.   listTail = obj;
  360.   if (listHead == NULL)
  361.     listHead = obj;
  362.   return data;
  363. }
  364. void * PMemoryHeap::Reallocate(void * ptr, size_t nSize, const char * file, int line)
  365. {
  366.   if (ptr == NULL)
  367.     return Allocate(nSize, file, line, NULL);
  368.   if (nSize == 0) {
  369.     Deallocate(ptr, NULL);
  370.     return NULL;
  371.   }
  372.   Wrapper mem;
  373.   if (mem->isDestroyed)
  374.     return realloc(ptr, nSize);
  375.   if (mem->InternalValidate(ptr, NULL, mem->leakDumpStream) != Ok)
  376.     return NULL;
  377.   Header * obj = (Header *)realloc(((Header *)ptr)-1, sizeof(Header) + nSize + sizeof(obj->guard));
  378.   if (obj == NULL) {
  379.     PAssertAlways(POutOfMemory);
  380.     return NULL;
  381.   }
  382.   PAssert(mem->allocationRequest != allocationBreakpoint, "Break on memory allocation.");
  383.   mem->currentMemoryUsage -= obj->size;
  384.   mem->currentMemoryUsage += nSize;
  385.   if (mem->currentMemoryUsage > mem->peakMemoryUsage)
  386.     mem->peakMemoryUsage = mem->currentMemoryUsage;
  387.   char * data = (char *)&obj[1];
  388.   memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard));
  389.   obj->size      = nSize;
  390.   obj->fileName  = file;
  391.   obj->line      = (WORD)line;
  392.   obj->request   = mem->allocationRequest++;
  393.   if (obj->prev != NULL)
  394.     obj->prev->next = obj;
  395.   else
  396.     mem->listHead = obj;
  397.   if (obj->next != NULL)
  398.     obj->next->prev = obj;
  399.   else
  400.     mem->listTail = obj;
  401.   return data;
  402. }
  403. void PMemoryHeap::Deallocate(void * ptr, const char * className)
  404. {
  405.   if (ptr == NULL)
  406.     return;
  407.   Wrapper mem;
  408.   if (mem->isDestroyed) {
  409.     free(ptr);
  410.     return;
  411.   }
  412.   if (mem->InternalValidate(ptr, className, mem->leakDumpStream) != Ok) {
  413.     free(ptr);
  414.     return;
  415.   }
  416.   Header * obj = ((Header *)ptr)-1;
  417.   if (obj->prev != NULL)
  418.     obj->prev->next = obj->next;
  419.   else
  420.     mem->listHead = obj->next;
  421.   if (obj->next != NULL)
  422.     obj->next->prev = obj->prev;
  423.   else
  424.     mem->listTail = obj->prev;
  425.   mem->currentMemoryUsage -= obj->size;
  426.   mem->currentObjects--;
  427.   memset(ptr, mem->freeFillChar, obj->size);  // Make use of freed data noticable
  428.   free(obj);
  429. }
  430. PMemoryHeap::Validation PMemoryHeap::Validate(void * ptr,
  431.                                               const char * className,
  432.                                               ostream * error)
  433. {
  434.   Wrapper mem;
  435.   return mem->InternalValidate(ptr, className, error);
  436. }
  437. PMemoryHeap::Validation PMemoryHeap::InternalValidate(void * ptr,
  438.                                                       const char * className,
  439.                                                       ostream * error)
  440. {
  441.   if (isDestroyed)
  442.     return Bad;
  443.   if (ptr == NULL)
  444.     return Trashed;
  445.   Header * obj = ((Header *)ptr)-1;
  446.   if (memcmp(obj->guard, obj->GuardBytes, sizeof(obj->guard)) != 0) {
  447.     if (error != NULL)
  448.       *error << "Underrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl;
  449.     return Bad;
  450.   }
  451.   
  452.   if (memcmp((char *)ptr+obj->size, obj->GuardBytes, sizeof(obj->guard)) != 0) {
  453.     if (error != NULL)
  454.       *error << "Overrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl;
  455.     return Bad;
  456.   }
  457.   
  458.   if (obj->className != NULL && strcmp(obj->className, className) != 0) {
  459.     if (error != NULL)
  460.       *error << "PObject " << ptr << '[' << obj->size << "] #" << obj->request
  461.              << " allocated as "" << obj->className
  462.              << "" and should be "" << className << ""." << endl;
  463.     return Bad;
  464.   }
  465.   Header * forward = obj;
  466.   Header * backward = obj;
  467.   while (forward->next != NULL && backward->prev != NULL) {
  468.     forward = forward->next;
  469.     backward = backward->prev;
  470.   }
  471.   if (forward != listTail && backward != listHead) {
  472.     if (error != NULL)
  473.       *error << "Block " << ptr << '[' << obj->size << "] #" << obj->request
  474.              << " not in heap!" << endl;
  475.     return Trashed;
  476.   }
  477.   return Ok;
  478. }
  479. void PMemoryHeap::SetIgnoreAllocations(BOOL ignore)
  480. {
  481.   Wrapper mem;
  482.   if (ignore)
  483.     mem->flags |= NoLeakPrint;
  484.   else
  485.     mem->flags &= ~NoLeakPrint;
  486. }
  487. void PMemoryHeap::DumpStatistics()
  488. {
  489.   Wrapper mem;
  490.   if (mem->leakDumpStream != NULL)
  491.     mem->InternalDumpStatistics(*mem->leakDumpStream);
  492. }
  493. void PMemoryHeap::DumpStatistics(ostream & strm)
  494. {
  495.   Wrapper mem;
  496.   mem->InternalDumpStatistics(strm);
  497. }
  498. void PMemoryHeap::InternalDumpStatistics(ostream & strm)
  499. {
  500.   strm << "nCurrent memory usage: " << currentMemoryUsage << " bytes";
  501.   if (currentMemoryUsage > 2048)
  502.     strm << ", " << (currentMemoryUsage+1023)/1024 << "kb";
  503.   if (currentMemoryUsage > 2097152)
  504.     strm << ", " << (currentMemoryUsage+1048575)/1048576 << "Mb";
  505.   strm << ".nCurrent objects count: " << currentObjects
  506.        << "nPeak memory usage: " << peakMemoryUsage << " bytes";
  507.   if (peakMemoryUsage > 2048)
  508.     strm << ", " << (peakMemoryUsage+1023)/1024 << "kb";
  509.   if (peakMemoryUsage > 2097152)
  510.     strm << ", " << (peakMemoryUsage+1048575)/1048576 << "Mb";
  511.   strm << ".nPeak objects created: " << peakObjects
  512.        << "nTotal objects created: " << totalObjects
  513.        << 'n' << endl;
  514. }
  515. DWORD PMemoryHeap::GetAllocationRequest()
  516. {
  517.   Wrapper mem;
  518.   return mem->allocationRequest;
  519. }
  520. void PMemoryHeap::SetAllocationBreakpoint(DWORD point)
  521. {
  522.   allocationBreakpoint = point;
  523. }
  524. void PMemoryHeap::DumpObjectsSince(DWORD objectNumber)
  525. {
  526.   Wrapper mem;
  527.   if (mem->leakDumpStream != NULL)
  528.     mem->InternalDumpObjectsSince(objectNumber, *mem->leakDumpStream);
  529. }
  530. void PMemoryHeap::DumpObjectsSince(DWORD objectNumber, ostream & strm)
  531. {
  532.   Wrapper mem;
  533.   mem->InternalDumpObjectsSince(objectNumber, strm);
  534. }
  535. void PMemoryHeap::InternalDumpObjectsSince(DWORD objectNumber, ostream & strm)
  536. {
  537.   for (Header * obj = listHead; obj != NULL; obj = obj->next) {
  538.     if (obj->request < objectNumber || (obj->flags&NoLeakPrint) != 0)
  539.       continue;
  540.     BYTE * data = (BYTE *)&obj[1];
  541.     if (obj->fileName != NULL)
  542.       strm << obj->fileName << '(' << obj->line << ") : ";
  543.     strm << '#' << obj->request << ' ' << (void *)data << " [" << obj->size << "] ";
  544.     if (obj->className != NULL)
  545.       strm << '"' << obj->className << "" ";
  546.     strm << 'n' << hex << setfill('0') << PBYTEArray(data, PMIN(16, obj->size), FALSE)
  547.                  << dec << setfill(' ') << endl;
  548.   }
  549. }
  550. #endif
  551. const char * PObject::GetClass(unsigned) const
  552. {
  553.   return Class();
  554. }
  555. BOOL PObject::IsClass(const char * clsName) const
  556. {
  557.   return strcmp(clsName, Class()) == 0;
  558. }
  559. BOOL PObject::IsDescendant(const char * clsName) const
  560. {
  561.   return strcmp(clsName, Class()) == 0;
  562. }
  563. PObject::Comparison PObject::CompareObjectMemoryDirect(const PObject&obj) const
  564. {
  565.   int retval = memcmp(this, &obj, sizeof(PObject));
  566.   if (retval < 0)
  567.     return LessThan;
  568.   if (retval > 0)
  569.     return GreaterThan;
  570.   return EqualTo;
  571. }
  572. PObject * PObject::Clone() const
  573. {
  574.   PAssertAlways(PUnimplementedFunction);
  575.   return NULL;
  576. }
  577. PObject::Comparison PObject::Compare(const PObject & obj) const
  578. {
  579.   return (Comparison)CompareObjectMemoryDirect(obj);
  580. }
  581. void PObject::PrintOn(ostream & strm) const
  582. {
  583.   strm << GetClass();
  584. }
  585. void PObject::ReadFrom(istream &)
  586. {
  587. }
  588. PINDEX PObject::PreSerialise(PSerialiser &)
  589. {
  590.   return 0;
  591. }
  592. void PObject::Serialise(PSerialiser &)
  593. {
  594. }
  595. void PObject::UnSerialise(PUnSerialiser &)
  596. {
  597. }
  598. PINDEX PObject::HashFunction() const
  599. {
  600.   return 0;
  601. }
  602. ///////////////////////////////////////////////////////////////////////////////
  603. // Serialisation support
  604. PSerialRegistration * PSerialRegistration::creatorHashTable[
  605.                                            PSerialRegistration::HashTableSize];
  606. PINDEX PSerialRegistration::HashFunction(const char * className)
  607. {
  608.   PINDEX hash = (BYTE)className[0];
  609.   if (className[0] != '') {
  610.     hash += (BYTE)className[1];
  611.     if (className[1] != '')
  612.       hash += (BYTE)className[2];
  613.   }
  614.   return hash%HashTableSize;
  615. }
  616. PSerialRegistration::PSerialRegistration(const char * clsNam,
  617.                                                           CreatorFunction func)
  618.   : className(clsNam), creator(func)
  619. {
  620.   clash = NULL;
  621.   PINDEX hash = HashFunction(className);
  622.   if (creatorHashTable[hash] != NULL)
  623.     creatorHashTable[hash]->clash = this;
  624.   creatorHashTable[hash] = this;
  625. }
  626. PSerialRegistration::CreatorFunction
  627.                            PSerialRegistration::GetCreator(const char * clsNam)
  628. {
  629.   PINDEX hash = HashFunction(clsNam);
  630.   PSerialRegistration * reg = creatorHashTable[hash];
  631.   while (reg != NULL) {
  632.     if (strcmp(reg->className, clsNam) == 0)
  633.       return reg->creator;
  634.   }
  635.   return NULL;
  636. }
  637. PSerialiser::PSerialiser(ostream & strm)
  638.   : stream(strm)
  639. {
  640. }
  641. PSerialiser & PSerialiser::operator<<(PObject & obj)
  642. {
  643.   obj.Serialise(*this);
  644.   return *this;
  645. }
  646. PTextSerialiser::PTextSerialiser(ostream & strm, PObject & data)
  647.   : PSerialiser(strm)
  648. {
  649.   data.Serialise(*this);
  650. }
  651. PSerialiser & PTextSerialiser::operator<<(char)
  652.   { return *this; }
  653. PSerialiser & PTextSerialiser::operator<<(unsigned char)
  654.   { return *this; }
  655. PSerialiser & PTextSerialiser::operator<<(signed char)
  656.   { return *this; }
  657. PSerialiser & PTextSerialiser::operator<<(short)
  658.   { return *this; }
  659. PSerialiser & PTextSerialiser::operator<<(unsigned short)
  660.   { return *this; }
  661. PSerialiser & PTextSerialiser::operator<<(int)
  662.   { return *this; }
  663. PSerialiser & PTextSerialiser::operator<<(unsigned int)
  664.   { return *this; }
  665. PSerialiser & PTextSerialiser::operator<<(long)
  666.   { return *this; }
  667. PSerialiser & PTextSerialiser::operator<<(unsigned long)
  668.   { return *this; }
  669. PSerialiser & PTextSerialiser::operator<<(float)
  670.   { return *this; }
  671. PSerialiser & PTextSerialiser::operator<<(double)
  672.   { return *this; }
  673. PSerialiser & PTextSerialiser::operator<<(long double)
  674.   { return *this; }
  675. PSerialiser & PTextSerialiser::operator<<(const char *)
  676.   { return *this; }
  677. PSerialiser & PTextSerialiser::operator<<(const unsigned char *)
  678.   { return *this; }
  679. PSerialiser & PTextSerialiser::operator<<(const signed char *)
  680.   { return *this; }
  681. PSerialiser & PTextSerialiser::operator<<(PObject & obj)
  682.   { return PSerialiser::operator<<(obj); }
  683. PBinarySerialiser::PBinarySerialiser(ostream & strm, PObject & data)
  684.   : PSerialiser(strm)
  685. {
  686.   classesUsed = new PSortedStringList;
  687.   data.PreSerialise(*this);
  688.   stream << *classesUsed;
  689.   data.Serialise(*this);
  690. }
  691. PBinarySerialiser::~PBinarySerialiser()
  692. {
  693.   delete classesUsed;
  694. }
  695. PSerialiser & PBinarySerialiser::operator<<(char)
  696.   { return *this; }
  697. PSerialiser & PBinarySerialiser::operator<<(unsigned char)
  698.   { return *this; }
  699. PSerialiser & PBinarySerialiser::operator<<(signed char)
  700.   { return *this; }
  701. PSerialiser & PBinarySerialiser::operator<<(short)
  702.   { return *this; }
  703. PSerialiser & PBinarySerialiser::operator<<(unsigned short)
  704.   { return *this; }
  705. PSerialiser & PBinarySerialiser::operator<<(int)
  706.   { return *this; }
  707. PSerialiser & PBinarySerialiser::operator<<(unsigned int)
  708.   { return *this; }
  709. PSerialiser & PBinarySerialiser::operator<<(long)
  710.   { return *this; }
  711. PSerialiser & PBinarySerialiser::operator<<(unsigned long)
  712.   { return *this; }
  713. PSerialiser & PBinarySerialiser::operator<<(float)
  714.   { return *this; }
  715. PSerialiser & PBinarySerialiser::operator<<(double)
  716.   { return *this; }
  717. PSerialiser & PBinarySerialiser::operator<<(long double)
  718.   { return *this; }
  719. PSerialiser & PBinarySerialiser::operator<<(const char *)
  720.   { return *this; }
  721. PSerialiser & PBinarySerialiser::operator<<(const unsigned char *)
  722.   { return *this; }
  723. PSerialiser & PBinarySerialiser::operator<<(const signed char *)
  724.   { return *this; }
  725. PSerialiser & PBinarySerialiser::operator<<(PObject & obj)
  726.   { return PSerialiser::operator<<(obj); }
  727. PUnSerialiser::PUnSerialiser(istream & strm)
  728.   : stream(strm)
  729. {
  730. }
  731. PTextUnSerialiser::PTextUnSerialiser(istream & strm)
  732.   : PUnSerialiser(strm)
  733. {
  734. }
  735. PUnSerialiser & PTextUnSerialiser::operator>>(char &)
  736.   { return *this; }
  737. PUnSerialiser & PTextUnSerialiser::operator>>(unsigned char &)
  738.   { return *this; }
  739. PUnSerialiser & PTextUnSerialiser::operator>>(signed char &)
  740.   { return *this; }
  741. PUnSerialiser & PTextUnSerialiser::operator>>(short &)
  742.   { return *this; }
  743. PUnSerialiser & PTextUnSerialiser::operator>>(unsigned short &)
  744.   { return *this; }
  745. PUnSerialiser & PTextUnSerialiser::operator>>(int &)
  746.   { return *this; }
  747. PUnSerialiser & PTextUnSerialiser::operator>>(unsigned int &)
  748.   { return *this; }
  749. PUnSerialiser & PTextUnSerialiser::operator>>(long &)
  750.   { return *this; }
  751. PUnSerialiser & PTextUnSerialiser::operator>>(unsigned long &)
  752.   { return *this; }
  753. PUnSerialiser & PTextUnSerialiser::operator>>(float &)
  754.   { return *this; }
  755. PUnSerialiser & PTextUnSerialiser::operator>>(double &)
  756.   { return *this; }
  757. PUnSerialiser & PTextUnSerialiser::operator>>(long double &)
  758.   { return *this; }
  759. PUnSerialiser & PTextUnSerialiser::operator>>(char *)
  760.   { return *this; }
  761. PUnSerialiser & PTextUnSerialiser::operator>>(unsigned char *)
  762.   { return *this; }
  763. PUnSerialiser & PTextUnSerialiser::operator>>(signed char *)
  764.   { return *this; }
  765. PUnSerialiser & PTextUnSerialiser::operator>>(PObject &)
  766.   { return *this; }
  767. PBinaryUnSerialiser::PBinaryUnSerialiser(istream & strm)
  768.   : PUnSerialiser(strm)
  769. {
  770.   classesUsed = new PStringArray;
  771. }
  772. PBinaryUnSerialiser::~PBinaryUnSerialiser()
  773. {
  774.   delete classesUsed;
  775. }
  776. PUnSerialiser & PBinaryUnSerialiser::operator>>(char &)
  777.   { return *this; }
  778. PUnSerialiser & PBinaryUnSerialiser::operator>>(unsigned char &)
  779.   { return *this; }
  780. PUnSerialiser & PBinaryUnSerialiser::operator>>(signed char &)
  781.   { return *this; }
  782. PUnSerialiser & PBinaryUnSerialiser::operator>>(short &)
  783.   { return *this; }
  784. PUnSerialiser & PBinaryUnSerialiser::operator>>(unsigned short &)
  785.   { return *this; }
  786. PUnSerialiser & PBinaryUnSerialiser::operator>>(int &)
  787.   { return *this; }
  788. PUnSerialiser & PBinaryUnSerialiser::operator>>(unsigned int &)
  789.   { return *this; }
  790. PUnSerialiser & PBinaryUnSerialiser::operator>>(long &)
  791.   { return *this; }
  792. PUnSerialiser & PBinaryUnSerialiser::operator>>(unsigned long &)
  793.   { return *this; }
  794. PUnSerialiser & PBinaryUnSerialiser::operator>>(float &)
  795.   { return *this; }
  796. PUnSerialiser & PBinaryUnSerialiser::operator>>(double &)
  797.   { return *this; }
  798. PUnSerialiser & PBinaryUnSerialiser::operator>>(long double &)
  799.   { return *this; }
  800. PUnSerialiser & PBinaryUnSerialiser::operator>>(char *)
  801.   { return *this; }
  802. PUnSerialiser & PBinaryUnSerialiser::operator>>(unsigned char *)
  803.   { return *this; }
  804. PUnSerialiser & PBinaryUnSerialiser::operator>>(signed char *)
  805.   { return *this; }
  806. PUnSerialiser & PBinaryUnSerialiser::operator>>(PObject &)
  807.   { return *this; }
  808. ///////////////////////////////////////////////////////////////////////////////
  809. // General reference counting support
  810. PSmartPointer::PSmartPointer(const PSmartPointer & ptr)
  811. {
  812.   object = ptr.object;
  813.   if (object != NULL)
  814.     ++object->referenceCount;
  815. }
  816. PSmartPointer & PSmartPointer::operator=(const PSmartPointer & ptr)
  817. {
  818.   if (object == ptr.object)
  819.     return *this;
  820.   if (object != NULL && --object->referenceCount == 0)
  821.     delete object;
  822.   object = ptr.object;
  823.   if (object != NULL)
  824.     ++object->referenceCount;
  825.   return *this;
  826. }
  827. PSmartPointer::~PSmartPointer()
  828. {
  829.   if (object != NULL && --object->referenceCount == 0)
  830.     delete object;
  831. }
  832. PObject::Comparison PSmartPointer::Compare(const PObject & obj) const
  833. {
  834.   PAssert(obj.IsDescendant(PSmartPointer::Class()), PInvalidCast);
  835.   PSmartObject * other = ((const PSmartPointer &)obj).object;
  836.   if (object == other)
  837.     return EqualTo;
  838.   return object < other ? LessThan : GreaterThan;
  839. }
  840. ///////////////////////////////////////////////////////////////////////////////
  841. // Large integer support
  842. #ifdef P_NEEDS_INT64
  843. void PInt64__::Add(const PInt64__ & v)
  844. {
  845.   unsigned long old = low;
  846.   high += v.high;
  847.   low += v.low;
  848.   if (low < old)
  849.     high++;
  850. }
  851. void PInt64__::Sub(const PInt64__ & v)
  852. {
  853.   unsigned long old = low;
  854.   high -= v.high;
  855.   low -= v.low;
  856.   if (low > old)
  857.     high--;
  858. }
  859. void PInt64__::Mul(const PInt64__ & v)
  860. {
  861.   DWORD p1 = (low&0xffff)*(v.low&0xffff);
  862.   DWORD p2 = (low >> 16)*(v.low >> 16);
  863.   DWORD p3 = (high&0xffff)*(v.high&0xffff);
  864.   DWORD p4 = (high >> 16)*(v.high >> 16);
  865.   low = p1 + (p2 << 16);
  866.   high = (p2 >> 16) + p3 + (p4 << 16);
  867. }
  868. void PInt64__::Div(const PInt64__ & v)
  869. {
  870.   long double dividend = high;
  871.   dividend *=  4294967296.0;
  872.   dividend += low;
  873.   long double divisor = high;
  874.   divisor *=  4294967296.0;
  875.   divisor += low;
  876.   long double quotient = dividend/divisor;
  877.   low = quotient;
  878.   high = quotient/4294967296.0;
  879. }
  880. void PInt64__::Mod(const PInt64__ & v)
  881. {
  882.   PInt64__ t = *this;
  883.   t.Div(v);
  884.   t.Mul(t);
  885.   Sub(t);
  886. }
  887. void PInt64__::ShiftLeft(int bits)
  888. {
  889.   if (bits >= 32) {
  890.     high = low << (bits - 32);
  891.     low = 0;
  892.   }
  893.   else {
  894.     high <<= bits;
  895.     high |= low >> (32 - bits);
  896.     low <<= bits;
  897.   }
  898. }
  899. void PInt64__::ShiftRight(int bits)
  900. {
  901.   if (bits >= 32) {
  902.     low = high >> (bits - 32);
  903.     high = 0;
  904.   }
  905.   else {
  906.     low >>= bits;
  907.     low |= high << (32 - bits);
  908.     high >>= bits;
  909.   }
  910. }
  911. BOOL PInt64::Lt(const PInt64 & v) const
  912. {
  913.   if ((long)high < (long)v.high)
  914.     return TRUE;
  915.   if ((long)high > (long)v.high)
  916.     return FALSE;
  917.   if ((long)high < 0)
  918.     return (long)low > (long)v.low;
  919.   return (long)low < (long)v.low;
  920. }
  921. BOOL PInt64::Gt(const PInt64 & v) const
  922. {
  923.   if ((long)high > (long)v.high)
  924.     return TRUE;
  925.   if ((long)high < (long)v.high)
  926.     return FALSE;
  927.   if ((long)high < 0)
  928.     return (long)low < (long)v.low;
  929.   return (long)low > (long)v.low;
  930. }
  931. BOOL PUInt64::Lt(const PUInt64 & v) const
  932. {
  933.   if (high < v.high)
  934.     return TRUE;
  935.   if (high > v.high)
  936.     return FALSE;
  937.   return low < high;
  938. }
  939. BOOL PUInt64::Gt(const PUInt64 & v) const
  940. {
  941.   if (high > v.high)
  942.     return TRUE;
  943.   if (high < v.high)
  944.     return FALSE;
  945.   return low > high;
  946. }
  947. static void Out64(ostream & stream, PUInt64 num)
  948. {
  949.   char buf[25];
  950.   char * p = &buf[sizeof(buf)];
  951.   *--p = '';
  952.   switch (stream.flags()&ios::basefield) {
  953.     case ios::oct :
  954.       while (num != 0) {
  955.         *--p = (num&7) + '0';
  956.         num >>= 3;
  957.       }
  958.       break;
  959.     case ios::hex :
  960.       while (num != 0) {
  961.         *--p = (num&15) + '0';
  962.         if (*p > '9')
  963.           *p += 7;
  964.         num >>= 4;
  965.       }
  966.       break;
  967.     default :
  968.       while (num != 0) {
  969.         *--p = num%10 + '0';
  970.         num /= 10;
  971.       }
  972.   }
  973.   if (*p == '')
  974.     *--p = '0';
  975.   stream << p;
  976. }
  977. ostream & operator<<(ostream & stream, const PInt64 & v)
  978. {
  979.   if (v >= 0)
  980.     Out64(stream, v);
  981.   else {
  982.     int w = stream.width();
  983.     stream.put('-');
  984.     if (w > 0)
  985.       stream.width(w-1);
  986.     Out64(stream, -v);
  987.   }
  988.   return stream;
  989. }
  990. ostream & operator<<(ostream & stream, const PUInt64 & v)
  991. {
  992.   Out64(stream, v);
  993.   return stream;
  994. }
  995. static PUInt64 Inp64(istream & stream)
  996. {
  997.   int base;
  998.   switch (stream.flags()&ios::basefield) {
  999.     case ios::oct :
  1000.       base = 8;
  1001.       break;
  1002.     case ios::hex :
  1003.       base = 16;
  1004.       break;
  1005.     default :
  1006.       base = 10;
  1007.   }
  1008.   if (isspace(stream.peek()))
  1009.     stream.get();
  1010.   PInt64 num = 0;
  1011.   while (isxdigit(stream.peek())) {
  1012.     int c = stream.get() - '0';
  1013.     if (c > 9)
  1014.       c -= 7;
  1015.     if (c > 9)
  1016.       c -= 32;
  1017.     num = num*base + c;
  1018.   }
  1019.   return num;
  1020. }
  1021. istream & operator>>(istream & stream, PInt64 & v)
  1022. {
  1023.   if (isspace(stream.peek()))
  1024.     stream.get();
  1025.   switch (stream.peek()) {
  1026.     case '-' :
  1027.       stream.ignore();
  1028.       v = -(PInt64)Inp64(stream);
  1029.       break;
  1030.     case '+' :
  1031.       stream.ignore();
  1032.     default :
  1033.       v = (PInt64)Inp64(stream);
  1034.   }
  1035.   return stream;
  1036. }
  1037. istream & operator>>(istream & stream, PUInt64 & v)
  1038. {
  1039.   v = Inp64(stream);
  1040.   return stream;
  1041. }
  1042. #endif
  1043. // End Of File ///////////////////////////////////////////////////////////////