summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/array.h50
-rw-r--r--src/myriad.cpp89
-rw-r--r--src/myriad.h58
-rw-r--r--src/tools/myriad.cpp17
-rw-r--r--src/unit/array.unit19
5 files changed, 219 insertions, 14 deletions
diff --git a/src/array.h b/src/array.h
index 39efb9e..ede43cc 100644
--- a/src/array.h
+++ b/src/array.h
@@ -297,6 +297,17 @@ namespace Bu
297 return *this; 297 return *this;
298 } 298 }
299 299
300 iterator operator+( int iAmnt )
301 {
302 if( iPos < 0 )
303 throw ArrayException(
304 "Cannot increment iterator past end of array.");
305 iPos += iAmnt;
306 if( iPos >= src.getSize() )
307 iPos = -1;
308 return *this;
309 }
310
300 iterator operator--( int ) 311 iterator operator--( int )
301 { 312 {
302 if( iPos < 0 ) 313 if( iPos < 0 )
@@ -316,6 +327,15 @@ namespace Bu
316 iPos = -1; 327 iPos = -1;
317 return *this; 328 return *this;
318 } 329 }
330
331 iterator operator-( int iAmnt )
332 {
333 if( iPos < src.getSize() )
334 iPos -= iAmnt;
335 if( iPos <= 0 )
336 iPos = -1;
337 return *this;
338 }
319 339
320 bool operator==( const iterator &oth ) const 340 bool operator==( const iterator &oth ) const
321 { 341 {
@@ -477,6 +497,36 @@ namespace Bu
477 return const_iterator( *this, -1 ); 497 return const_iterator( *this, -1 );
478 } 498 }
479 499
500 MyType &insert( iterator i, const value &rVal )
501 {
502 if( i.iPos == -1 )
503 {
504 append( rVal );
505 return *this;
506 }
507
508 _hardCopy();
509 if( core->iSize == core->iCapacity )
510 {
511 core->setCapacity( core->iCapacity + inc );
512 }
513 core->iSize++;
514
515 core->va.construct(
516 &core->pData[core->iSize-1],
517 core->pData[core->iSize-2]
518 );
519 for( int iPos = core->iSize-2; iPos > i.iPos; iPos-- )
520 {
521 core->va.destroy( &core->pData[iPos] );
522 core->va.construct( &core->pData[iPos], core->pData[iPos-1] );
523 }
524 core->va.destroy( &core->pData[i.iPos] );
525 core->va.construct( &core->pData[i.iPos], rVal );
526
527 return *this;
528 }
529
480 /** 530 /**
481 * If order is important, use this. It will delete the suggested item 531 * If order is important, use this. It will delete the suggested item
482 * and move the rest of the data up a spot. This is a time O(n) 532 * and move the rest of the data up a spot. This is a time O(n)
diff --git a/src/myriad.cpp b/src/myriad.cpp
index 2f5c14f..9d7a849 100644
--- a/src/myriad.cpp
+++ b/src/myriad.cpp
@@ -151,6 +151,7 @@ void Bu::Myriad::initialize()
151 // << ", pIn->tell()=" << pIn->tell() << sio.nl; 151 // << ", pIn->tell()=" << pIn->tell() << sio.nl;
152 s.aBlocks.append( iBId ); 152 s.aBlocks.append( iBId );
153 bsBlockUsed.setBit( iBId ); 153 bsBlockUsed.setBit( iBId );
154 iUsed++;
154 if( (j == 0 && k == iHeaderBlocks-1) ) 155 if( (j == 0 && k == iHeaderBlocks-1) )
155 { 156 {
156 // sio << "Myriad: - End of prepartition, unlocking skipping." 157 // sio << "Myriad: - End of prepartition, unlocking skipping."
@@ -172,6 +173,13 @@ void Bu::Myriad::initialize()
172 173
173void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate ) 174void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
174{ 175{
176 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
177 {
178 delete *i;
179 }
180 aStreams.clear();
181 iUsed = 0;
182
175 int iHeaderSize = 14 + 8 + 4; 183 int iHeaderSize = 14 + 8 + 4;
176 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize ); 184 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize );
177 char cBuf = 1; 185 char cBuf = 1;
@@ -192,6 +200,7 @@ void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
192 // << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl; 200 // << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
193 201
194 bsBlockUsed.setSize( iPreAllocate, true ); 202 bsBlockUsed.setSize( iPreAllocate, true );
203 iUsed++;
195 204
196 char *pBlock = new char[iBlockSize]; 205 char *pBlock = new char[iBlockSize];
197 memset( pBlock, 0, iBlockSize ); 206 memset( pBlock, 0, iBlockSize );
@@ -240,6 +249,7 @@ void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
240 { 249 {
241 pStr->aBlocks.append( j ); 250 pStr->aBlocks.append( j );
242 bsBlockUsed.setBit( j ); 251 bsBlockUsed.setBit( j );
252 iUsed++;
243 } 253 }
244 254
245 aStreams.append( pStr ); 255 aStreams.append( pStr );
@@ -283,6 +293,7 @@ void Bu::Myriad::updateHeader()
283// << " to header." << sio.nl; 293// << " to header." << sio.nl;
284 aStreams[0]->aBlocks.append( iBlock ); 294 aStreams[0]->aBlocks.append( iBlock );
285 bsBlockUsed.setBit( iBlock ); 295 bsBlockUsed.setBit( iBlock );
296 iUsed++;
286 iHeaderSize += 4; 297 iHeaderSize += 4;
287 iNewBlocks = blkDiv( iHeaderSize, iBlockSize ); 298 iNewBlocks = blkDiv( iHeaderSize, iBlockSize );
288 } 299 }
@@ -339,6 +350,7 @@ int Bu::Myriad::createStream( int iPreAllocate )
339// sio << "Myriad: Adding block " << iFreeBlock << sio.nl; 350// sio << "Myriad: Adding block " << iFreeBlock << sio.nl;
340 pStr->aBlocks.append( iFreeBlock ); 351 pStr->aBlocks.append( iFreeBlock );
341 bsBlockUsed.setBit( iFreeBlock ); 352 bsBlockUsed.setBit( iFreeBlock );
353 iUsed++;
342 } 354 }
343 355
344 bHeaderChanged = true; 356 bHeaderChanged = true;
@@ -346,6 +358,52 @@ int Bu::Myriad::createStream( int iPreAllocate )
346 return pStr->iId; 358 return pStr->iId;
347} 359}
348 360
361int Bu::Myriad::createStreamWithId( int iId, int iPreAllocate )
362{
363 try
364 {
365 findStream( iId );
366 throw MyriadException( MyriadException::streamExists,
367 "There is already a stream with the given id.");
368 }
369 catch( MyriadException &e )
370 {
371 Stream *pStr = new Stream();
372 pStr->iId = iId;
373 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate="
374 // << iPreAllocate << sio.nl;
375 pStr->iSize = 0;
376 if( aStreams.last()->iId < iId )
377 {
378 aStreams.append( pStr );
379 }
380 else
381 {
382 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
383 {
384 if( (*i)->iId > iId )
385 {
386 aStreams.insert( i, pStr );
387 break;
388 }
389 }
390 }
391
392 for( int j = 0; j < iPreAllocate; j++ )
393 {
394 int iFreeBlock = findEmptyBlock();
395 // sio << "Myriad: Adding block " << iFreeBlock << sio.nl;
396 pStr->aBlocks.append( iFreeBlock );
397 bsBlockUsed.setBit( iFreeBlock );
398 iUsed++;
399 }
400
401 bHeaderChanged = true;
402
403 return pStr->iId;
404 }
405}
406
349int Bu::Myriad::findEmptyBlock() 407int Bu::Myriad::findEmptyBlock()
350{ 408{
351 bHeaderChanged = true; 409 bHeaderChanged = true;
@@ -374,6 +432,12 @@ int Bu::Myriad::findEmptyBlock()
374 432
375void Bu::Myriad::deleteStream( int iId ) 433void Bu::Myriad::deleteStream( int iId )
376{ 434{
435 if( iId < 0 )
436 throw MyriadException( MyriadException::invalidStreamId,
437 "Invalid stream id.");
438 if( iId == 0 )
439 throw MyriadException( MyriadException::protectedStream,
440 "You cannot delete stream zero, it is protected.");
377 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 441 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
378 { 442 {
379 if( (*i)->iId == iId ) 443 if( (*i)->iId == iId )
@@ -382,6 +446,7 @@ void Bu::Myriad::deleteStream( int iId )
382 for( BlockArray::iterator j = pStream->aBlocks.begin(); j; j++ ) 446 for( BlockArray::iterator j = pStream->aBlocks.begin(); j; j++ )
383 { 447 {
384 bsBlockUsed.setBit( *j, false ); 448 bsBlockUsed.setBit( *j, false );
449 iUsed--;
385 } 450 }
386 aStreams.erase( i ); 451 aStreams.erase( i );
387 bHeaderChanged = true; 452 bHeaderChanged = true;
@@ -391,12 +456,33 @@ void Bu::Myriad::deleteStream( int iId )
391 } 456 }
392} 457}
393 458
459Bu::Array<int> Bu::Myriad::getStreamIds()
460{
461 Bu::Array<int> aRet( aStreams.getSize() );
462 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
463 {
464 aRet.append( (*i)->iId );
465 }
466
467 return aRet;
468}
469
470int Bu::Myriad::getStreamSize( int iId )
471{
472 return findStream( iId )->iSize;
473}
474
394Bu::MyriadStream Bu::Myriad::openStream( int iId ) 475Bu::MyriadStream Bu::Myriad::openStream( int iId )
395{ 476{
396 //sio << "Myriad: Request to open stream: " << iId << sio.nl; 477 //sio << "Myriad: Request to open stream: " << iId << sio.nl;
397 return MyriadStream( *this, findStream( iId ) ); 478 return MyriadStream( *this, findStream( iId ) );
398} 479}
399 480
481int Bu::Myriad::getNumStreams()
482{
483 return aStreams.getSize();
484}
485
400int Bu::Myriad::getBlockSize() 486int Bu::Myriad::getBlockSize()
401{ 487{
402 return iBlockSize; 488 return iBlockSize;
@@ -469,6 +555,7 @@ int Bu::Myriad::streamAddBlock( Stream *pStream )
469 int iBlock = findEmptyBlock(); 555 int iBlock = findEmptyBlock();
470 pStream->aBlocks.append( iBlock ); 556 pStream->aBlocks.append( iBlock );
471 bsBlockUsed.setBit( iBlock ); 557 bsBlockUsed.setBit( iBlock );
558 iUsed++;
472 return iBlock; 559 return iBlock;
473} 560}
474 561
@@ -484,6 +571,8 @@ void Bu::Myriad::setStreamSize( Stream *pStream, long iSize )
484 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize; 571 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize;
485 iNewSize-64 > iSize; iNewSize -= iBlockSize ) 572 iNewSize-64 > iSize; iNewSize -= iBlockSize )
486 { 573 {
574 if( bsBlockUsed.getBit( pStream->aBlocks.last() ) )
575 iUsed--;
487 bsBlockUsed.setBit( pStream->aBlocks.last(), false ); 576 bsBlockUsed.setBit( pStream->aBlocks.last(), false );
488 pStream->aBlocks.eraseLast(); 577 pStream->aBlocks.eraseLast();
489 } 578 }
diff --git a/src/myriad.h b/src/myriad.h
index b5cd18c..53a42b8 100644
--- a/src/myriad.h
+++ b/src/myriad.h
@@ -26,16 +26,22 @@ namespace Bu
26 invalidFormat, 26 invalidFormat,
27 badVersion, 27 badVersion,
28 invalidWordSize, 28 invalidWordSize,
29 noSuchStream 29 noSuchStream,
30 streamExists,
31 invalidStreamId,
32 protectedStream
30 }; 33 };
31 subExceptionDeclEnd() 34 subExceptionDeclEnd()
32 35
33 /** 36 /**
34 * Numerically Indexed Data Streams. This is a working name so I can 37 * Myriad block-allocated stream multiplexing system. This is a system for
35 * actually get some code written instead of agonizing over the name. 38 * creating streams that contain other streams in a flexible and lightweight
36 * 39 * manner. Basically, you can create a file (or any other stream) that can
37 * This is a system for creating streams that contain other streams in 40 * store any number of flexible, growing streams. The streams within the
38 * a flexible block-allocated system. 41 * Myriad stream are automatically numbered, not named. This works more
42 * or less like a filesystem, but without the extra layer for managing
43 * file and directory links. This would actually be very easy to add
44 * on top of Myriad, but is not required.
39 * 45 *
40 * Header format is as follows: 46 * Header format is as follows:
41 * 47 *
@@ -78,23 +84,43 @@ namespace Bu
78 { 84 {
79 friend class MyriadStream; 85 friend class MyriadStream;
80 public: 86 public:
87 /**
88 * Create a Myriad object that uses the given stream to store data.
89 * This stream must be random access. The block size and preallocate
90 * values passed in are values that will be used if the given stream
91 * is empty. In that case the stream will be "formatted" for myriad
92 * with the specified block size. If there is already a viable Myriad
93 * format present in the stream, then the blocksize and preallocate
94 * values will be ignored and the values from the stream will be used
95 * instead. If the stream doesn't appear to be Myriad formatted an
96 * exception will be thrown.
97 */
81 Myriad( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ); 98 Myriad( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 );
82 virtual ~Myriad(); 99 virtual ~Myriad();
83 100
84 /** 101 /**
85 * Create a new Myriad system in the assosiated stream. This should be 102 * Destroy whatever data may be in the base stream and create a new
86 * used carefully, it will destroy all data already within the stream. 103 * Myriad system there with the given blocksize. Use this with care,
87 * More options will probably be added soon. 104 * it will destroy anything that was already in the stream, and
105 * generally, should not ever have to be used.
88 */ 106 */
89 void initialize( int iBlockSize, int iPreAllocate=1 ); 107 void initialize( int iBlockSize, int iPreAllocate=1 );
90 108
91 /** 109 /**
92 * Create a new stream within the Myriad system. The ID of the new stream 110 * Create a new stream within the Myriad system. The ID of the new
93 * is returned. 111 * stream is returned.
94 */ 112 */
95 int createStream( int iPreAllocate=1 ); 113 int createStream( int iPreAllocate=1 );
96 114
97 /** 115 /**
116 * Create a new stream within the Myriad system with a given id. The
117 * id that you provide will be the new id of the stream unless it's
118 * already used, in which case an error is thrown. This is primarilly
119 * useful when copying an old Myriad file into a new one.
120 */
121 int createStreamWithId( int iId, int iPreAllocate=1 );
122
123 /**
98 * Delete a stream that's already within the Myriad. 124 * Delete a stream that's already within the Myriad.
99 */ 125 */
100 void deleteStream( int iId ); 126 void deleteStream( int iId );
@@ -104,10 +130,13 @@ namespace Bu
104 */ 130 */
105 MyriadStream openStream( int iId ); 131 MyriadStream openStream( int iId );
106 132
133 Bu::Array<int> getStreamIds();
134 int getStreamSize( int iId );
135
136 int getNumStreams();
107 int getBlockSize(); 137 int getBlockSize();
108 int getNumBlocks(); 138 int getNumBlocks();
109 int getNumUsedBlocks(); 139 int getNumUsedBlocks();
110 int getBlockOverhead();
111 140
112 /** 141 /**
113 * Syncronize the header data, etc. with the storage stream. It's not 142 * Syncronize the header data, etc. with the storage stream. It's not
@@ -115,6 +144,11 @@ namespace Bu
115 */ 144 */
116 void sync(); 145 void sync();
117 146
147 /**
148 * Read the first few bytes from the given stream and return true/false
149 * depending on weather or not it's a Myriad stream. This will throw
150 * an exception if the stream is empty, or is not random access.
151 */
118 static bool isMyriad( Bu::Stream &sStore ); 152 static bool isMyriad( Bu::Stream &sStore );
119 153
120 private: 154 private:
diff --git a/src/tools/myriad.cpp b/src/tools/myriad.cpp
index 535d7ac..73ceba1 100644
--- a/src/tools/myriad.cpp
+++ b/src/tools/myriad.cpp
@@ -106,8 +106,7 @@ int main( int argc, char *argv[] )
106 else 106 else
107 { 107 {
108 File fOut( opts.sFile, File::WriteNew|File::Read ); 108 File fOut( opts.sFile, File::WriteNew|File::Read );
109 Myriad m( fOut ); 109 Myriad m( fOut, opts.iBlockSize, opts.iPreallocate );
110 m.initialize( opts.iBlockSize, opts.iPreallocate );
111 } 110 }
112 break; 111 break;
113 112
@@ -121,6 +120,20 @@ int main( int argc, char *argv[] )
121 { 120 {
122 File fIn( opts.sFile, File::Read ); 121 File fIn( opts.sFile, File::Read );
123 Myriad m( fIn ); 122 Myriad m( fIn );
123 sio << "Myriad info:" << sio.nl
124 << " Block size: " << m.getBlockSize() << sio.nl
125 << " Block count: " << m.getNumBlocks() << sio.nl
126 << " Blocks used: " << m.getNumUsedBlocks() << " ("
127 << m.getNumUsedBlocks()*100/m.getNumBlocks() << "%)"
128 << sio.nl
129 << " Stream count: " << m.getNumStreams() << sio.nl;
130 Bu::Array<int> aStreams = m.getStreamIds();
131 sio << " Stream info:" << sio.nl;
132 for( Bu::Array<int>::iterator i = aStreams.begin(); i; i++ )
133 {
134 sio << " " << Fmt(4) << *i << ") "
135 << m.getStreamSize( *i ) << "b" << sio.nl;
136 }
124 } 137 }
125 break; 138 break;
126 139
diff --git a/src/unit/array.unit b/src/unit/array.unit
index 1493033..f3fdeda 100644
--- a/src/unit/array.unit
+++ b/src/unit/array.unit
@@ -9,6 +9,9 @@
9#include "bu/hash.h" 9#include "bu/hash.h"
10#include "bu/array.h" 10#include "bu/array.h"
11 11
12#include "bu/sio.h"
13using Bu::sio;
14
12suite Array 15suite Array
13{ 16{
14 test general 17 test general
@@ -82,4 +85,20 @@ suite Array
82 unitTest( a3[1].get("Test") == "Bloop" ); 85 unitTest( a3[1].get("Test") == "Bloop" );
83 unitTest( a3[1].get("Foo") == "ooF" ); 86 unitTest( a3[1].get("Foo") == "ooF" );
84 } 87 }
88
89 test insert
90 {
91 Bu::Array<int> aInts;
92 aInts.insert( aInts.end(), 4 );
93 aInts.insert( aInts.begin(), 1 );
94 aInts.insert( aInts.end(), 5 );
95 aInts.insert( aInts.begin()+1, 3 );
96 aInts.insert( aInts.begin()+1, 2 );
97 aInts.insert( aInts.begin(), 0 );
98
99 for( int j = 0; j < 6; j++ )
100 {
101 unitTest( aInts[j] == j );
102 }
103 }
85} 104}