summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2010-02-10 18:20:40 +0000
committerMike Buland <eichlan@xagasoft.com>2010-02-10 18:20:40 +0000
commit79b7b631750b69cbe06daedb0453306595dea6ad (patch)
tree284dc89fa2ee6ec88e9b0625a412185d5d1348b0 /src
parent1f29dc180b5a86ddf2115f97ad410e0e9b1beb4b (diff)
downloadlibbu++-79b7b631750b69cbe06daedb0453306595dea6ad.tar.gz
libbu++-79b7b631750b69cbe06daedb0453306595dea6ad.tar.bz2
libbu++-79b7b631750b69cbe06daedb0453306595dea6ad.tar.xz
libbu++-79b7b631750b69cbe06daedb0453306595dea6ad.zip
Changed the name of nids to Myriad, I like it, but I'm not getting rid of nids
until I can safely migrate to Myriad.
Diffstat (limited to 'src')
-rw-r--r--src/array.h245
-rw-r--r--src/bitstring.cpp9
-rw-r--r--src/bitstring.h3
-rw-r--r--src/myriad.cpp284
-rw-r--r--src/myriad.h144
-rw-r--r--src/myriadstream.cpp223
-rw-r--r--src/myriadstream.h58
-rw-r--r--src/tests/nids.cpp10
-rw-r--r--src/tools/myriad.cpp115
-rw-r--r--src/unit/array.unit2
10 files changed, 1010 insertions, 83 deletions
diff --git a/src/array.h b/src/array.h
index 6279382..af41c33 100644
--- a/src/array.h
+++ b/src/array.h
@@ -11,10 +11,95 @@
11#include <memory> 11#include <memory>
12#include "bu/exceptionbase.h" 12#include "bu/exceptionbase.h"
13#include "bu/archivebase.h" 13#include "bu/archivebase.h"
14#include "bu/sharedcore.h"
14 15
15namespace Bu 16namespace Bu
16{ 17{
17 subExceptionDecl( ArrayException ) 18 subExceptionDecl( ArrayException )
19
20 template<typename value, int inc, typename valuealloc>
21 class ArrayCore
22 {
23 public:
24 ArrayCore() :
25 pData( NULL ),
26 iSize( 0 ),
27 iCapacity( 0 )
28 { }
29
30 void setCapacity( int iNewLen )
31 {
32 //clear();
33 //iCapacity = iCapacity;
34 //pData = va.allocate( iCapacity );
35 if( iNewLen <= iCapacity ) return;
36 value *pNewData = va.allocate( iNewLen );
37 if( pData )
38 {
39 for( int j = 0; j < iSize; j++ )
40 {
41 va.construct( &pNewData[j], pData[j] );
42 va.destroy( &pData[j] );
43 }
44 va.deallocate( pData, iCapacity );
45 }
46 pData = pNewData;
47 iCapacity = iNewLen;
48 }
49
50 virtual ~ArrayCore()
51 {
52 clear();
53 }
54
55 void clear()
56 {
57 if( pData )
58 {
59 for( int j = 0; j < iSize; j++ )
60 {
61 va.destroy( &pData[j] );
62 }
63 va.deallocate( pData, iCapacity );
64 pData = NULL;
65 }
66 iSize = 0;
67 iCapacity = 0;
68 }
69
70 void erase( int iPos )
71 {
72 for( int j = iPos; j < iSize; j++ )
73 {
74 va.destroy( &pData[j] );
75 if( j == iSize-1 )
76 {
77 iSize--;
78 return;
79 }
80 va.construct( &pData[j], pData[j+1] );
81 }
82 }
83
84 void swapErase( int iPos )
85 {
86 if( iPos == iSize-1 )
87 {
88 erase( iPos );
89 return;
90 }
91 va.destroy( &pData[iPos] );
92 va.construct( &pData[iPos], pData[iSize-1] );
93 va.destroy( &pData[iSize-1] );
94 iSize--;
95 }
96
97 valuealloc va;
98 value *pData;
99 long iSize;
100 long iCapacity;
101 };
102
18 /** 103 /**
19 * Array type container, just like a normal array only flexible and keeps 104 * Array type container, just like a normal array only flexible and keeps
20 * track of your memory for you. 105 * track of your memory for you.
@@ -25,51 +110,57 @@ namespace Bu
25 *@ingroup Containers 110 *@ingroup Containers
26 */ 111 */
27 template<typename value, int inc=10, typename valuealloc=std::allocator<value> > 112 template<typename value, int inc=10, typename valuealloc=std::allocator<value> >
28 class Array 113 class Array : public SharedCore<ArrayCore<value, inc, valuealloc> >
29 { 114 {
30 private: 115 private:
31 typedef class Array<value, inc, valuealloc> MyType; 116 typedef class Array<value, inc, valuealloc> MyType;
117 typedef class ArrayCore<value, inc, valuealloc> Core;
118
119 protected:
120 using SharedCore< Core >::core;
121 using SharedCore< Core >::_hardCopy;
122 using SharedCore< Core >::_allocateCore;
32 123
33 public: 124 public:
34 Array() : 125 struct const_iterator;
35 pData( NULL ), 126 struct iterator;
36 iSize( 0 ), 127
37 iCapacity( 0 ) 128 Array()
38 { 129 {
39 } 130 }
40 131
41 Array( const MyType &src ) : 132 Array( const MyType &src ) :
42 pData( NULL ), 133 SharedCore< Core >( src )
43 iSize( 0 ),
44 iCapacity( 0 )
45 { 134 {
46 *this = src;
47 } 135 }
48 136
49 Array( long iSetCap ) : 137 Array( long iSetCap )
50 pData( NULL ),
51 iSize( 0 ),
52 iCapacity( 0 )
53 { 138 {
54 setCapacity( iSetCap ); 139 setCapacity( iSetCap );
55 } 140 }
56 141
57 ~Array() 142 ~Array()
58 { 143 {
59 clear();
60 } 144 }
61 145
62 MyType &operator=( const MyType &src ) 146 bool operator==( const MyType &src ) const
63 { 147 {
64 clear(); 148 if( core == src.core )
65 setCapacity( src.iCapacity ); 149 return true;
150 if( core->iSize != src.core->iSize )
151 return false;
66 152
67 long iTop = src.getSize(); 153 for( int j = 0; j < core->iSize; j++ )
68 for( long i = 0; i < iTop; ++i )
69 { 154 {
70 append( src[i] ); 155 if( core->pData[j] != src.core->pData[j] )
156 return false;
71 } 157 }
72 return *this; 158 return true;
159 }
160
161 bool operator!=( const MyType &src ) const
162 {
163 return !(*this == src);
73 } 164 }
74 165
75 /** 166 /**
@@ -77,46 +168,61 @@ namespace Bu
77 */ 168 */
78 void clear() 169 void clear()
79 { 170 {
80 if( pData ) 171 _hardCopy();
81 { 172 core->clear();
82 for( int j = 0; j < iSize; j++ )
83 {
84 va.destroy( &pData[j] );
85 }
86 va.deallocate( pData, iCapacity );
87 pData = NULL;
88 }
89 iSize = 0;
90 iCapacity = 0;
91 } 173 }
92 174
93 void append( const value &rVal ) 175 void append( const value &rVal )
94 { 176 {
95 if( iSize == iCapacity ) 177 _hardCopy();
178 if( core->iSize == core->iCapacity )
96 { 179 {
97 setCapacity( iCapacity + inc ); 180 core->setCapacity( core->iCapacity + inc );
98 } 181 }
99 182
100 va.construct( &pData[iSize++], rVal ); 183 core->va.construct( &core->pData[core->iSize++], rVal );
101 } 184 }
102 185
103 //operator 186 //operator
104 value &operator[]( long iIndex ) 187 value &operator[]( long iIndex )
105 { 188 {
106 if( iIndex < 0 || iIndex >= iSize ) 189 _hardCopy();
190 if( iIndex < 0 || iIndex >= core->iSize )
107 throw ArrayException( 191 throw ArrayException(
108 "Index %d out of range 0:%d", iIndex, iSize ); 192 "Index %d out of range 0:%d", iIndex, core->iSize );
109 193
110 return pData[iIndex]; 194 return core->pData[iIndex];
111 } 195 }
112 196
113 const value &operator[]( long iIndex ) const 197 const value &operator[]( long iIndex ) const
114 { 198 {
115 if( iIndex < 0 || iIndex >= iSize ) 199 if( iIndex < 0 || iIndex >= core->iSize )
116 throw ArrayException( 200 throw ArrayException(
117 "Index %d out of range 0:%d", iIndex, iSize ); 201 "Index %d out of range 0:%d", iIndex, core->iSize );
202
203 return core->pData[iIndex];
204 }
205
206 value &first()
207 {
208 _hardCopy();
209 return core->pData[0];
210 }
211
212 const value &first() const
213 {
214 return core->pData[0];
215 }
216
217 value &last()
218 {
219 _hardCopy();
220 return core->pData[core->iSize-1];
221 }
118 222
119 return pData[iIndex]; 223 const value &last() const
224 {
225 return core->pData[core->iSize-1];
120 } 226 }
121 227
122 /** 228 /**
@@ -125,7 +231,7 @@ namespace Bu
125 */ 231 */
126 long getSize() const 232 long getSize() const
127 { 233 {
128 return iSize; 234 return core->iSize;
129 } 235 }
130 236
131 /** 237 /**
@@ -136,7 +242,7 @@ namespace Bu
136 */ 242 */
137 long getCapacity() const 243 long getCapacity() const
138 { 244 {
139 return iCapacity; 245 return core->iCapacity;
140 } 246 }
141 247
142 /** 248 /**
@@ -149,19 +255,8 @@ namespace Bu
149 */ 255 */
150 void setCapacity( long iNewLen ) 256 void setCapacity( long iNewLen )
151 { 257 {
152 if( iNewLen <= iCapacity ) return; 258 _hardCopy();
153 value *pNewData = va.allocate( iNewLen ); 259 core->setCapacity( iNewLen );
154 if( pData )
155 {
156 for( int j = 0; j < iSize; j++ )
157 {
158 va.construct( &pNewData[j], pData[j] );
159 va.destroy( &pData[j] );
160 }
161 va.deallocate( pData, iCapacity );
162 }
163 pData = pNewData;
164 iCapacity = iNewLen;
165 } 260 }
166 261
167 typedef struct iterator 262 typedef struct iterator
@@ -387,16 +482,8 @@ namespace Bu
387 */ 482 */
388 void erase( iterator i ) 483 void erase( iterator i )
389 { 484 {
390 for( int j = i.iPos; j < iSize; j++ ) 485 _hardCopy();
391 { 486 core->erase( i.iPos );
392 va.destroy( &pData[j] );
393 if( j == iSize-1 )
394 {
395 iSize--;
396 return;
397 }
398 va.construct( &pData[j], pData[j+1] );
399 }
400 } 487 }
401 488
402 /** 489 /**
@@ -408,22 +495,24 @@ namespace Bu
408 */ 495 */
409 void swapErase( iterator i ) 496 void swapErase( iterator i )
410 { 497 {
411 if( i.iPos == iSize-1 ) 498 _hardCopy();
412 { 499 swapErase( i.iPos );
413 erase( i ); 500 }
414 return; 501
502 protected:
503 virtual Core *_copyCore( Core *src )
504 {
505 Core *pRet = _allocateCore();
506 pRet->setCapacity( src->iCapacity );
507 pRet->iSize = src->iSize;
508 for( int j = 0; j < src->iSize; j++ )
509 {
510 pRet->va.construct( &pRet->pData[j], src->pData[j] );
415 } 511 }
416 va.destroy( &pData[i.iPos] ); 512 return pRet;
417 va.construct( &pData[i.iPos], pData[iSize-1] );
418 va.destroy( &pData[iSize-1] );
419 iSize--;
420 } 513 }
421 514
422 private: 515 private:
423 valuealloc va;
424 value *pData;
425 long iSize;
426 long iCapacity;
427 }; 516 };
428 517
429 class Formatter; 518 class Formatter;
diff --git a/src/bitstring.cpp b/src/bitstring.cpp
index f05818f..a7881cc 100644
--- a/src/bitstring.cpp
+++ b/src/bitstring.cpp
@@ -443,6 +443,15 @@ long Bu::BitString::getHighestOrderBitPos()
443 443
444 return -1; 444 return -1;
445} 445}
446
447Bu::FString Bu::BitString::toString()
448{
449 Bu::FString sRet;
450 for( int j = iBits-1; j >= 0; j-- )
451 sRet.append( getBit( j )?'1':'0' );
452 return sRet;
453}
454
446/* 455/*
447bool Bu::BitString::writeToFile( FILE *fh ) 456bool Bu::BitString::writeToFile( FILE *fh )
448{ 457{
diff --git a/src/bitstring.h b/src/bitstring.h
index b5f1ada..7a83f50 100644
--- a/src/bitstring.h
+++ b/src/bitstring.h
@@ -9,6 +9,7 @@
9#define BU_BITSTRING_H 9#define BU_BITSTRING_H
10 10
11#include "bu/util.h" 11#include "bu/util.h"
12#include "bu/fstring.h"
12 13
13namespace Bu 14namespace Bu
14{ 15{
@@ -202,6 +203,8 @@ namespace Bu
202 */ 203 */
203 long toLong( long iStart = 0, long iSize = 32 ); 204 long toLong( long iStart = 0, long iSize = 32 );
204 205
206 Bu::FString toString();
207
205 //operators 208 //operators
206 BitString &operator=( const BitString &xSrc ); 209 BitString &operator=( const BitString &xSrc );
207 BitString operator~(); 210 BitString operator~();
diff --git a/src/myriad.cpp b/src/myriad.cpp
new file mode 100644
index 0000000..64c8d20
--- /dev/null
+++ b/src/myriad.cpp
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/myriad.h"
9#include "bu/stream.h"
10#include "bu/myriadstream.h"
11#include <stdio.h>
12
13#include "bu/sio.h"
14using Bu::sio;
15using Bu::Fmt;
16
17#define Myriad_MAGIC_CODE ((unsigned char *)"\xFF\xC3\x99\xBD")
18
19namespace Bu
20{
21 subExceptionDef( MyriadException )
22 template<typename t> t blkDiv( t total, t block ) {
23 return (total/block)+((total%block==0)?(0):(1));
24 }
25}
26
27Bu::Myriad::Myriad( Bu::Stream &sStore ) :
28 sStore( sStore ),
29 iBlockSize( 0 ),
30 iBlocks( 0 ),
31 iUsed( 0 )
32{
33}
34
35Bu::Myriad::~Myriad()
36{
37 updateHeader();
38
39 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
40 {
41 delete *i;
42 }
43}
44
45void Bu::Myriad::sync()
46{
47 updateHeader();
48
49 // Later, also flush all caches.
50}
51
52void Bu::Myriad::initialize()
53{
54 sStore.setPosEnd( 0 );
55 int iSize = sStore.tell();
56 sStore.setPos( 0 );
57
58 unsigned char buf[4];
59 if( sStore.read( buf, 4 ) < 4 )
60 throw MyriadException("Input stream appears to be empty.");
61 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
62 {
63 throw MyriadException(
64 "Stream does not appear to be a valid Myriad format.");
65 }
66 sStore.read( buf, 2 );
67 if( buf[0] != 1 )
68 throw MyriadException(
69 "We can only handle version 1 for now.");
70 if( buf[1] != 32 )
71 throw MyriadException(
72 "We can only handle 32-bit words at the moment.");
73 sStore.read( &iBlockSize, 4 );
74 int iStreams;
75 sStore.read( &iStreams, 4 );
76
77 iBlocks = iSize/iBlockSize;
78 sio << "Myriad: iSize=" << iSize << ", iBlockSize=" << iBlockSize
79 << ", iBlocks=" << iBlocks << ", iStreams=" << iStreams << sio.nl;
80
81 int iHeaderSize = 14 + 8 + 4;
82 int iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
83
84 while( iHeaderSize > iHeaderBlocks*iBlockSize )
85 {
86 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
87 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
88 }
89
90 sio << "Myriad: iHeaderSize=" << iHeaderSize
91 << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
92
93 bsBlockUsed.setSize( iBlocks, true );
94
95 bool bCanSkip = false; // Can skip around, post initial header stream i/o
96 for( int j = 0; j < iStreams; j++ )
97 {
98 int iHdrBlock = 0;
99 int iCurBlock = 0;
100 aStreams.append( new Stream() );
101 Stream &s = *aStreams[j];
102 sStore.read( &s.iId, 4 );
103 sStore.read( &s.iSize, 4 );
104 int iSBlocks = blkDiv(s.iSize, iBlockSize);
105 sio << "Myriad: - Stream::iId=" << s.iId << ", Stream::iSize=" << s.iSize
106 << ", Stream::aBlocks=" << iSBlocks
107 << ", sStore.tell()=" << sStore.tell() << sio.nl;
108 for( int k = 0; k < iSBlocks; k++ )
109 {
110 int iBId;
111 sStore.read( &iBId, 4 );
112 sio << "Myriad: - iBId=" << iBId
113 << ", iStartPos=" << iBId*iBlockSize
114 << ", sStore.tell()=" << sStore.tell() << sio.nl;
115 s.aBlocks.append( iBId );
116 bsBlockUsed.setBit( iBId );
117 if( (j == 0 && k == iHeaderBlocks-1) )
118 {
119 sio << "Myriad: - End of prepartition, unlocking skipping."
120 << sio.nl;
121 bCanSkip = true;
122 iCurBlock = blkDiv( (int)sStore.tell(), iBlockSize );
123 }
124 if( bCanSkip && sStore.tell() >= iCurBlock*iBlockSize+iBlockSize )
125 {
126 iHdrBlock++;
127 iCurBlock = aStreams[0]->aBlocks[iHdrBlock];
128 sio << "Myriad: Ran out of data in block, finding next header "
129 "block: " << iHdrBlock << " = " << iCurBlock << " ("
130 << iCurBlock*iBlockSize << "b)" << sio.nl;
131 sStore.setPos( iCurBlock*iBlockSize );
132 }
133 }
134 }
135
136 sio << bsBlockUsed.toString() << sio.nl;
137
138 //printf("%d blocks, %db each, %db block offset\n",
139 // iBlocks, iBlockSize, iBlockStart );
140
141}
142
143void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate )
144{
145 int iHeaderSize = 14 + 8 + 4;
146 int iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
147 char cBuf = 1;
148 int iBuf = 0;
149
150 Stream *pStr = new Stream;
151 pStr->iId = 0;
152
153 while( iHeaderSize > iHeaderBlocks*iBlockSize )
154 {
155 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
156 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
157 }
158
159 iPreAllocate += iHeaderBlocks;
160
161 sio << "Myriad: iHeaderSize=" << iHeaderSize << ", iBlockSize="
162 << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl;
163
164 bsBlockUsed.setSize( iPreAllocate, true );
165
166 char *pBlock = new char[iBlockSize];
167 memset( pBlock, 0, iBlockSize );
168 for( int j = 0; j < iPreAllocate; j++ )
169 {
170 sStore.write( pBlock, iBlockSize );
171 pStr->aBlocks.append( j );
172 }
173 delete[] (char *)pBlock;
174
175 sStore.setPos( 0 );
176
177 // Magic number
178 sStore.write( Myriad_MAGIC_CODE, 4 );
179
180 // Version (0)
181 sStore.write( &cBuf, 1 );
182
183 // Bits per int
184 cBuf = 32;
185 sStore.write( &cBuf, 1 );
186
187 // The size of each block
188 sStore.write( &iBlockSize, 4 );
189
190 iBuf = 1;
191 // The number of streams
192 sStore.write( &iBuf, 4 );
193
194 // Stream header
195 iBuf = 0;
196 sStore.write( &iBuf, 4 );
197 sStore.write( &iHeaderSize, 4 );
198 for( iBuf = 0; iBuf < iHeaderBlocks; iBuf++ )
199 {
200 sStore.write( &iBuf, 4 );
201 }
202
203 this->iBlockSize = iBlockSize;
204 this->iBlocks = iPreAllocate;
205
206 pStr->iSize = sStore.tell();
207
208 //hStreams.insert( 0, BlockArray( 0 ) );
209}
210
211void Bu::Myriad::updateHeader()
212{
213 if( !sStore.canWrite() )
214 return;
215
216
217
218 // TODO: Use the stream class to access this really smoothly, I hope :)
219}
220
221int Bu::Myriad::createStream( int iPreAllocate )
222{
223 Stream *pStr = new Stream();
224 pStr->iId = aStreams.last()->iId+1;
225 sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate="
226 << iPreAllocate << sio.nl;
227 pStr->iSize = 0;
228
229 for( int j = 0; j < iPreAllocate; j++ )
230 {
231 int iFreeBlock = findEmptyBlock();
232 sio << "Myriad: Adding block " << j << sio.nl;
233 pStr->aBlocks.append( j );
234 bsBlockUsed.setBit( j );
235 }
236
237 return 0;
238}
239
240int Bu::Myriad::findEmptyBlock()
241{
242 for( int j = 0; j < bsBlockUsed.getSize(); j++ )
243 {
244 if( bsBlockUsed.getBit( j ) == false )
245 return j;
246 }
247 sio << "Myriad: findEmptyBlock(): No empty blocks, adding new one." << sio.nl;
248
249 bsBlockUsed.setSize( bsBlockUsed.getSize()+1, false );
250 sStore.setPos( iBlockSize*iBlocks );
251
252 char *pBlock = new char[iBlockSize];
253 memset( pBlock, 0, iBlockSize );
254 sStore.write( pBlock, iBlockSize );
255 delete pBlock;
256
257 return iBlockSize++;
258}
259
260void Bu::Myriad::deleteStream( int /*iID*/ )
261{
262}
263
264Bu::MyriadStream Bu::Myriad::openStream( int iID )
265{
266 return MyriadStream( *this, iID );
267}
268
269int Bu::Myriad::getBlockSize()
270{
271 return iBlockSize;
272}
273
274int Bu::Myriad::getNumBlocks()
275{
276 return iBlocks;
277}
278
279int Bu::Myriad::getNumUsedBlocks()
280{
281 return iUsed;
282}
283
284
diff --git a/src/myriad.h b/src/myriad.h
new file mode 100644
index 0000000..772729f
--- /dev/null
+++ b/src/myriad.h
@@ -0,0 +1,144 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MYRIAD_H
9#define BU_MYRIAD_H
10
11#include <stdint.h>
12#include "bu/bitstring.h"
13#include "bu/exceptionbase.h"
14#include "bu/array.h"
15
16namespace Bu
17{
18 class Stream;
19 class MyriadStream;
20
21 subExceptionDecl( MyriadException )
22
23 /**
24 * Numerically Indexed Data Streams. This is a working name so I can
25 * actually get some code written instead of agonizing over the name.
26 *
27 * This is a system for creating streams that contain other streams in
28 * a flexible block-allocated system.
29 *
30 * Header format is as follows:
31 *
32 * MMMMvBssssSSSS*
33 * M = Magic number
34 * v = version number
35 * B = Bits per int
36 * s = Blocksize in bytes
37 * S = Number of Streams
38 *
39 * The * represents the Stream headers, one per stream, as follows:
40 * IIIIssss$
41 * I = Id number of the stream
42 * s = size of stream in bytes
43 *
44 * The $ represents the Block headers, one per used block, as follows:
45 * IIII
46 * I = Index of the block
47 *
48 * The stream/block data is interleaved in the header, so all blocks stored
49 * with one stream are together. The block headers are in order, and the
50 * data in them is required to be "solid" you cannot fill partial blocks
51 * mid-way through a stream.
52 *
53 * The initial block starts with the nids header, and is both the zero block
54 * and the zero stream. For now, the minimum block size is the size needed
55 * to store the base header, the zero stream header, and the first two
56 * blocks of the zero stream, so 30 bytes. Since it's reccomended to use
57 * a size that will fit evenly into filesystem blocks, then a size of 32 is
58 * probably the smallest reccomended size because all powers of two equal
59 * to or greater than 32 are evenly divisible by 32.
60 *
61 * I have had a thought that if the block size were smaller than 42 bytes
62 * the header would consume the first N blocks where N * block size is
63 * enough space to house the initial header, the first stream header, and
64 * the first N block headers. This, of course, causes you to hit an
65 * infinite header if the block size is small enough.
66 */
67 class Myriad
68 {
69 friend class MyriadStream;
70 public:
71 Myriad( Bu::Stream &sStore );
72 virtual ~Myriad();
73
74 /**
75 * Initialize this object based on the data already in the assosiated
76 * stream. This will be called automatically for you if you forget,
77 * but if you want to pre-initialize for some reason, just call this
78 * once before you actually start doing anything with your Myriad.
79 */
80 void initialize();
81
82 /**
83 * Create a new Myriad system in the assosiated stream. This should be
84 * used carefully, it will destroy all data already within the stream.
85 * More options will probably be added soon.
86 */
87 void initialize( int iBlockSize, int iPreAllocate=1 );
88
89 /**
90 * Create a new stream within the Myriad system. The ID of the new stream
91 * is returned.
92 */
93 int createStream( int iPreAllocate=1 );
94
95 /**
96 * Delete a stream that's already within the Myriad.
97 */
98 void deleteStream( int iID );
99
100 /**
101 * Return a new Stream object assosiated with the given stream ID.
102 */
103 MyriadStream openStream( int iID );
104
105 int getBlockSize();
106 int getNumBlocks();
107 int getNumUsedBlocks();
108 int getBlockOverhead();
109
110 /**
111 * Syncronize the header data, etc. with the storage stream. It's not
112 * a bad idea to call this periodically.
113 */
114 void sync();
115
116 private:
117 enum
118 {
119 blockUnused = 0xFFFFFFFFUL
120 };
121
122 void updateHeader();
123 int findEmptyBlock();
124
125 private:
126 Bu::Stream &sStore;
127 int iBlockSize;
128 int iBlocks;
129 int iUsed;
130 Bu::BitString bsBlockUsed;
131 typedef Bu::Array<int> BlockArray;
132 class Stream
133 {
134 public:
135 int iId;
136 int iSize;
137 BlockArray aBlocks;
138 };
139 typedef Bu::Array<Stream *> StreamArray;
140 StreamArray aStreams;
141 };
142};
143
144#endif
diff --git a/src/myriadstream.cpp b/src/myriadstream.cpp
new file mode 100644
index 0000000..c9b3326
--- /dev/null
+++ b/src/myriadstream.cpp
@@ -0,0 +1,223 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/myriadstream.h"
9
10#include <string.h>
11
12Bu::MyriadStream::MyriadStream( Myriad &rMyriad, uint32_t uStream ) :
13 rMyriad( rMyriad ),
14 uStream( uStream ),
15 pCurBlock( NULL ),
16 uCurBlock( uStream ),
17 uSize( 0 ),
18 uBlockSize( rMyriad.iBlockSize ),
19 uPos( 0 )
20{
21 //printf("MyriadStream::allocated\n");
22 //pCurBlock = rMyriad.newBlock();
23 //rMyriad.getBlock( uStream, pCurBlock );
24 //uSize = pCurBlock->uBytesUsed;
25}
26
27Bu::MyriadStream::~MyriadStream()
28{
29 //printf("Destroying stream?\n");
30 //rMyriad.updateStreamSize( uStream, uSize );
31 //rMyriad.deleteBlock( pCurBlock );
32}
33
34void Bu::MyriadStream::close()
35{
36}
37
38size_t Bu::MyriadStream::read( void *pBuf, size_t nBytes )
39{
40 /*
41 if( nBytes == 0 )
42 return 0;
43 if( nBytes + uPos > uSize )
44 nBytes = uSize - uPos;
45 if( (uPos%uBlockSize)+nBytes < uBlockSize )
46 {
47 size_t iRead = nBytes;
48 if( iRead > pCurBlock->uBytesUsed-(uPos%uBlockSize) )
49 iRead = pCurBlock->uBytesUsed-(uPos%uBlockSize);
50 memcpy( pBuf, pCurBlock->pData+(uPos%uBlockSize), iRead );
51 //printf("read buffill: %ub, %u-%u/%u -> %d-%d/%d (a:%u)",
52 // iRead, uPos, uPos+iRead-1, uSize, 0, iRead-1, nBytes, uCurBlock );
53 uPos += iRead;
54 //printf(" -- %u\n", uPos%uBlockSize );
55 //printf("ra: block %u = %ub:%u (%ub total)\n",
56 // uCurBlock, uPos, nBytes, uSize );
57
58 // This can't happen, if we're right on a boundery, it goes to the
59 // other case
60 //if( uPos%uBlockSize == 0 )
61 // uCurBlock = rMyriad.getNextBlock( uCurBlock, pCurBlock, false );
62 return iRead;
63 }
64 else
65 {
66 size_t nTotal = 0;
67 for(;;)
68 {
69 uint32_t iRead = nBytes;
70 if( iRead > uBlockSize-(uPos%uBlockSize) )
71 iRead = uBlockSize-(uPos%uBlockSize);
72 if( iRead > pCurBlock->uBytesUsed-(uPos%uBlockSize) )
73 iRead = pCurBlock->uBytesUsed-(uPos%uBlockSize);
74 memcpy( ((char *)pBuf)+nTotal,
75 pCurBlock->pData+(uPos%uBlockSize), iRead );
76 //printf(" read buffill: %ub, %u-%u/%u -> %d-%d/%d (b:%u)\n",
77 // iRead, uPos, uPos+iRead-1, uSize,
78 // nTotal, nTotal+nBytes-1, nBytes, uCurBlock );
79 uPos += iRead;
80 nBytes -= iRead;
81 nTotal += iRead;
82 //printf("rb: block %u = %ub:%u (%ub total)\n",
83 // uCurBlock, uPos, iRead, uSize );
84 if( uPos%uBlockSize == 0 )
85 uCurBlock = rMyriad.getNextBlock( uCurBlock, pCurBlock, false );
86 if( nBytes == 0 || uPos >= uSize )
87 return nTotal;
88 }
89 }*/
90 return 0;
91}
92
93size_t Bu::MyriadStream::write( const void *pBuf, size_t nBytes )
94{
95 if( nBytes == 0 )
96 return 0;
97/* if( pCurBlock->uBytesUsed >= uBlockSize )
98 {
99 // We're at the end of our current block, allocate another before we do
100 // anything.
101 uCurBlock = rMyriad.getNextBlock( uCurBlock, pCurBlock );
102 } */
103 /*
104 if( (uPos%uBlockSize)+nBytes < uBlockSize )
105 {
106 //printf("wa: %u:%u:%u:%u -> ", uPos, uPos%uBlockSize, uSize, pCurBlock->uBytesUsed );
107 memcpy( pCurBlock->pData+(uPos%uBlockSize), pBuf, nBytes );
108 //printf("write buffill: %ub, %u-%u/%u -> %d-%d/%d (a:%u:%u)\n",
109 // nBytes, 0, nBytes-1, nBytes,
110 // uPos, uPos+nBytes-1, uSize, uCurBlock,
111 // pCurBlock->uBytesUsed );
112 if( (uPos%uBlockSize)+nBytes > pCurBlock->uBytesUsed )
113 pCurBlock->uBytesUsed = (uPos%uBlockSize)+nBytes;
114 rMyriad.setBlock( uCurBlock, pCurBlock );
115 uPos += nBytes;
116 if( uPos > uSize )
117 uSize = uPos;
118 //printf("block %u = %ub (%ub total) %d:%u\n",
119 // uCurBlock, pCurBlock->uBytesUsed, uSize, nBytes, uPos );
120 return nBytes;
121 }
122 else
123 {
124 size_t nTotal = 0;
125 for(;;)
126 {
127 uint32_t uNow = uBlockSize-(uPos%uBlockSize);
128 //printf("uNow: %u (%u-(%u%%%u)) %d req\n", uNow, uBlockSize, uPos, uBlockSize, nBytes );
129 if( nBytes < uNow )
130 uNow = nBytes;
131 memcpy( pCurBlock->pData+(uPos%uBlockSize),
132 &((char *)pBuf)[nTotal], uNow );
133 //printf("write buffill: %ub, %u-%u/%u -> %d-%d/%d (b:%u:%u)\n",
134 // uNow, nTotal, nTotal+uNow-1, nBytes,
135 // uPos, uPos+uNow-1, uSize, uCurBlock, pCurBlock->uBytesUsed );
136 if( (uPos%uBlockSize)+uNow > pCurBlock->uBytesUsed )
137 pCurBlock->uBytesUsed = (uPos%uBlockSize)+uNow;
138 rMyriad.setBlock( uCurBlock, pCurBlock );
139 uPos += uNow;
140 if( uPos > uSize )
141 uSize = uPos;
142 nTotal += uNow;
143 nBytes -= uNow;
144 //printf("wb: block %u = %ub (%ub total)\n",
145 // uCurBlock, pCurBlock->uBytesUsed, uSize );
146 //if( pCurBlock->uBytesUsed == uBlockSize )
147 if( uPos%uBlockSize == 0 )
148 uCurBlock = rMyriad.getNextBlock( uCurBlock, pCurBlock );
149 if( nBytes == 0 )
150 return nTotal;
151 }
152 }*/
153 return 0;
154}
155
156long Bu::MyriadStream::tell()
157{
158 return uPos;
159}
160
161void Bu::MyriadStream::seek( long offset )
162{
163 uPos += offset;
164}
165
166void Bu::MyriadStream::setPos( long pos )
167{
168 uPos = pos;
169}
170
171void Bu::MyriadStream::setPosEnd( long pos )
172{
173 uPos = uSize-pos-1;
174}
175
176bool Bu::MyriadStream::isEos()
177{
178 return true;
179}
180
181bool Bu::MyriadStream::isOpen()
182{
183 return true;
184}
185
186void Bu::MyriadStream::flush()
187{
188}
189
190bool Bu::MyriadStream::canRead()
191{
192 return true;
193}
194
195bool Bu::MyriadStream::canWrite()
196{
197 return true;
198}
199
200bool Bu::MyriadStream::isReadable()
201{
202 return true;
203}
204
205bool Bu::MyriadStream::isWritable()
206{
207 return true;
208}
209
210bool Bu::MyriadStream::isSeekable()
211{
212 return true;
213}
214
215bool Bu::MyriadStream::isBlocking()
216{
217 return true;
218}
219
220void Bu::MyriadStream::setBlocking( bool /*bBlocking*/ )
221{
222}
223
diff --git a/src/myriadstream.h b/src/myriadstream.h
new file mode 100644
index 0000000..755ff53
--- /dev/null
+++ b/src/myriadstream.h
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MYRIAD_STREAM_H
9#define BU_MYRIAD_STREAM_H
10
11#include "bu/stream.h"
12#include "bu/myriad.h"
13
14namespace Bu
15{
16 class MyriadStream : public Bu::Stream
17 {
18 friend class Myriad;
19 private:
20 /**
21 * These can only be created by the Myriad class.
22 */
23 MyriadStream( Myriad &rMyriad, uint32_t uStream );
24
25 public:
26 virtual ~MyriadStream();
27
28 virtual void close();
29 virtual size_t read( void *pBuf, size_t nBytes );
30 virtual size_t write( const void *pBuf, size_t nBytes );
31 using Stream::write;
32 virtual long tell();
33 virtual void seek( long offset );
34 virtual void setPos( long pos );
35 virtual void setPosEnd( long pos );
36 virtual bool isEos();
37 virtual bool isOpen();
38 virtual void flush();
39 virtual bool canRead();
40 virtual bool canWrite();
41 virtual bool isReadable();
42 virtual bool isWritable();
43 virtual bool isSeekable();
44 virtual bool isBlocking();
45 virtual void setBlocking( bool bBlocking=true );
46
47 private:
48 Myriad &rMyriad;
49 uint32_t uStream;
50 char *pCurBlock;
51 uint32_t uCurBlock;
52 uint32_t uSize;
53 uint32_t uBlockSize;
54 uint32_t uPos;
55 };
56};
57
58#endif
diff --git a/src/tests/nids.cpp b/src/tests/nids.cpp
index bb5993b..41d0432 100644
--- a/src/tests/nids.cpp
+++ b/src/tests/nids.cpp
@@ -23,18 +23,19 @@ int main( int argc, char *argv[] )
23 Bu::File::ReadWrite|Bu::File::Create|Bu::File::Truncate ); 23 Bu::File::ReadWrite|Bu::File::Create|Bu::File::Truncate );
24 Bu::Nids n( fOut ); 24 Bu::Nids n( fOut );
25 25
26 n.initialize( 120, 1 ); 26 n.initialize( 32, 1 );
27 Bu::NidsStream s = n.openStream( n.createStream() ); 27/* Bu::NidsStream s = n.openStream( n.createStream() );
28 28
29 Bu::FString sBuf( 350 ); 29 Bu::FString sBuf( 350 );
30 memset( sBuf.getStr(), 'a', 350 ); 30 memset( sBuf.getStr(), 'a', 350 );
31 s.write( sBuf ); 31 s.write( sBuf );*/
32 } 32 }
33 else if( argv[1][0] == 'r' ) 33 else if( argv[1][0] == 'r' )
34 { 34 {
35 Bu::File fOut( argv[2], Bu::File::Read ); 35 Bu::File fOut( argv[2], Bu::File::Read );
36 Bu::Nids n( fOut ); 36 Bu::Nids n( fOut );
37 37 n.initialize();
38/*
38 Bu::NidsStream s = n.openStream( 0 ); 39 Bu::NidsStream s = n.openStream( 0 );
39 char buf[75]; 40 char buf[75];
40 for( int j = 0; j < 3; j++ ) 41 for( int j = 0; j < 3; j++ )
@@ -44,6 +45,7 @@ int main( int argc, char *argv[] )
44 printf("\n(read %d chars)\n", iRead ); 45 printf("\n(read %d chars)\n", iRead );
45 } 46 }
46 printf("Position: %ld\n", s.tell() ); 47 printf("Position: %ld\n", s.tell() );
48 */
47 } 49 }
48 else 50 else
49 { 51 {
diff --git a/src/tools/myriad.cpp b/src/tools/myriad.cpp
new file mode 100644
index 0000000..e951882
--- /dev/null
+++ b/src/tools/myriad.cpp
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2007-2008 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/sio.h"
9#include "bu/file.h"
10#include "bu/myriad.h"
11#include "bu/myriadstream.h"
12#include "bu/optparser.h"
13
14#include <stdlib.h>
15
16using namespace Bu;
17
18enum Mode
19{
20 modeCreate,
21 modeInfo,
22
23 modeNone
24};
25
26class Options : public OptParser
27{
28public:
29 Options( int argc, char *argv[] ) :
30 eMode( modeNone ),
31 iBlockSize( 64 ),
32 iPreallocate( 0 )
33 {
34 addHelpBanner("Mode of operation:");
35 addOption( eMode, 'c', "create", "Create a new NIDS file." );
36 addOption( eMode, "info", "Display some info about a NIDS file." );
37 addHelpOption();
38
39 addHelpBanner("\nGeneral options:");
40 addOption( iBlockSize, 'b', "block-size", "Set the block size." );
41 addOption( iPreallocate, 'p', "preallocate",
42 "Number of blocks to preallocate." );
43 addOption( sOutput, 'o', "output", "Set the output filename." );
44 addOption( sInput, 'i', "input", "Set the input filename." );
45
46 setOverride( "create", "create" );
47 setOverride( "info", "info" );
48
49 parse( argc, argv );
50 }
51
52 Mode eMode;
53 int iBlockSize;
54 int iPreallocate;
55 Bu::FString sOutput;
56 Bu::FString sInput;
57};
58
59Bu::Formatter &operator>>( Bu::Formatter &f, Mode &m )
60{
61 Bu::FString sTok = f.readToken();
62 if( sTok == "create" || sTok == "c" )
63 m = modeCreate;
64 else if( sTok == "info" )
65 m = modeInfo;
66 else
67 m = modeNone;
68 return f;
69}
70
71int main( int argc, char *argv[] )
72{
73 Options opts( argc, argv );
74
75 switch( opts.eMode )
76 {
77 case modeCreate:
78 if( !opts.sOutput )
79 {
80 sio << "Please specify an output file to create a stream for."
81 << sio.nl;
82 return 0;
83 }
84 else
85 {
86 File fOut( opts.sOutput, File::WriteNew );
87 Myriad n( fOut );
88 n.initialize( opts.iBlockSize, opts.iPreallocate );
89 }
90 break;
91
92 case modeInfo:
93 if( !opts.sInput )
94 {
95 sio << "Please specify an input file to display info about."
96 << sio.nl;
97 return 0;
98 }
99 else
100 {
101 File fIn( opts.sInput, File::Read );
102 Myriad n( fIn );
103 n.initialize();
104 }
105 break;
106
107 case modeNone:
108 sio << "Please select a mode, for more info, try --help."
109 << sio.nl << sio.nl;
110 break;
111 }
112
113 return 0;
114}
115
diff --git a/src/unit/array.unit b/src/unit/array.unit
index b6528eb..daedd5f 100644
--- a/src/unit/array.unit
+++ b/src/unit/array.unit
@@ -76,7 +76,7 @@
76 76
77 StrHashArray a3; 77 StrHashArray a3;
78 a3 = a1; 78 a3 = a1;
79 79
80 unitTest( a3[0].get("Hi") == "Yo" ); 80 unitTest( a3[0].get("Hi") == "Yo" );
81 unitTest( a3[0].get("Bye") == "Later" ); 81 unitTest( a3[0].get("Bye") == "Later" );
82 unitTest( a3[1].get("Test") == "Bloop" ); 82 unitTest( a3[1].get("Test") == "Bloop" );