home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UDynDynArray.cp < prev    next >
Encoding:
Text File  |  1994-03-16  |  20.7 KB  |  817 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UDynDynArray.cp
  3.  
  4. #include "UDynDynArray.h"
  5. #include "Tools.h"
  6. #include "StreamTools.h"
  7.  
  8. #pragma segment MyArray
  9.  
  10. #define qDebugDynDyn qDebug & 0
  11. #define qDebugDynDynSpecial qDebug & 0
  12. #define qDebugDynDynIntense qDebug & 0
  13. #define qDebugStream qDebug & 0
  14.  
  15. #define qDebugLogHandleResize qDebug & 0
  16.  
  17. const long kCurrentDynDynVersion = 1;
  18. const long kMinDynDynVersion = 1;
  19.  
  20. const long kIndexEntrySize = 2 * sizeof(long);
  21. //========================================================================
  22.  
  23. CChunkyHandle::CChunkyHandle()
  24. {
  25.     fHandleH = nil;
  26.     fSize = 0;
  27.     fAllocSize = 0;
  28.     fHandleIsLocked = false;
  29.     fChunk = 4;
  30. }
  31.  
  32. void CChunkyHandle::IChunkyHandle(long chunk)
  33. {
  34.     if (qDebug && chunk <= 0)
  35.         ProgramBreak("Bad chunk");
  36.     fChunk = chunk;
  37.     fHandleH = NewPermHandle(0);
  38. }
  39.  
  40. CChunkyHandle::~CChunkyHandle()
  41. {
  42.     fHandleH = DisposeIfHandle(fHandleH);
  43. }
  44.  
  45. void CChunkyHandle::SizeToFit()
  46. {
  47.     if (fAllocSize == fSize)
  48.         return;
  49. #if qDebugLogHandleResize
  50.     fprintf(stderr, "ChunckSizeToFit: %ld -> %ld\n", fAllocSize, fSize);
  51. #endif
  52.     SetHandleSize(fHandleH, fSize);
  53.     if (qDebug && MemError() != noErr) 
  54.         ProgramBreak("MemError() after DownSizing");
  55.     fAllocSize = fSize;
  56. }
  57.  
  58. void CChunkyHandle::SetNeededSize(long needed)
  59. {
  60.     if (qDebug && needed < 0)
  61.         ProgramBreak("needed < 0");
  62.     if (needed <= fAllocSize && fAllocSize - needed <= 2 * fChunk)
  63.     {
  64.         fSize = needed;
  65.         if (qDebugDynDynIntense)
  66.             SanityCheck();
  67.         return;
  68.     }
  69.     long newAllocSize = (needed + fChunk) - (needed + fChunk) % fChunk;
  70.     if (newAllocSize == 0)
  71.     {
  72.         newAllocSize = fChunk;
  73.         // else we'll do SetSize(0)/SetSize(1024) when adding/deleting
  74.         // the first element from the list
  75.     }
  76.     if (qDebugDynDynIntense && newAllocSize < needed)
  77.         ProgramBreak("newAllocSize < needed");
  78. #if qDebugLogHandleResize
  79.     fprintf(stderr, "Chunckresize: %ld -> %ld\n", fAllocSize, newAllocSize);
  80. #endif
  81.     if (newAllocSize > fAllocSize)
  82.         SetPermHandleSize(fHandleH, newAllocSize);
  83.     else
  84.     {
  85.         SetHandleSize(fHandleH, newAllocSize);
  86.         if (qDebug && MemError() != noErr) 
  87.             ProgramBreak("MemError() after DownSizing");
  88.     }
  89.     fAllocSize = newAllocSize;
  90.     fSize = needed;
  91.     if (qDebugDynDynIntense)
  92.         SanityCheck();
  93. }
  94.  
  95. void CChunkyHandle::DeltaSize(long delta)
  96. {
  97.     SetNeededSize(fSize + delta);
  98. }
  99.  
  100. void CChunkyHandle::DeleteAll()
  101. {
  102.     SetNeededSize(0);
  103. }
  104.  
  105. void CChunkyHandle::MakeGap(long offset, long gaplen)
  106. {
  107. #if qDebug
  108.     if (offset < 0 || gaplen < 0 || offset > fSize)
  109.         ProgramBreak("Bad gap");
  110. #endif
  111.     long oldSize = fSize;
  112.     long movebytes = oldSize - offset;
  113.     SetNeededSize(fSize + gaplen);
  114.     if (movebytes)
  115.     {
  116.         Ptr fromP = PtrAtOffset(offset);
  117.         Ptr toP = fromP + gaplen;
  118.         if (qDebug && offset + gaplen + movebytes > fSize)
  119.             ProgramBreak("Bad calc");
  120.         MyBlockMove(fromP, toP, movebytes);
  121.     }
  122. #if qDebug
  123.     BlockSet(PtrAtOffset(offset), gaplen, 0xF1);
  124. #endif
  125. }
  126.  
  127. void CChunkyHandle::DeleteGap(long offset, long gaplen)
  128. {
  129. #if qDebug
  130.     if (offset < 0 || gaplen < 0 || offset + gaplen > fSize)
  131.         ProgramBreak("Bad gap");
  132. #endif
  133.     long oldSize = fSize;
  134.     long movebytes = oldSize - offset - gaplen;
  135.     if (movebytes)
  136.     {
  137.         Ptr toP = PtrAtOffset(offset);
  138.         Ptr fromP = toP + gaplen;
  139.         if (qDebug && offset + gaplen + movebytes > fSize)
  140.             ProgramBreak("Bad calc");
  141.         MyBlockMove(fromP, toP, movebytes);
  142.     }
  143.     SetNeededSize(fSize - gaplen);
  144. }
  145.  
  146. void CChunkyHandle::AppendChar(char ch)
  147. {
  148.     SetNeededSize(fSize + 1);
  149.     *(*fHandleH + fSize - 1) = ch;
  150. }
  151.  
  152. Boolean CChunkyHandle::LockHandle(Boolean newLock, Boolean moveHigh)
  153. {
  154.     if (newLock == fHandleIsLocked) 
  155.         return newLock;
  156. #if qDebugDynDyn
  157.     fprintf(stderr, "CChunkyHandle::LockHandle() at $%lx, ", long(this));
  158.     fprintf(stderr, "%slocked -> ", fHandleIsLocked ? "" : "un");
  159.     fprintf(stderr, "%slocked", newLock ? "" : "un");
  160.     fprintf(stderr, "%s\n", moveHigh ? ", moveHigh" : "");
  161. #endif
  162.     fHandleIsLocked = newLock;
  163.     if (newLock)
  164.         if (moveHigh)
  165.             HLockHi(fHandleH);
  166.         else
  167.             HLock(fHandleH);
  168.     else
  169.         HUnlock(fHandleH);
  170. }
  171.  
  172. void CChunkyHandle::DoRead(TStream *aStream)
  173. {
  174.     LockHandle(false, false);
  175.     MyStreamReadHandle(aStream, fHandleH);
  176.     fSize = GetHandleSize(fHandleH);
  177.     fAllocSize = fSize;
  178. }
  179.  
  180. void CChunkyHandle::DoWrite(TStream *aStream)
  181. {
  182.     SizeToFit();
  183. #if qDebugStream
  184.     long oldSize = aStream->GetPosition();
  185. #endif    
  186.     MyStreamWriteHandle(aStream, fHandleH);
  187. #if qDebugStream
  188.     long size = aStream->GetPosition() - oldSize;
  189.     fprintf(stderr, "Chunck at $%lx: stream write: %ld -> %ld = %ld\n", long(this), oldSize, aStream->GetPosition(), size);
  190. #endif
  191. }
  192.  
  193. long CChunkyHandle::NeededDiskSpace()
  194. {
  195.     // Break the implementation of MyStreamSizeOfHandle as it requires me to resize the handle
  196.     // and this will cause every bit of speed to disappear as this function is called each time
  197.     // an element is saved
  198.     long size = (fSize + 3) & ~3;
  199.     size += sizeof(long) + sizeof(long);
  200. //    long size = MyStreamSizeOfHandle(fHandleH);
  201. #if qDebugStream
  202.     fprintf(stderr, "Chunck at $%lx: stream get size = %ld\n", long(this), size);
  203. #endif
  204.     return size;
  205. }
  206.  
  207. void CChunkyHandle::DebugDump(Boolean /* verbose */)
  208. {
  209. #if qDebug
  210.     fprintf(stderr, "  CChunkyHandle: fSize = %ld, fAllocSize = %ld, fChunk = %ld, lock = %ld, ghs = %ld\n", fSize, fAllocSize, fChunk, fHandleIsLocked, (fHandleH?GetHandleSize(fHandleH):-1));
  211. #endif
  212. }
  213.  
  214. Boolean CChunkyHandle::SanityCheck()
  215. {
  216. #if qDebug
  217.     if (!fHandleH)
  218.     {
  219.         fprintf(stderr, "CChunkyHandle::SanityCheck, Missing handle\n");
  220.         return false;
  221.     }
  222.     if (!VerboseIsHandle(fHandleH))
  223.         ProgramBreak("Ups, real bad handle");
  224.     if (fSize < 0 || fAllocSize < 0 || fSize > fAllocSize)
  225.     {
  226.         fprintf(stderr, "CChunkyHandle::SanityCheck, bad sizes: fSize  = %ld, fAllocSize = %ld\n", fSize, fAllocSize);
  227.         return false;
  228.     }
  229.     long ghs = GetHandleSize(fHandleH);
  230.     if (ghs != fAllocSize)
  231.     {
  232.         fprintf(stderr, "CChunkyHandle::SanityCheck, GetHandleSize() = %ld  !=  fAllocSize == %ld\n", ghs, fAllocSize);
  233.         return false;
  234.     }
  235.     if (fHandleIsLocked)
  236.         fprintf(stderr, "CChunkyHandle::SanityCheck, WARNING: handle is locked\n");
  237. #endif
  238.     return true;
  239. }
  240.  
  241. //========================================================================
  242.  
  243. PDynDynArray::PDynDynArray()
  244.     : fIndex(), fData()
  245. {
  246. #if qDebugDynDyn
  247.     fprintf(stderr, "PDynDynArray::PDynDynArray() at $%lx\n", long(this));
  248. #endif
  249.     if (qDebug) FailNonPtrObject(this);
  250. }
  251.  
  252. void PDynDynArray::IDynDynArray(long allocChunk)
  253. {
  254.     if (qDebug) FailNonPtrObject(this);
  255.     FailInfo fi;
  256.     if (fi.Try())
  257.     {
  258.         fIndex.IChunkyHandle(128 * 4);
  259.         fData.IChunkyHandle(allocChunk);
  260. #if qDebugDynDyn
  261.         fprintf(stderr, "PDynDynArray::IDynDynArray() at $%lx\n", long(this));
  262. #endif
  263.         fi.Success();
  264.     }
  265.     else // fail
  266.     {
  267.         delete this;
  268.         fi.ReSignal();
  269.     }
  270. }
  271.  
  272. PDynDynArray::~PDynDynArray()
  273. {
  274.     if (qDebug) FailNonPtrObject(this);
  275. #if qDebugDynDyn
  276.     fprintf(stderr, "PDynDynArray::~PDynDynArray() at $%lx, had %ld items\n", long(this), MySize());
  277. #endif
  278. }
  279.  
  280. void PDynDynArray::DoRead(TStream *aStream)
  281. {
  282.     if (qDebug) FailNonPtrObject(this);
  283.     long version = aStream->ReadLong();
  284.     MyStreamCheckVersion(version, kMinDynDynVersion, kCurrentDynDynVersion, "PDynDynArray");
  285.     fData.DoRead(aStream);
  286.     fIndex.DoRead(aStream);
  287. #if qDebugDynDyn
  288.     fprintf(stderr, "PDynDynArray::DoRead() at $%lx, read %ld items\n", long(this), MySize());
  289. #endif
  290. #if qDebug | qDebugDynDynIntense
  291.     PDynDynArray::SanityCheck();
  292. #endif
  293. }
  294.  
  295. void PDynDynArray::DoWrite(TStream *aStream)
  296. {
  297.     if (qDebug) FailNonPtrObject(this);
  298. #if qDebugDynDynIntense
  299.     PDynDynArray::SanityCheck();
  300. #endif
  301.     aStream->WriteLong(kCurrentDynDynVersion);
  302.     fData.DoWrite(aStream);
  303.     fIndex.DoWrite(aStream);
  304. #if qDebugDynDyn
  305.     fprintf(stderr, "PDynDynArray::DoWrite() at $%lx, wrote %ld items\n", long(this), MySize());
  306. #endif
  307. }
  308.  
  309. long PDynDynArray::NeededDiskSpace()
  310. {
  311.     if (qDebug) FailNonPtrObject(this);
  312.     return    sizeof(long) +                                    // version number
  313.                     fData.NeededDiskSpace() +
  314.                     fIndex.NeededDiskSpace();
  315. }
  316.  
  317. void PDynDynArray::DeleteAll()
  318. {
  319.     if (qDebug) FailNonPtrObject(this);
  320. #if qDebugDynDynIntense
  321.     PDynDynArray::SanityCheck();
  322. #endif
  323. #if qDebugDynDyn
  324.     fprintf(stderr, "PDynDynArray::DeleteAll() at $%lx, deleted %ld items\n", long(this), MySize());
  325. #endif
  326.     fIndex.DeleteAll();
  327.     fData.DeleteAll();
  328. #if qDebugDynDynIntense
  329.     PDynDynArray::SanityCheck();
  330. #endif
  331. }
  332.  
  333. ArrayIndex PDynDynArray::CreateNewElement(long size)
  334. {
  335.     if (qDebug) FailNonPtrObject(this);
  336. #if qDebugDynDynIntense
  337.     PDynDynArray::SanityCheck();
  338. #endif
  339.     if (qDebug && size < 0)
  340.         ProgramBreak("size < 0");
  341. // should I unlock fDataH if it's locked? I do that now.
  342.     if (fData.LockHandle(false, false))
  343.         if (qDebug) ProgramBreak("Data handle was locked ???");
  344. #if qDebugDynDynSpecial
  345.     fprintf(stderr, "PDynDynArray::CreateNewElement() at $%lx\n", long(this));
  346.     fprintf(stderr, "-   no elem: %ld, new element size = %ld, ", MySize(), size);
  347. #endif
  348.     FailInfo fi;
  349.     if (fi.Try()) 
  350.     {
  351.         long oldDataLen = fData.GetSize();
  352.         fData.DeltaSize(size);
  353.         fIndex.DeltaSize(kIndexEntrySize);
  354.         long indexOffset = GetIndexOffset(MySize());
  355.         long *indexEntry = (long*)fIndex.PtrAtOffset(indexOffset);
  356.         *indexEntry++ = oldDataLen;
  357.         *indexEntry = size;
  358. #if qDebugDynDynIntense
  359.         PDynDynArray::SanityCheck();
  360. #endif
  361.         fi.Success();
  362.         return MySize();
  363.     }
  364.     else 
  365.     {
  366.         // no recovery is needed as the last failable statement is the 
  367.         // resizing of fIndex which holds the size of the array
  368.         fi.ReSignal();
  369.     }
  370. }
  371.  
  372. Boolean PDynDynArray::LockDataHandle(Boolean newLock, Boolean moveHigh)
  373. {
  374.     if (qDebug) FailNonPtrObject(this);
  375.     return fData.LockHandle(newLock, moveHigh);
  376. }
  377.  
  378. void PDynDynArray::DeleteElementAt(ArrayIndex index)
  379. {
  380.     if (qDebug) FailNonPtrObject(this);
  381. #if qDebugDynDynIntense
  382.     PDynDynArray::SanityCheck();
  383. #endif
  384.     if (index < 1 || index > MySize())
  385.     {
  386. #if qDebug
  387.         fprintf(stderr, "index = %ld out of range: 1 - %ld", index, MySize());
  388.         ProgramBreak(gEmptyString);
  389. #endif
  390.         return;
  391.     }
  392.     FailInfo fi;
  393.     if (fi.Try()) 
  394.     {
  395.         long dataOffset = GetElementOffset(index);
  396.         long dataLen = GetElementSize(index);
  397.         long indexOffset = GetIndexOffset(index);
  398.         long oldSize = MySize();
  399. #if qDebugDynDynSpecial
  400.         fprintf(stderr, "PDynDynArray::DeleteElementAt() at $%lx, index = %ld\n", long(this), index);
  401.         fprintf(stderr, "-  element size: %ld, no array elements: %ld\n", dataLen, MySize());
  402. #endif
  403.         // kill the index entry
  404.         fIndex.DeleteGap(indexOffset, kIndexEntrySize);
  405.         if (index < oldSize)  // if not last element, update the offsets for the rest of the elements
  406.         {
  407.             long *iP = (long*)fIndex.PtrAtOffset(indexOffset);
  408.             for (ArrayIndex i = index; i < oldSize; i++) // we have delete it now, so i < oldSize
  409.             {
  410.                 *iP++ -= dataLen; // adjust offset
  411.                 ++iP; // jump past length
  412.             }
  413.         }
  414.         // kill the data
  415.         fData.DeleteGap(dataOffset, dataLen);
  416. #if qDebugDynDynSpecial
  417.         fprintf(stderr, "After DeleteElementAt:\n");
  418.         DebugDump(false);
  419. #endif
  420. #if qDebugDynDynIntense
  421.         PDynDynArray::SanityCheck();
  422. #endif
  423.         fi.Success();
  424.     }
  425.     else // fail
  426.     {
  427.         DebugStr("This should never happend: failure in PDynDynArray::DeleteElementAt()");
  428.         fi.ReSignal();
  429.     }
  430. }
  431.  
  432. void PDynDynArray::SetElementSize(ArrayIndex index, long newElementSize)
  433. {
  434.     if (qDebug) FailNonPtrObject(this);
  435. #if qDebugDynDynIntense
  436.     PDynDynArray::SanityCheck();
  437. #endif
  438.     long oldElementSize = GetElementSize(index);
  439.     if (newElementSize == oldElementSize)
  440.         return; // no change in size
  441. #if qDebugDynDynSpecial
  442.     fprintf(stderr, "PDynDynArray::SetElementSize() at $%lx, index = %ld, size %ld -> %ld\n", long(this), index, oldElementSize, newElementSize);
  443. #endif
  444.     if (index < 1 || index > MySize())
  445.     {
  446. #if qDebug
  447.         fprintf(stderr, "index = %ld out of range: 1 - %ld", index, MySize());
  448.         ProgramBreak(gEmptyString);
  449. #endif
  450.         return;
  451.     }
  452. #if qDebug
  453.     if (newElementSize < 0 || newElementSize > 10 * 1024 * 1024)
  454.     {
  455.         fprintf(stderr, "Crazy element size: %ld\n", newElementSize);
  456.         ProgramBreak(gEmptyString);
  457.         return;
  458.     }
  459. #endif
  460.     FailInfo fi;
  461.     if (fi.Try()) 
  462.     {
  463.         long dataOffset = GetElementOffset(index);
  464.         long deltaElementSize = newElementSize - oldElementSize;
  465.         long oldDataLen = fData.GetSize();
  466.         long newDataLen = oldDataLen + deltaElementSize;
  467. #if qDebugDynDynSpecial
  468.         fprintf(stderr, "-  ΔelmSize: %ld, oldDataLen = %ld, newDataLen = %ld\n", deltaElementSize, oldDataLen, newDataLen);
  469. #endif
  470.         if (deltaElementSize > 0)
  471.             fData.MakeGap(dataOffset + oldElementSize, deltaElementSize);
  472.         else
  473.             fData.DeleteGap(dataOffset + newElementSize, -deltaElementSize);
  474.         // adjust rest of offsets
  475.         long indexOffset = GetIndexOffset(index);
  476.         long *lP = (long*)fIndex.PtrAtOffset(indexOffset);
  477.         lP++; // offset
  478.         *lP++ = newElementSize; // new length
  479.         if (index < MySize()) // if not last element, then adjust rest of offsets
  480.         {
  481.             for (ArrayIndex i = index + 1; i <= MySize(); i++)
  482.             {
  483.                 *lP++ += deltaElementSize; // adjust offset
  484.                 lP++; // no change in length
  485.             }
  486.         }
  487. #if qDebugDynDynSpecial
  488.         fprintf(stderr, "-  adjusted %ld index entries (offset += %ld bytes)\n", MySize() - index + 1, deltaElementSize);
  489. #endif
  490. #if qDebugDynDynSpecial
  491.         fprintf(stderr, "After SetElementSize:\n");
  492.         DebugDump(false);
  493. #endif
  494. #if qDebugDynDynIntense
  495.         PDynDynArray::SanityCheck();
  496. #endif
  497.         fi.Success();
  498.     }
  499.     else // fail
  500.     {
  501.         fi.ReSignal();
  502.     }
  503. }
  504.  
  505. void PDynDynArray::InsertElementBefore(ArrayIndex index) // buggy, I think
  506. {
  507.     if (qDebug) FailNonPtrObject(this);
  508. #if qDebugDynDynSpecial
  509.     fprintf(stderr, "PDynDynArray::InsertElementBefore() at $%lx, index = %ld, MySize() = %ld\n", long(this), index, MySize());
  510. #endif
  511. #if qDebugDynDynIntense
  512.     PDynDynArray::SanityCheck();
  513. #endif
  514.     if (index > MySize())
  515.     {
  516. #if qDebugDynDynSpecial
  517.         fprintf(stderr, "-  appending new item to list\n");
  518. #endif
  519.         CreateNewElement(0);
  520.         return;
  521.     }
  522.     if (qDebug && index < 1)
  523.         ProgramBreak("-  index < 1 *****");
  524.     long dataOffset = GetElementOffset(index);
  525.     long indexOffset = GetIndexOffset(index);
  526.     fIndex.MakeGap(indexOffset, kIndexEntrySize);
  527.     long *lP = (long*) fIndex.PtrAtOffset(indexOffset);
  528.     *lP++ = dataOffset;
  529.     *lP = 0;
  530. #if qDebugDynDynIntense
  531.     PDynDynArray::SanityCheck();
  532. #endif
  533. }
  534.  
  535. void PDynDynArray::InsertElementBefore(ArrayIndex index, const void *elementPtr, long size)
  536. {
  537.     if (qDebug) FailNonPtrObject(this);
  538.     VOLATILE(index);
  539.     InsertElementBefore(index);
  540.     FailInfo fi;
  541.     if (fi.Try())
  542.     {
  543.         SetElementSize(index, size);
  544.         BytesMove(elementPtr, ComputeAddress(index), size);
  545.         fi.Success();
  546.     }
  547.     else // fail
  548.     {
  549.         // remove the empty element
  550.         DeleteElementAt(index);
  551.         fi.ReSignal();
  552.     }
  553. }
  554.  
  555. void PDynDynArray::InsertLast(const void *elementPtr, long size)
  556. {
  557.     if (qDebug) FailNonPtrObject(this);
  558.     ArrayIndex index = CreateNewElement(size);
  559.     Ptr p = ComputeAddress(index);
  560.     BytesMove(elementPtr, p, size);
  561. }
  562.  
  563. ArrayIndex PDynDynArray::GetSize()
  564. {
  565.     if (qDebug) FailNonPtrObject(this);
  566.     return MySize();
  567. }
  568.  
  569. long PDynDynArray::GetDataAllocSize()
  570. {
  571.     return fData.GetAllocSize();
  572. }
  573.  
  574. void PDynDynArray::SizeAllocToFit()
  575. {
  576.     fData.SizeToFit();
  577.     fIndex.SizeToFit();
  578. }
  579.  
  580. void PDynDynArray::GetElementsAt(ArrayIndex index, void* elementPtr, ArrayIndex count)
  581. {
  582.     if (qDebug) FailNonPtrObject(this);
  583. #if qDebug
  584.     if (index < 1 || index + count - 1 > MySize())
  585.     {
  586.         fprintf(stderr, "PDynDynArray::GetElementsAt, index = %ld, count = %ld, MySize() = %ld\n", index, count, MySize());
  587.         ProgramBreak(gEmptyString);
  588.     }
  589. #endif
  590.     long size = 0;
  591.     for (ArrayIndex i = 0; i < count; i++)
  592.         size += GetElementSize(index + i);
  593. #if qDebugDynDynSpecial
  594.     fprintf(stderr, "PDynDynArray::GetElementsAt() at $%lx, ", long(this));
  595.     fprintf(stderr, "index = %ld, count = %ld, to $%lx\n", index, count, elementPtr);
  596.     fprintf(stderr, "-  size of the elements: %ld bytes\n", size);
  597. #endif
  598.     BytesMove(ComputeAddress(index), elementPtr, size);
  599. }
  600.  
  601. void PDynDynArray::ReplaceElementsAt(ArrayIndex index, const void *elementPtr, ArrayIndex count)
  602. {
  603.     if (qDebug) FailNonPtrObject(this);
  604. #if qDebugDynDynIntense
  605.     PDynDynArray::SanityCheck();
  606. #endif
  607. #if qDebug
  608.     if (index < 1 || index + count - 1 > MySize())
  609.     {
  610.         fprintf(stderr, "PDynDynArray::ReplaceElementsAt, index = %ld, count = %ld, MySize() = %ld\n", index, count, MySize());
  611.         ProgramBreak(gEmptyString);
  612.     }
  613. #endif
  614.     long size = 0;
  615.     for (ArrayIndex i = 0; i < count; i++)
  616.         size += GetElementSize(index + i);
  617. #if qDebugDynDynSpecial
  618.     fprintf(stderr, "PDynDynArray::ReplaceElementsAt() at $%lx, ", long(this));
  619.     fprintf(stderr, "index = %ld, count = %ld, from $%lx\n", index, count, elementPtr);
  620.     fprintf(stderr, "-  size of the elements: %ld bytes\n", size);
  621. #endif
  622.     BytesMove(elementPtr, ComputeAddress(index), size);
  623. #if qDebugDynDynIntense
  624.     PDynDynArray::SanityCheck();
  625. #endif
  626. }
  627.  
  628. void PDynDynArray::Specify(PDynDynArray *arrayToCopy)
  629. {
  630. if (qDebug) ProgramBreak("Totally untested");
  631.     if (qDebug) FailNonPtrObject(this);
  632.     if (qDebug) FailNonPtrObject(arrayToCopy);
  633.     FailInfo fi;
  634.     if (fi.Try())
  635.     {
  636.         LockDataHandle(false);
  637.         DeleteAll();
  638.         long dataSize = arrayToCopy->fData.GetSize();
  639.         long indexSize = arrayToCopy->fIndex.GetSize();
  640.         fData.SetNeededSize(dataSize);
  641.         fIndex.SetNeededSize(indexSize);
  642.         BlockMove(arrayToCopy->fData.PtrAtOffset(0), fData.PtrAtOffset(0), dataSize);
  643.         BlockMove(arrayToCopy->fIndex.PtrAtOffset(0), fIndex.PtrAtOffset(0), indexSize);
  644.         fi.Success();
  645.     }
  646.     else // fail
  647.     {
  648.         DeleteAll();
  649.         fi.ReSignal();
  650.     }
  651. }
  652.  
  653. long PDynDynArray::GetIndexOffset(ArrayIndex index)
  654. {
  655.     return (index - 1) * kIndexEntrySize;
  656. }
  657.  
  658. long PDynDynArray::GetElementOffset(ArrayIndex index)
  659. {
  660.     return *( (long*)fIndex.PtrAtOffset(GetIndexOffset(index)) );
  661. }
  662.  
  663. long PDynDynArray::GetElementSize(ArrayIndex index)
  664. {
  665.     if (qDebug) FailNonPtrObject(this);
  666.     return *(long*)fIndex.PtrAtOffset(GetIndexOffset(index) + sizeof(long));
  667. }
  668.  
  669. Ptr PDynDynArray::ComputeAddress(ArrayIndex index) // OBS: CPointer into an unlocked handle!
  670. {
  671. #if qDebug
  672.     FailNonPtrObject(this);
  673.     if (index < 1 || index > MySize()) 
  674.     {
  675.         fprintf(stderr, "Invalid index = %ld (%ld-%ld)\n", index, 1, MySize());
  676.         ProgramBreak(gEmptyString);
  677.         return nil;
  678.     }
  679. #endif
  680.     Ptr p = fIndex.PtrAtOffset((index - 1) * kIndexEntrySize);
  681.     return fData.PtrAtOffset(*(long*)p);
  682. }
  683.  
  684. void PDynDynArray::DebugDump(Boolean verbose)
  685. {
  686.     if (qDebug) FailNonPtrObject(this);
  687. #if qDebug
  688.     fprintf(stderr, "DebugDump af PDynDynArray\n");
  689.     fprintf(stderr, "Index: ");
  690.     fIndex.DebugDump(verbose);
  691.     fprintf(stderr, "Data:  ");
  692.     fData.DebugDump(verbose);
  693.     for (ArrayIndex index = 1; index <= MySize(); index++)
  694.     {
  695.         long offset = GetElementOffset(index);
  696.         if (offset < 0 || offset > fData.GetSize())
  697.         {
  698.             fprintf(stderr, "%3ld seems too bad to dump (offset = %ld)\n", index, offset);
  699.             continue;
  700.         }
  701.         long size = GetElementSize(index);
  702.         fprintf(stderr, "%3ld: offset =%6ld, length = %5ld, ",
  703.             index, offset, size);
  704.         if (verbose)
  705.         {
  706.             fprintf(stderr, "data = ");
  707.             Ptr p = ComputeAddress(index);
  708.             long elNr = *p - 'A' + 1;
  709.             long *lP = (long*) p;
  710.             if (size >= 4)
  711.                 fprintf(stderr, "$%8lx", *lP);
  712.             if (size >= 8)
  713.                 fprintf(stderr, "%8lx", *(lP+1));
  714.             fprintf(stderr, " = ");
  715.             for (long i = MinMax(0, size, 8); i; i--)
  716.                 putc(*p++, stderr);
  717.             if (elNr >= 1 && elNr <= 50)
  718.                 fprintf(stderr, " = #%2ld", elNr);
  719.         }
  720.         fprintf(stderr, "\n");
  721.     }
  722.     fprintf(stderr, "End of dump\n");
  723. #else
  724.     verbose = verbose;
  725. #endif
  726. }
  727.  
  728. Boolean PDynDynArray::SanityCheck()
  729. {
  730.     if (qDebug) FailNonPtrObject(this);
  731.     Boolean isGood = true;
  732. #if qDebug
  733.     long checkOffset = 0;
  734.     for (ArrayIndex index = 1; index <= MySize(); index++)
  735.     {
  736.         long offset = GetElementOffset(index);
  737.         long size = GetElementSize(index);
  738.         if (offset != checkOffset)
  739.         {
  740.             fprintf(stderr, "WRONG: PDynDynArray::SanityCheck, bad element-offset, index = %ld, offset = %ld, expected offset = %ld\n", index, offset, checkOffset);
  741.             isGood = false;
  742.             break;
  743.         }
  744.         checkOffset = offset + size;
  745.     }
  746.     if (checkOffset != fData.GetSize())
  747.     {
  748.         fprintf(stderr, "WRONG: PDynDynArray::SanityCheck, used size of datahandle  = %ld, fData.GetSize() = %ld\n", checkOffset, fData.GetSize());
  749.         isGood = false;
  750.     }
  751.     if (fIndex.GetSize() & 3)
  752.     {
  753.         fprintf(stderr, "WRONG: PDynDynArray::SanityCheck, fIndex.GetSize() = %ld   (long-even odd)\n", fIndex.GetSize());
  754.         isGood = false;
  755.     }
  756.     if (!isGood)
  757.         PDynDynArray::DebugDump(true);
  758. #endif
  759.     return isGood;
  760. }
  761. //==========================================================================
  762.  
  763. PString255Array::PString255Array()
  764. {
  765. }
  766.  
  767. void PString255Array::IString255Array(long allocChunk = 512)
  768. {
  769.     IDynDynArray(allocChunk);
  770. }
  771.  
  772. PString255Array::~PString255Array()
  773. {
  774. }
  775.  
  776. inline long PString255Array::StringSize(const CStr255 &s)
  777. {
  778.     return (s.Length() + 4) & ~3;
  779. }
  780.  
  781. void PString255Array::Append(const CStr255 &s)
  782. {
  783.     const unsigned char *p = (const unsigned char*)&s;
  784.     InsertLast(p, StringSize(s));
  785. }
  786.  
  787. void PString255Array::GetStringAt(ArrayIndex index, CStr255 &s)
  788. {
  789.     Ptr p = ComputeAddress(index);
  790.     BytesMove(p, &s, 1 + *(unsigned char*)p);
  791. }
  792.  
  793. void PString255Array::ReplaceStringAt(ArrayIndex index, CStr255 &s)
  794. {
  795.     SetElementSize(index, StringSize(s));
  796.     ReplaceElementsAt(index, &s, 1);
  797. }
  798.  
  799. void PString255Array::InsertStringBefore(ArrayIndex index, CStr255 &s)
  800. {
  801.     InsertElementBefore(index, &s, StringSize(s));
  802. }
  803. //==========================================================================
  804. PDynDynArray *NewDynDynArray(long allocChunk)
  805. {
  806.     PDynDynArray *dda = new PDynDynArray();
  807.     dda->IDynDynArray(allocChunk);
  808.     return dda;
  809. }
  810.  
  811. PString255Array *NewString255Array(long allocChunk)
  812. {
  813.     PString255Array *dda = new PString255Array();
  814.     dda->IString255Array(allocChunk);
  815.     return dda;
  816. }
  817.