diff options
Diffstat (limited to '')
-rw-r--r-- | bnftest | 18 | ||||
-rw-r--r-- | bnftest.2 | 24 | ||||
-rw-r--r-- | default.bld | 16 | ||||
-rw-r--r-- | src/archive.cpp | 9 | ||||
-rw-r--r-- | src/archive.h | 4 | ||||
-rw-r--r-- | src/archivebase.h | 5 | ||||
-rw-r--r-- | src/array.h | 29 | ||||
-rw-r--r-- | src/cachestorefiles.h | 2 | ||||
-rw-r--r-- | src/cachestoremyriad.h | 2 | ||||
-rw-r--r-- | src/client.cpp | 9 | ||||
-rw-r--r-- | src/client.h | 8 | ||||
-rw-r--r-- | src/fastcgi.cpp | 22 | ||||
-rw-r--r-- | src/fastcgi.h | 18 | ||||
-rw-r--r-- | src/fbasicstring.h | 241 | ||||
-rw-r--r-- | src/file.cpp | 1 | ||||
-rw-r--r-- | src/hash.h | 1057 | ||||
-rw-r--r-- | src/heap.h | 300 | ||||
-rw-r--r-- | src/httpget.h | 4 | ||||
-rw-r--r-- | src/itoserver.cpp | 12 | ||||
-rw-r--r-- | src/itoserver.h | 6 | ||||
-rw-r--r-- | src/lexer.h | 4 | ||||
-rw-r--r-- | src/list.h | 29 | ||||
-rw-r--r-- | src/listhash.cpp | 8 | ||||
-rw-r--r-- | src/listhash.h | 54 | ||||
-rw-r--r-- | src/myriad.h | 2 | ||||
-rw-r--r-- | src/myriadfs.cpp | 78 | ||||
-rw-r--r-- | src/myriadfs.h | 54 | ||||
-rw-r--r-- | src/newline.h | 2 | ||||
-rw-r--r-- | src/paramproc.cpp | 523 | ||||
-rw-r--r-- | src/paramproc.h | 163 | ||||
-rw-r--r-- | src/parser.cpp | 34 | ||||
-rw-r--r-- | src/parser.h | 5 | ||||
-rw-r--r-- | src/ringbuffer.h | 209 | ||||
-rw-r--r-- | src/server.cpp | 14 | ||||
-rw-r--r-- | src/server.h | 6 | ||||
-rw-r--r-- | src/set.h | 760 | ||||
-rw-r--r-- | src/sharedcore.h | 77 | ||||
-rw-r--r-- | src/tcpserversocket.cpp (renamed from src/serversocket.cpp) | 36 | ||||
-rw-r--r-- | src/tcpserversocket.h (renamed from src/serversocket.h) | 18 | ||||
-rw-r--r-- | src/tcpsocket.cpp (renamed from src/socket.cpp) | 148 | ||||
-rw-r--r-- | src/tcpsocket.h (renamed from src/socket.h) | 31 | ||||
-rw-r--r-- | src/tests/sharedcore.cpp | 2 | ||||
-rw-r--r-- | src/tests/socketblock.cpp | 10 | ||||
-rw-r--r-- | src/tests/socketbreak.cpp | 10 | ||||
-rw-r--r-- | src/tests/tcpsocket.cpp (renamed from src/tests/socket.cpp) | 4 | ||||
-rw-r--r-- | src/tools/bnfcompile.cpp | 410 | ||||
-rw-r--r-- | src/tools/myriadfs.cpp | 38 | ||||
-rw-r--r-- | src/tools/parser.cpp | 89 | ||||
-rw-r--r-- | src/unit/fstring.unit | 9 | ||||
-rw-r--r-- | src/unit/hash.unit | 13 | ||||
-rw-r--r-- | src/utfstring.cpp | 29 | ||||
-rw-r--r-- | src/utfstring.h | 24 | ||||
-rw-r--r-- | src/variant.h | 18 |
53 files changed, 2221 insertions, 2477 deletions
@@ -0,0 +1,18 @@ | |||
1 | tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen | ||
2 | tokEquals tokNumber; | ||
3 | |||
4 | input: input line | ||
5 | | | ||
6 | ; | ||
7 | |||
8 | line: expr tokEquals {print} | ||
9 | ; | ||
10 | |||
11 | expr: expr tokPlus expr {add} | ||
12 | | expr tokMinus expr {subtract} | ||
13 | | expr tokMult expr {multiply} | ||
14 | | expr tokDivide expr {divide} | ||
15 | | tokOpenParen expr tokCloseParen | ||
16 | | [tokNumber] | ||
17 | ; | ||
18 | |||
diff --git a/bnftest.2 b/bnftest.2 new file mode 100644 index 0000000..229943b --- /dev/null +++ b/bnftest.2 | |||
@@ -0,0 +1,24 @@ | |||
1 | tokens = tokPlus tokMinus tokMult tokDivide tokOpenParen tokCloseParen | ||
2 | tokEquals tokNumber; | ||
3 | |||
4 | input: line input# | ||
5 | | | ||
6 | ; | ||
7 | |||
8 | input#: line input# | ||
9 | | | ||
10 | ; | ||
11 | |||
12 | line: expr tokEquals {print} | ||
13 | ; | ||
14 | |||
15 | expr: tokOpenParen expr tokCloseParen expr# | ||
16 | | [tokNumber] expr# | ||
17 | ; | ||
18 | |||
19 | expr#: tokPlus expr {add} expr# | ||
20 | | tokMinus expr {subtract} expr# | ||
21 | | tokMult expr {multiply} expr# | ||
22 | | tokDivide expr {divide} expr# | ||
23 | | | ||
24 | ; | ||
diff --git a/default.bld b/default.bld index 857e988..50baefb 100644 --- a/default.bld +++ b/default.bld | |||
@@ -82,6 +82,22 @@ target "viewcsv" | |||
82 | } | 82 | } |
83 | 83 | ||
84 | // | 84 | // |
85 | // This shouldn't be. Basically, if you set a property on a top level target | ||
86 | // that has children it seems like the items should apply to the children. | ||
87 | // I'm honestly not 100% sure what the policy should be yet, but this seems like | ||
88 | // I shouldn't have to do it this way. | ||
89 | // | ||
90 | target "src/tools/myriadfs.o" | ||
91 | { | ||
92 | CXXFLAGS += "-D_FILE_OFFSET_BITS=64"; | ||
93 | } | ||
94 | |||
95 | target "myriadfs" | ||
96 | { | ||
97 | LDFLAGS += "-lfuse"; | ||
98 | } | ||
99 | |||
100 | // | ||
85 | // General Tests | 101 | // General Tests |
86 | // | 102 | // |
87 | 103 | ||
diff --git a/src/archive.cpp b/src/archive.cpp index 69d4a0c..7a10921 100644 --- a/src/archive.cpp +++ b/src/archive.cpp | |||
@@ -22,20 +22,15 @@ Bu::Archive::~Archive() | |||
22 | { | 22 | { |
23 | } | 23 | } |
24 | 24 | ||
25 | void Bu::Archive::write( const void *pData, int32_t nSize ) | 25 | void Bu::Archive::write( const void *pData, size_t nSize ) |
26 | { | 26 | { |
27 | if( nSize == 0 || pData == NULL ) | 27 | if( nSize == 0 || pData == NULL ) |
28 | return; | 28 | return; |
29 | 29 | ||
30 | // Bu::sio << "Writing starting at pos: " << rStream.tell() << " - " | ||
31 | // << Bu::sio.flush; | ||
32 | |||
33 | rStream.write( (const char *)pData, nSize ); | 30 | rStream.write( (const char *)pData, nSize ); |
34 | // | ||
35 | // Bu::sio << rStream.tell() << " (" << nSize << "b)" << Bu::sio.nl; | ||
36 | } | 31 | } |
37 | 32 | ||
38 | void Bu::Archive::read( void *pData, int32_t nSize ) | 33 | void Bu::Archive::read( void *pData, size_t nSize ) |
39 | { | 34 | { |
40 | if( nSize == 0 || pData == NULL ) | 35 | if( nSize == 0 || pData == NULL ) |
41 | return; | 36 | return; |
diff --git a/src/archive.h b/src/archive.h index bd85113..9d2aee2 100644 --- a/src/archive.h +++ b/src/archive.h | |||
@@ -83,8 +83,8 @@ namespace Bu | |||
83 | virtual ~Archive(); | 83 | virtual ~Archive(); |
84 | virtual void close(); | 84 | virtual void close(); |
85 | 85 | ||
86 | virtual void write(const void *, int32_t); | 86 | virtual void write( const void *pData, size_t iSize ); |
87 | virtual void read(void *, int32_t); | 87 | virtual void read( void *pData, size_t iSize ); |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * For storage, get an ID for the pointer to the object you're going to | 90 | * For storage, get an ID for the pointer to the object you're going to |
diff --git a/src/archivebase.h b/src/archivebase.h index c871bb5..18591f0 100644 --- a/src/archivebase.h +++ b/src/archivebase.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define BU_ARCHIVE_BASE_H | 9 | #define BU_ARCHIVE_BASE_H |
10 | 10 | ||
11 | #include <stdint.h> | 11 | #include <stdint.h> |
12 | #include <unistd.h> | ||
12 | 13 | ||
13 | namespace Bu | 14 | namespace Bu |
14 | { | 15 | { |
@@ -19,8 +20,8 @@ namespace Bu | |||
19 | virtual ~ArchiveBase(); | 20 | virtual ~ArchiveBase(); |
20 | 21 | ||
21 | virtual void close()=0; | 22 | virtual void close()=0; |
22 | virtual void write( const void *pData, int32_t iLength )=0; | 23 | virtual void write( const void *pData, size_t iLength )=0; |
23 | virtual void read( void *pData, int32_t iLength )=0; | 24 | virtual void read( void *pData, size_t iLength )=0; |
24 | virtual bool isLoading()=0; | 25 | virtual bool isLoading()=0; |
25 | }; | 26 | }; |
26 | 27 | ||
diff --git a/src/array.h b/src/array.h index eeee677..f225c97 100644 --- a/src/array.h +++ b/src/array.h | |||
@@ -18,9 +18,18 @@ namespace Bu | |||
18 | subExceptionDecl( ArrayException ) | 18 | subExceptionDecl( ArrayException ) |
19 | 19 | ||
20 | template<typename value, int inc, typename valuealloc> | 20 | template<typename value, int inc, typename valuealloc> |
21 | class Array; | ||
22 | |||
23 | /** @cond DEVEL */ | ||
24 | template<typename value, int inc, typename valuealloc> | ||
21 | class ArrayCore | 25 | class ArrayCore |
22 | { | 26 | { |
23 | public: | 27 | friend class Array<value, inc, valuealloc>; |
28 | friend class SharedCore< | ||
29 | Array<value, inc, valuealloc>, | ||
30 | ArrayCore<value, inc, valuealloc> | ||
31 | >; | ||
32 | private: | ||
24 | ArrayCore() : | 33 | ArrayCore() : |
25 | pData( NULL ), | 34 | pData( NULL ), |
26 | iSize( 0 ), | 35 | iSize( 0 ), |
@@ -99,6 +108,7 @@ namespace Bu | |||
99 | long iSize; | 108 | long iSize; |
100 | long iCapacity; | 109 | long iCapacity; |
101 | }; | 110 | }; |
111 | /** @endcond */ | ||
102 | 112 | ||
103 | /** | 113 | /** |
104 | * Array type container, just like a normal array only flexible and keeps | 114 | * Array type container, just like a normal array only flexible and keeps |
@@ -110,16 +120,20 @@ namespace Bu | |||
110 | *@ingroup Containers | 120 | *@ingroup Containers |
111 | */ | 121 | */ |
112 | template<typename value, int inc=10, typename valuealloc=std::allocator<value> > | 122 | template<typename value, int inc=10, typename valuealloc=std::allocator<value> > |
113 | class Array : public SharedCore<ArrayCore<value, inc, valuealloc> > | 123 | class Array : public SharedCore< |
124 | Array<value, inc, valuealloc>, | ||
125 | ArrayCore<value, inc, valuealloc> | ||
126 | > | ||
114 | { | 127 | { |
115 | private: | 128 | private: |
116 | typedef class Array<value, inc, valuealloc> MyType; | 129 | typedef class Array<value, inc, valuealloc> MyType; |
117 | typedef class ArrayCore<value, inc, valuealloc> Core; | 130 | typedef class ArrayCore<value, inc, valuealloc> Core; |
118 | 131 | ||
119 | protected: | 132 | protected: |
120 | using SharedCore< Core >::core; | 133 | using SharedCore<MyType, Core>::core; |
121 | using SharedCore< Core >::_hardCopy; | 134 | using SharedCore<MyType, Core>::_hardCopy; |
122 | using SharedCore< Core >::_allocateCore; | 135 | using SharedCore<MyType, Core>::_resetCore; |
136 | using SharedCore<MyType, Core>::_allocateCore; | ||
123 | 137 | ||
124 | public: | 138 | public: |
125 | struct const_iterator; | 139 | struct const_iterator; |
@@ -130,7 +144,7 @@ namespace Bu | |||
130 | } | 144 | } |
131 | 145 | ||
132 | Array( const MyType &src ) : | 146 | Array( const MyType &src ) : |
133 | SharedCore< Core >( src ) | 147 | SharedCore<MyType, Core >( src ) |
134 | { | 148 | { |
135 | } | 149 | } |
136 | 150 | ||
@@ -168,8 +182,7 @@ namespace Bu | |||
168 | */ | 182 | */ |
169 | void clear() | 183 | void clear() |
170 | { | 184 | { |
171 | _hardCopy(); | 185 | _resetCore(); |
172 | core->clear(); | ||
173 | } | 186 | } |
174 | 187 | ||
175 | MyType &append( const value &rVal ) | 188 | MyType &append( const value &rVal ) |
diff --git a/src/cachestorefiles.h b/src/cachestorefiles.h index 1906b13..c2cf091 100644 --- a/src/cachestorefiles.h +++ b/src/cachestorefiles.h | |||
@@ -83,7 +83,7 @@ namespace Bu | |||
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | virtual void unload( obtype *pObj, const keytype &key ) | 86 | virtual void unload( obtype *pObj, const keytype & ) |
87 | { | 87 | { |
88 | delete pObj; | 88 | delete pObj; |
89 | } | 89 | } |
diff --git a/src/cachestoremyriad.h b/src/cachestoremyriad.h index b90793d..21c84e6 100644 --- a/src/cachestoremyriad.h +++ b/src/cachestoremyriad.h | |||
@@ -85,7 +85,7 @@ namespace Bu | |||
85 | return pOb; | 85 | return pOb; |
86 | } | 86 | } |
87 | 87 | ||
88 | virtual void unload( obtype *pObj, const keytype &key ) | 88 | virtual void unload( obtype *pObj, const keytype & ) |
89 | { | 89 | { |
90 | delete pObj; | 90 | delete pObj; |
91 | } | 91 | } |
diff --git a/src/client.cpp b/src/client.cpp index becd1bd..b635c8b 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
@@ -6,7 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bu/client.h" | 8 | #include "bu/client.h" |
9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
11 | #include <errno.h> | 11 | #include <errno.h> |
12 | #include "bu/protocol.h" | 12 | #include "bu/protocol.h" |
@@ -16,7 +16,8 @@ | |||
16 | /** Read buffer size. */ | 16 | /** Read buffer size. */ |
17 | #define RBS (1024*2) | 17 | #define RBS (1024*2) |
18 | 18 | ||
19 | Bu::Client::Client( Bu::Socket *pSocket, class Bu::ClientLinkFactory *pfLink ) : | 19 | Bu::Client::Client( Bu::TcpSocket *pSocket, |
20 | class Bu::ClientLinkFactory *pfLink ) : | ||
20 | pTopStream( pSocket ), | 21 | pTopStream( pSocket ), |
21 | pSocket( pSocket ), | 22 | pSocket( pSocket ), |
22 | pProto( NULL ), | 23 | pProto( NULL ), |
@@ -59,7 +60,7 @@ void Bu::Client::processInput() | |||
59 | break; | 60 | break; |
60 | } | 61 | } |
61 | } | 62 | } |
62 | catch( Bu::SocketException &e ) | 63 | catch( Bu::TcpSocketException &e ) |
63 | { | 64 | { |
64 | pTopStream->close(); | 65 | pTopStream->close(); |
65 | bWantsDisconnect = true; | 66 | bWantsDisconnect = true; |
@@ -195,7 +196,7 @@ long Bu::Client::getOutputSize() | |||
195 | return qbWrite.getSize(); | 196 | return qbWrite.getSize(); |
196 | } | 197 | } |
197 | 198 | ||
198 | const Bu::Socket *Bu::Client::getSocket() const | 199 | const Bu::TcpSocket *Bu::Client::getSocket() const |
199 | { | 200 | { |
200 | return pSocket; | 201 | return pSocket; |
201 | } | 202 | } |
diff --git a/src/client.h b/src/client.h index f336524..096df2f 100644 --- a/src/client.h +++ b/src/client.h | |||
@@ -17,7 +17,7 @@ namespace Bu | |||
17 | { | 17 | { |
18 | class Protocol; | 18 | class Protocol; |
19 | class Stream; | 19 | class Stream; |
20 | class Socket; | 20 | class TcpSocket; |
21 | class ClientLinkFactory; | 21 | class ClientLinkFactory; |
22 | 22 | ||
23 | /** | 23 | /** |
@@ -26,7 +26,7 @@ namespace Bu | |||
26 | class Client : public Bu::Stream | 26 | class Client : public Bu::Stream |
27 | { | 27 | { |
28 | public: | 28 | public: |
29 | Client( Bu::Socket *pSocket, Bu::ClientLinkFactory *pfLink ); | 29 | Client( Bu::TcpSocket *pSocket, Bu::ClientLinkFactory *pfLink ); |
30 | virtual ~Client(); | 30 | virtual ~Client(); |
31 | 31 | ||
32 | void processInput(); | 32 | void processInput(); |
@@ -58,7 +58,7 @@ namespace Bu | |||
58 | void close(); | 58 | void close(); |
59 | void tick(); | 59 | void tick(); |
60 | 60 | ||
61 | const Bu::Socket *getSocket() const; | 61 | const Bu::TcpSocket *getSocket() const; |
62 | 62 | ||
63 | void disconnect(); | 63 | void disconnect(); |
64 | bool wantsDisconnect(); | 64 | bool wantsDisconnect(); |
@@ -117,7 +117,7 @@ namespace Bu | |||
117 | typedef Bu::List<Bu::Stream *> FilterList; | 117 | typedef Bu::List<Bu::Stream *> FilterList; |
118 | FilterList lFilts; | 118 | FilterList lFilts; |
119 | Bu::Stream *pTopStream; | 119 | Bu::Stream *pTopStream; |
120 | Bu::Socket *pSocket; | 120 | Bu::TcpSocket *pSocket; |
121 | Bu::Protocol *pProto; | 121 | Bu::Protocol *pProto; |
122 | Bu::QueueBuf qbRead; | 122 | Bu::QueueBuf qbRead; |
123 | Bu::QueueBuf qbWrite; | 123 | Bu::QueueBuf qbWrite; |
diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp index 8168928..ca3010e 100644 --- a/src/fastcgi.cpp +++ b/src/fastcgi.cpp | |||
@@ -24,14 +24,14 @@ Bu::FastCgi::FastCgi() : | |||
24 | pSrv( NULL ), | 24 | pSrv( NULL ), |
25 | bRunning( true ) | 25 | bRunning( true ) |
26 | { | 26 | { |
27 | pSrv = new Bu::ServerSocket( STDIN_FILENO, false ); | 27 | pSrv = new Bu::TcpServerSocket( STDIN_FILENO, false ); |
28 | } | 28 | } |
29 | 29 | ||
30 | Bu::FastCgi::FastCgi( int iPort ) : | 30 | Bu::FastCgi::FastCgi( int iPort ) : |
31 | pSrv( NULL ), | 31 | pSrv( NULL ), |
32 | bRunning( true ) | 32 | bRunning( true ) |
33 | { | 33 | { |
34 | pSrv = new Bu::ServerSocket( iPort ); | 34 | pSrv = new Bu::TcpServerSocket( iPort ); |
35 | } | 35 | } |
36 | 36 | ||
37 | Bu::FastCgi::~FastCgi() | 37 | Bu::FastCgi::~FastCgi() |
@@ -64,17 +64,17 @@ bool Bu::FastCgi::isEmbedded() | |||
64 | #endif | 64 | #endif |
65 | } | 65 | } |
66 | 66 | ||
67 | void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r ) | 67 | void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r ) |
68 | { | 68 | { |
69 | int iRead = s.read( &r, sizeof(Record) ); | 69 | int iRead = s.read( &r, sizeof(Record) ); |
70 | if( iRead != sizeof(Record) ) | 70 | if( iRead != sizeof(Record) ) |
71 | throw Bu::SocketException("Hey, the size %d is wrong for Record. (%s)", | 71 | throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)", |
72 | iRead, strerror( errno ) ); | 72 | iRead, strerror( errno ) ); |
73 | r.uRequestId = ntohs( r.uRequestId ); | 73 | r.uRequestId = ntohs( r.uRequestId ); |
74 | r.uContentLength = ntohs( r.uContentLength ); | 74 | r.uContentLength = ntohs( r.uContentLength ); |
75 | } | 75 | } |
76 | 76 | ||
77 | void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) | 77 | void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r ) |
78 | { | 78 | { |
79 | // sio << "Out -> " << r << sio.nl; | 79 | // sio << "Out -> " << r << sio.nl; |
80 | r.uRequestId = htons( r.uRequestId ); | 80 | r.uRequestId = htons( r.uRequestId ); |
@@ -82,19 +82,19 @@ void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) | |||
82 | s.write( &r, sizeof(Record) ); | 82 | s.write( &r, sizeof(Record) ); |
83 | } | 83 | } |
84 | 84 | ||
85 | void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b ) | 85 | void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b ) |
86 | { | 86 | { |
87 | s.read( &b, sizeof(BeginRequestBody) ); | 87 | s.read( &b, sizeof(BeginRequestBody) ); |
88 | b.uRole = ntohs( b.uRole ); | 88 | b.uRole = ntohs( b.uRole ); |
89 | } | 89 | } |
90 | 90 | ||
91 | void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b ) | 91 | void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b ) |
92 | { | 92 | { |
93 | b.uStatus = htonl( b.uStatus ); | 93 | b.uStatus = htonl( b.uStatus ); |
94 | s.write( &b, sizeof(b) ); | 94 | s.write( &b, sizeof(b) ); |
95 | } | 95 | } |
96 | 96 | ||
97 | uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) | 97 | uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead ) |
98 | { | 98 | { |
99 | uint8_t uByte[4]; | 99 | uint8_t uByte[4]; |
100 | s.read( uByte, 1 ); | 100 | s.read( uByte, 1 ); |
@@ -107,7 +107,7 @@ uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) | |||
107 | return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); | 107 | return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); |
108 | } | 108 | } |
109 | 109 | ||
110 | void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead ) | 110 | void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead ) |
111 | { | 111 | { |
112 | uint32_t uName = readLen( s, uRead ); | 112 | uint32_t uName = readLen( s, uRead ); |
113 | uint32_t uValue = readLen( s, uRead ); | 113 | uint32_t uValue = readLen( s, uRead ); |
@@ -162,7 +162,7 @@ void Bu::FastCgi::run() | |||
162 | if( iSock < 0 ) | 162 | if( iSock < 0 ) |
163 | continue; | 163 | continue; |
164 | 164 | ||
165 | Bu::Socket s( iSock ); | 165 | Bu::TcpSocket s( iSock ); |
166 | s.setBlocking( true ); | 166 | s.setBlocking( true ); |
167 | // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; | 167 | // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; |
168 | try | 168 | try |
@@ -362,7 +362,7 @@ void Bu::FastCgi::run() | |||
362 | } | 362 | } |
363 | } | 363 | } |
364 | } | 364 | } |
365 | catch( Bu::SocketException &e ) | 365 | catch( Bu::TcpSocketException &e ) |
366 | { | 366 | { |
367 | // sio << "Bu::SocketException: " << e.what() << sio.nl << | 367 | // sio << "Bu::SocketException: " << e.what() << sio.nl << |
368 | // "\tSocket open: " << s.isOpen() << sio.nl; | 368 | // "\tSocket open: " << s.isOpen() << sio.nl; |
diff --git a/src/fastcgi.h b/src/fastcgi.h index 262872c..7c1c04c 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h | |||
@@ -11,8 +11,8 @@ | |||
11 | #include "bu/fstring.h" | 11 | #include "bu/fstring.h" |
12 | #include "bu/hash.h" | 12 | #include "bu/hash.h" |
13 | #include "bu/array.h" | 13 | #include "bu/array.h" |
14 | #include "bu/socket.h" | 14 | #include "bu/tcpsocket.h" |
15 | #include "bu/serversocket.h" | 15 | #include "bu/tcpserversocket.h" |
16 | 16 | ||
17 | namespace Bu | 17 | namespace Bu |
18 | { | 18 | { |
@@ -109,18 +109,18 @@ namespace Bu | |||
109 | virtual void onUninit() { }; | 109 | virtual void onUninit() { }; |
110 | 110 | ||
111 | private: | 111 | private: |
112 | void read( Bu::Socket &s, Record &r ); | 112 | void read( Bu::TcpSocket &s, Record &r ); |
113 | void read( Bu::Socket &s, BeginRequestBody &b ); | 113 | void read( Bu::TcpSocket &s, BeginRequestBody &b ); |
114 | uint32_t readLen( Bu::Socket &s, uint16_t &uUsed ); | 114 | uint32_t readLen( Bu::TcpSocket &s, uint16_t &uUsed ); |
115 | void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed ); | 115 | void readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uUsed ); |
116 | 116 | ||
117 | void write( Bu::Socket &s, Record r ); | 117 | void write( Bu::TcpSocket &s, Record r ); |
118 | void write( Bu::Socket &s, EndRequestBody b ); | 118 | void write( Bu::TcpSocket &s, EndRequestBody b ); |
119 | 119 | ||
120 | bool hasChannel( int iChan ); | 120 | bool hasChannel( int iChan ); |
121 | 121 | ||
122 | private: | 122 | private: |
123 | Bu::ServerSocket *pSrv; | 123 | Bu::TcpServerSocket *pSrv; |
124 | bool bRunning; | 124 | bool bRunning; |
125 | Bu::Array<Channel *> aChannel; | 125 | Bu::Array<Channel *> aChannel; |
126 | }; | 126 | }; |
diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 4c33479..064ff16 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | namespace Bu | 26 | namespace Bu |
27 | { | 27 | { |
28 | /** @cond DEVEL */ | ||
28 | template< typename chr > | 29 | template< typename chr > |
29 | struct FStringChunk | 30 | struct FStringChunk |
30 | { | 31 | { |
@@ -34,10 +35,55 @@ namespace Bu | |||
34 | }; | 35 | }; |
35 | 36 | ||
36 | #define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) ) | 37 | #define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) ) |
38 | |||
39 | template< typename chr, int nMinSize, typename chralloc, | ||
40 | typename chunkalloc> class FBasicString; | ||
41 | |||
42 | template<typename chr> | ||
43 | size_t strlen( const chr *pData ) | ||
44 | { | ||
45 | for( size_t tLen = 0;; ++tLen ) | ||
46 | { | ||
47 | if( pData[tLen] == (chr)0 ) | ||
48 | return tLen; | ||
49 | } | ||
50 | return -1; | ||
51 | } | ||
52 | |||
53 | template<char> | ||
54 | size_t strlen( const char *pData ) | ||
55 | { | ||
56 | return ::strlen( pData ); | ||
57 | } | ||
58 | |||
59 | template<typename chr> | ||
60 | int strncmp( const chr *a, const chr *b, size_t iLen ) | ||
61 | { | ||
62 | for( size_t iPos = 0; iPos < iLen; iPos++ ) | ||
63 | { | ||
64 | if( a[iPos] != b[iPos] ) | ||
65 | { | ||
66 | return a[iPos]-b[iPos]; | ||
67 | } | ||
68 | } | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | template<char> | ||
73 | int strncmp( const char *a, const char *b, size_t iLen ) | ||
74 | { | ||
75 | return ::strncmp( a, b, iLen ); | ||
76 | } | ||
37 | 77 | ||
38 | template<typename chr, int nMinSize, typename chralloc, typename chunkalloc> | 78 | template<typename chr, int nMinSize, typename chralloc, typename chunkalloc> |
39 | struct FStringCore | 79 | struct FStringCore |
40 | { | 80 | { |
81 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; | ||
82 | friend class SharedCore< | ||
83 | FBasicString<chr, nMinSize, chralloc, chunkalloc>, | ||
84 | FStringCore<chr, nMinSize, chralloc, chunkalloc> | ||
85 | >; | ||
86 | private: | ||
41 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType; | 87 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType; |
42 | typedef struct FStringChunk<chr> Chunk; | 88 | typedef struct FStringChunk<chr> Chunk; |
43 | FStringCore() : | 89 | FStringCore() : |
@@ -157,6 +203,7 @@ namespace Bu | |||
157 | nLength += pNewChunk->nLength; | 203 | nLength += pNewChunk->nLength; |
158 | } | 204 | } |
159 | }; | 205 | }; |
206 | /** @endcond */ | ||
160 | 207 | ||
161 | /** | 208 | /** |
162 | * Flexible String class. This class was designed with string passing and | 209 | * Flexible String class. This class was designed with string passing and |
@@ -174,55 +221,24 @@ namespace Bu | |||
174 | *@param chralloc (typename) Memory Allocator for chr | 221 | *@param chralloc (typename) Memory Allocator for chr |
175 | *@param chunkalloc (typename) Memory Allocator for chr chunks | 222 | *@param chunkalloc (typename) Memory Allocator for chr chunks |
176 | */ | 223 | */ |
177 | template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | 224 | template< typename chr, int nMinSize=256, |
178 | class FBasicString : public SharedCore< FStringCore<chr, nMinSize, chralloc, chunkalloc> > | 225 | typename chralloc=std::allocator<chr>, |
226 | typename chunkalloc=std::allocator<struct FStringChunk<chr> > > | ||
227 | class FBasicString : public SharedCore< | ||
228 | FBasicString<chr, nMinSize, chralloc, chunkalloc>, | ||
229 | FStringCore<chr, nMinSize, chralloc, chunkalloc> > | ||
179 | { | 230 | { |
180 | protected: | 231 | protected: |
181 | typedef struct FStringChunk<chr> Chunk; | 232 | typedef struct FStringChunk<chr> Chunk; |
182 | typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; | 233 | typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; |
183 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core; | 234 | typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core; |
184 | 235 | ||
185 | using SharedCore< Core >::core; | 236 | using SharedCore<MyType, Core >::core; |
186 | using SharedCore< Core >::_hardCopy; | 237 | using SharedCore<MyType, Core >::_hardCopy; |
187 | |||
188 | public: | ||
189 | FBasicString() | ||
190 | { | ||
191 | } | ||
192 | |||
193 | FBasicString( const chr *pData ) | ||
194 | { | ||
195 | append( pData ); | ||
196 | } | ||
197 | |||
198 | FBasicString( const chr *pData, long nLength ) | ||
199 | { | ||
200 | append( pData, nLength ); | ||
201 | } | ||
202 | 238 | ||
203 | FBasicString( const MyType &rSrc ) : | 239 | public: // Iterators |
204 | SharedCore<Core>( rSrc ) | ||
205 | { | ||
206 | } | ||
207 | |||
208 | FBasicString( const MyType &rSrc, long nLength ) | ||
209 | { | ||
210 | append( rSrc, nLength ); | ||
211 | } | ||
212 | |||
213 | FBasicString( const MyType &rSrc, long nStart, long nLength ) | ||
214 | { | ||
215 | append( rSrc, nStart, nLength ); | ||
216 | } | ||
217 | |||
218 | FBasicString( long nSize ) | ||
219 | { | ||
220 | core->pFirst = core->pLast = core->newChunk( nSize ); | ||
221 | core->nLength = nSize; | ||
222 | } | ||
223 | |||
224 | struct iterator; | 240 | struct iterator; |
225 | struct const_iterator | 241 | typedef struct const_iterator |
226 | { | 242 | { |
227 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; | 243 | friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>; |
228 | friend struct iterator; | 244 | friend struct iterator; |
@@ -243,7 +259,7 @@ namespace Bu | |||
243 | { | 259 | { |
244 | } | 260 | } |
245 | 261 | ||
246 | const_iterator( const iterator &i ) : | 262 | const_iterator( const struct iterator &i ) : |
247 | pChunk( i.pChunk ), | 263 | pChunk( i.pChunk ), |
248 | iPos( i.iPos ) | 264 | iPos( i.iPos ) |
249 | { | 265 | { |
@@ -454,7 +470,7 @@ namespace Bu | |||
454 | } | 470 | } |
455 | return const_iterator( NULL, 0 ); | 471 | return const_iterator( NULL, 0 ); |
456 | } | 472 | } |
457 | }; | 473 | } const_iterator; |
458 | 474 | ||
459 | typedef struct iterator | 475 | typedef struct iterator |
460 | { | 476 | { |
@@ -702,11 +718,41 @@ namespace Bu | |||
702 | } | 718 | } |
703 | } iterator; | 719 | } iterator; |
704 | 720 | ||
705 | typedef struct const_iterator const_iterator; | 721 | public: |
722 | FBasicString() | ||
723 | { | ||
724 | } | ||
725 | |||
726 | FBasicString( const chr *pData ) | ||
727 | { | ||
728 | append( pData ); | ||
729 | } | ||
730 | |||
731 | FBasicString( const chr *pData, long nLength ) | ||
732 | { | ||
733 | append( pData, nLength ); | ||
734 | } | ||
735 | |||
736 | FBasicString( const MyType &rSrc ) : | ||
737 | SharedCore<MyType, Core>( rSrc ) | ||
738 | { | ||
739 | } | ||
706 | 740 | ||
707 | //typedef chr *iterator; | 741 | FBasicString( const MyType &rSrc, long nLength ) |
708 | // typedef const chr *const_iterator; | 742 | { |
709 | // typedef iterator const_iterator; | 743 | append( rSrc, nLength ); |
744 | } | ||
745 | |||
746 | FBasicString( const MyType &rSrc, long nStart, long nLength ) | ||
747 | { | ||
748 | append( rSrc, nStart, nLength ); | ||
749 | } | ||
750 | |||
751 | FBasicString( long nSize ) | ||
752 | { | ||
753 | core->pFirst = core->pLast = core->newChunk( nSize ); | ||
754 | core->nLength = nSize; | ||
755 | } | ||
710 | 756 | ||
711 | FBasicString( const const_iterator &s ) | 757 | FBasicString( const const_iterator &s ) |
712 | { | 758 | { |
@@ -731,14 +777,8 @@ namespace Bu | |||
731 | if( !pData ) return; | 777 | if( !pData ) return; |
732 | long nLen; | 778 | long nLen; |
733 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } | 779 | for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } |
734 | if( nLen == 0 ) | ||
735 | return; | ||
736 | |||
737 | Chunk *pNew = core->newChunk( nLen ); | ||
738 | cpy( pNew->pData, pData, nLen ); | ||
739 | 780 | ||
740 | _hardCopy(); | 781 | append( pData, 0, nLen ); |
741 | core->appendChunk( pNew ); | ||
742 | } | 782 | } |
743 | 783 | ||
744 | /** | 784 | /** |
@@ -748,15 +788,7 @@ namespace Bu | |||
748 | */ | 788 | */ |
749 | void append( const chr *pData, long nLen ) | 789 | void append( const chr *pData, long nLen ) |
750 | { | 790 | { |
751 | if( nLen == 0 ) | 791 | append( pData, 0, nLen ); |
752 | return; | ||
753 | |||
754 | Chunk *pNew = core->newChunk( nLen ); | ||
755 | |||
756 | cpy( pNew->pData, pData, nLen ); | ||
757 | |||
758 | _hardCopy(); | ||
759 | core->appendChunk( pNew ); | ||
760 | } | 792 | } |
761 | 793 | ||
762 | /** | 794 | /** |
@@ -767,15 +799,37 @@ namespace Bu | |||
767 | */ | 799 | */ |
768 | void append( const chr *pData, long nStart, long nLen ) | 800 | void append( const chr *pData, long nStart, long nLen ) |
769 | { | 801 | { |
770 | if( nLen == 0 ) | 802 | if( !pData ) return; |
803 | if( nLen <= 0 ) | ||
771 | return; | 804 | return; |
772 | 805 | ||
773 | Chunk *pNew = core->newChunk( nLen ); | 806 | pData += nStart; |
774 | |||
775 | cpy( pNew->pData, pData+nStart, nLen ); | ||
776 | 807 | ||
777 | _hardCopy(); | 808 | _hardCopy(); |
778 | core->appendChunk( pNew ); | 809 | |
810 | if( core->pLast && core->pLast->nLength < nMinSize ) | ||
811 | { | ||
812 | int nAmnt = nMinSize - core->pLast->nLength; | ||
813 | if( nAmnt > nLen ) | ||
814 | nAmnt = nLen; | ||
815 | cpy( | ||
816 | core->pLast->pData+core->pLast->nLength, | ||
817 | pData, | ||
818 | nAmnt | ||
819 | ); | ||
820 | pData += nAmnt; | ||
821 | core->pLast->nLength += nAmnt; | ||
822 | nLen -= nAmnt; | ||
823 | core->nLength += nAmnt; | ||
824 | } | ||
825 | |||
826 | if( nLen > 0 ) | ||
827 | { | ||
828 | Chunk *pNew = core->newChunk( nLen ); | ||
829 | cpy( pNew->pData, pData, nLen ); | ||
830 | core->appendChunk( pNew ); | ||
831 | // core->nLength += nLen; | ||
832 | } | ||
779 | } | 833 | } |
780 | 834 | ||
781 | /** | 835 | /** |
@@ -804,7 +858,7 @@ namespace Bu | |||
804 | */ | 858 | */ |
805 | void append( const MyType & sData ) | 859 | void append( const MyType & sData ) |
806 | { | 860 | { |
807 | append( sData.getStr(), sData.getSize() ); | 861 | append( sData.getStr(), 0, sData.getSize() ); |
808 | } | 862 | } |
809 | 863 | ||
810 | /** | 864 | /** |
@@ -815,7 +869,7 @@ namespace Bu | |||
815 | */ | 869 | */ |
816 | void append( const MyType & sData, long nLen ) | 870 | void append( const MyType & sData, long nLen ) |
817 | { | 871 | { |
818 | append( sData.getStr(), nLen ); | 872 | append( sData.getStr(), 0, nLen ); |
819 | } | 873 | } |
820 | 874 | ||
821 | /** | 875 | /** |
@@ -1029,7 +1083,7 @@ namespace Bu | |||
1029 | */ | 1083 | */ |
1030 | void insert( long nPos, const chr *pData ) | 1084 | void insert( long nPos, const chr *pData ) |
1031 | { | 1085 | { |
1032 | insert( nPos, pData, strlen( pData ) ); | 1086 | insert( nPos, pData, Bu::strlen( pData ) ); |
1033 | } | 1087 | } |
1034 | 1088 | ||
1035 | void remove( long nPos, long nLen ) | 1089 | void remove( long nPos, long nLen ) |
@@ -1155,13 +1209,13 @@ namespace Bu | |||
1155 | if( iStart < 0 ) | 1209 | if( iStart < 0 ) |
1156 | iStart = 0; | 1210 | iStart = 0; |
1157 | if( iStart >= core->nLength ) | 1211 | if( iStart >= core->nLength ) |
1158 | return ""; | 1212 | return (const chr[]){(chr)0}; |
1159 | if( iSize < 0 ) | 1213 | if( iSize < 0 ) |
1160 | iSize = core->nLength; | 1214 | iSize = core->nLength; |
1161 | if( iStart+iSize > core->nLength ) | 1215 | if( iStart+iSize > core->nLength ) |
1162 | iSize = core->nLength-iStart; | 1216 | iSize = core->nLength-iStart; |
1163 | if( iSize == 0 ) | 1217 | if( iSize == 0 ) |
1164 | return ""; | 1218 | return (const chr[]){(chr)0}; |
1165 | 1219 | ||
1166 | flatten(); | 1220 | flatten(); |
1167 | MyType ret( core->pFirst->pData+iStart, iSize ); | 1221 | MyType ret( core->pFirst->pData+iStart, iSize ); |
@@ -1212,37 +1266,6 @@ namespace Bu | |||
1212 | } | 1266 | } |
1213 | } | 1267 | } |
1214 | 1268 | ||
1215 | /** | ||
1216 | * (std::string compatability) Get a pointer to the string array. | ||
1217 | *@returns (chr *) The string data. | ||
1218 | */ | ||
1219 | DEPRECATED | ||
1220 | chr *c_str() | ||
1221 | { | ||
1222 | if( core->pFirst == NULL || core->nLength == 0 ) | ||
1223 | return NULL; | ||
1224 | |||
1225 | flatten(); | ||
1226 | _hardCopy(); | ||
1227 | core->pFirst->pData[core->nLength] = (chr)0; | ||
1228 | return core->pFirst->pData; | ||
1229 | } | ||
1230 | |||
1231 | /** | ||
1232 | * (std::string compatability) Get a const pointer to the string array. | ||
1233 | *@returns (const chr *) The string data. | ||
1234 | */ | ||
1235 | DEPRECATED | ||
1236 | const chr *c_str() const | ||
1237 | { | ||
1238 | if( core->pFirst == NULL || core->nLength == 0 ) | ||
1239 | return NULL; | ||
1240 | |||
1241 | flatten(); | ||
1242 | core->pFirst->pData[core->nLength] = (chr)0; | ||
1243 | return core->pFirst->pData; | ||
1244 | } | ||
1245 | |||
1246 | Bu::List<MyType> split( const chr c ) const | 1269 | Bu::List<MyType> split( const chr c ) const |
1247 | { | 1270 | { |
1248 | Bu::List<MyType> ret; | 1271 | Bu::List<MyType> ret; |
@@ -1423,11 +1446,11 @@ namespace Bu | |||
1423 | wordexp_t result; | 1446 | wordexp_t result; |
1424 | 1447 | ||
1425 | /* Expand the string for the program to run. */ | 1448 | /* Expand the string for the program to run. */ |
1426 | switch (wordexp (core->pFirst->pData, &result, 0)) | 1449 | switch (wordexp ((char *)core->pFirst->pData, &result, 0)) |
1427 | { | 1450 | { |
1428 | case 0: /* Successful. */ | 1451 | case 0: /* Successful. */ |
1429 | { | 1452 | { |
1430 | set( result.we_wordv[0] ); | 1453 | set( (chr *)result.we_wordv[0] ); |
1431 | wordfree( &result ); | 1454 | wordfree( &result ); |
1432 | return; | 1455 | return; |
1433 | } | 1456 | } |
@@ -1941,7 +1964,7 @@ namespace Bu | |||
1941 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1964 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
1942 | 1965 | ||
1943 | Chunk *pNew = core->newChunk( iLen ); | 1966 | Chunk *pNew = core->newChunk( iLen ); |
1944 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 1967 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
1945 | core->appendChunk( pNew ); | 1968 | core->appendChunk( pNew ); |
1946 | 1969 | ||
1947 | va_end( ap ); | 1970 | va_end( ap ); |
@@ -1958,7 +1981,7 @@ namespace Bu | |||
1958 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1981 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
1959 | 1982 | ||
1960 | Chunk *pNew = core->newChunk( iLen ); | 1983 | Chunk *pNew = core->newChunk( iLen ); |
1961 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 1984 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
1962 | core->appendChunk( pNew ); | 1985 | core->appendChunk( pNew ); |
1963 | 1986 | ||
1964 | va_end( ap ); | 1987 | va_end( ap ); |
@@ -1975,7 +1998,7 @@ namespace Bu | |||
1975 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); | 1998 | long iLen = vsnprintf( NULL, 0, sFrmt, ap ); |
1976 | 1999 | ||
1977 | Chunk *pNew = core->newChunk( iLen ); | 2000 | Chunk *pNew = core->newChunk( iLen ); |
1978 | vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); | 2001 | vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap ); |
1979 | core->prependChunk( pNew ); | 2002 | core->prependChunk( pNew ); |
1980 | 2003 | ||
1981 | va_end( ap ); | 2004 | va_end( ap ); |
diff --git a/src/file.cpp b/src/file.cpp index 0566ee8..008b88e 100644 --- a/src/file.cpp +++ b/src/file.cpp | |||
@@ -11,7 +11,6 @@ | |||
11 | #include <sys/stat.h> | 11 | #include <sys/stat.h> |
12 | #include <fcntl.h> | 12 | #include <fcntl.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <stdlib.h> // for mkstemp | ||
15 | #include <time.h> | 14 | #include <time.h> |
16 | 15 | ||
17 | #include "bu/config.h" | 16 | #include "bu/config.h" |
@@ -12,7 +12,8 @@ | |||
12 | #include "bu/exceptionbase.h" | 12 | #include "bu/exceptionbase.h" |
13 | #include "bu/list.h" | 13 | #include "bu/list.h" |
14 | #include "bu/util.h" | 14 | #include "bu/util.h" |
15 | #include "archivebase.h" | 15 | #include "bu/archivebase.h" |
16 | #include "bu/sharedcore.h" | ||
16 | 17 | ||
17 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) | 18 | #define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) |
18 | 19 | ||
@@ -49,138 +50,357 @@ namespace Bu | |||
49 | } | 50 | } |
50 | }; | 51 | }; |
51 | 52 | ||
52 | template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<value>, typename challoc = std::allocator<uint32_t> > | 53 | template<typename key, typename value, typename sizecalc, typename keyalloc, |
54 | typename valuealloc, typename challoc> | ||
53 | class Hash; | 55 | class Hash; |
54 | 56 | ||
55 | template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator<uint32_t> > | 57 | /** @cond DEVEL */ |
56 | struct HashProxy | 58 | template<typename key, typename value, typename sizecalc, typename keyalloc, |
59 | typename valuealloc, typename challoc > | ||
60 | class HashCore | ||
57 | { | 61 | { |
58 | friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>; | 62 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; |
63 | friend class SharedCore< | ||
64 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>, | ||
65 | HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> | ||
66 | >; | ||
59 | private: | 67 | private: |
60 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, const key *k, uint32_t nPos, uint32_t hash ) : | 68 | HashCore() : |
61 | hsh( h ), | 69 | nCapacity( 0 ), |
62 | pKey( k ), | 70 | nFilled( 0 ), |
63 | nPos( nPos ), | 71 | nDeleted( 0 ), |
64 | hash( hash ), | 72 | bFilled( NULL ), |
65 | bFilled( false ) | 73 | bDeleted( NULL ), |
74 | aKeys( NULL ), | ||
75 | aValues( NULL ), | ||
76 | aHashCodes( NULL ) | ||
66 | { | 77 | { |
67 | } | 78 | } |
68 | 79 | ||
69 | HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : | 80 | virtual ~HashCore() |
70 | hsh( h ), | ||
71 | nPos( nPos ), | ||
72 | pValue( pValue ), | ||
73 | bFilled( true ) | ||
74 | { | 81 | { |
82 | clear(); | ||
75 | } | 83 | } |
76 | 84 | ||
77 | Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; | 85 | void init() |
78 | const key *pKey; | 86 | { |
79 | uint32_t nPos; | 87 | if( nCapacity > 0 ) |
80 | _value *pValue; | 88 | return; |
81 | uint32_t hash; | ||
82 | bool bFilled; | ||
83 | 89 | ||
84 | public: | 90 | nCapacity = 11; |
85 | /** | 91 | nKeysSize = bitsToBytes( nCapacity ); |
86 | * Cast operator for HashProxy. | 92 | bFilled = ca.allocate( nKeysSize ); |
87 | *@returns (value_type &) The value the HashProxy is pointing to. | 93 | bDeleted = ca.allocate( nKeysSize ); |
88 | */ | 94 | clearBits(); |
89 | operator _value &() | 95 | |
96 | aHashCodes = ca.allocate( nCapacity ); | ||
97 | aKeys = ka.allocate( nCapacity ); | ||
98 | aValues = va.allocate( nCapacity ); | ||
99 | } | ||
100 | |||
101 | void clearBits() | ||
90 | { | 102 | { |
91 | if( bFilled == false ) | 103 | if( nCapacity == 0 ) |
92 | throw HashException( | 104 | return; |
93 | excodeNotFilled, | 105 | |
94 | "No data assosiated with that key." | 106 | for( uint32_t j = 0; j < nKeysSize; j++ ) |
95 | ); | 107 | { |
96 | return *pValue; | 108 | bFilled[j] = bDeleted[j] = 0; |
109 | } | ||
97 | } | 110 | } |
98 | 111 | ||
99 | /** | 112 | void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) |
100 | * Direct function for retrieving a value out of the HashProxy. | ||
101 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
102 | */ | ||
103 | DEPRECATED | ||
104 | _value &value() | ||
105 | { | 113 | { |
106 | if( bFilled == false ) | 114 | init(); |
107 | throw HashException( | 115 | |
108 | excodeNotFilled, | 116 | bFilled[loc/32] |= (1<<(loc%32)); |
109 | "No data assosiated with that key." | 117 | va.construct( &aValues[loc], v ); |
110 | ); | 118 | ka.construct( &aKeys[loc], k ); |
111 | return *pValue; | 119 | aHashCodes[loc] = hash; |
120 | nFilled++; | ||
121 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
122 | // nFilled, nDeleted, nCapacity ); | ||
123 | } | ||
124 | |||
125 | void _erase( uint32_t loc ) | ||
126 | { | ||
127 | if( nCapacity == 0 ) | ||
128 | return; | ||
129 | |||
130 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
131 | va.destroy( &aValues[loc] ); | ||
132 | ka.destroy( &aKeys[loc] ); | ||
133 | nDeleted++; | ||
134 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
135 | // nFilled, nDeleted, nCapacity ); | ||
136 | } | ||
137 | |||
138 | key &getKeyAtPos( uint32_t nPos ) | ||
139 | { | ||
140 | if( nPos >= nCapacity ) | ||
141 | throw HashException("Referenced position invalid."); | ||
142 | return aKeys[nPos]; | ||
112 | } | 143 | } |
113 | 144 | ||
114 | /** | 145 | const key &getKeyAtPos( uint32_t nPos ) const |
115 | * Direct function for retrieving a value out of the HashProxy. | ||
116 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
117 | */ | ||
118 | _value &getValue() | ||
119 | { | 146 | { |
120 | if( bFilled == false ) | 147 | if( nPos >= nCapacity ) |
121 | throw HashException( | 148 | throw HashException("Referenced position invalid."); |
122 | excodeNotFilled, | 149 | return aKeys[nPos]; |
123 | "No data assosiated with that key." | 150 | } |
124 | ); | 151 | |
125 | return *pValue; | 152 | value &getValueAtPos( uint32_t nPos ) |
153 | { | ||
154 | if( nPos >= nCapacity ) | ||
155 | throw HashException("Referenced position invalid."); | ||
156 | return aValues[nPos]; | ||
157 | } | ||
158 | |||
159 | const value &getValueAtPos( uint32_t nPos ) const | ||
160 | { | ||
161 | if( nPos >= nCapacity ) | ||
162 | throw HashException("Referenced position invalid."); | ||
163 | return aValues[nPos]; | ||
126 | } | 164 | } |
127 | 165 | ||
128 | /** | 166 | uint32_t getFirstPos( bool &bFinished ) const |
129 | * Whether this HashProxy points to something real or not. | 167 | { |
130 | */ | 168 | for( uint32_t j = 0; j < nCapacity; j++ ) |
131 | bool isFilled() | 169 | { |
170 | if( isFilled( j ) ) | ||
171 | if( !isDeleted( j ) ) | ||
172 | return j; | ||
173 | } | ||
174 | |||
175 | bFinished = true; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
132 | { | 180 | { |
133 | return bFilled; | 181 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) |
182 | { | ||
183 | if( isFilled( j ) ) | ||
184 | if( !isDeleted( j ) ) | ||
185 | return j; | ||
186 | } | ||
187 | |||
188 | bFinished = true; | ||
189 | return 0; | ||
134 | } | 190 | } |
135 | 191 | ||
136 | /** | 192 | uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) |
137 | * Erase the data pointed to by this HashProxy. | ||
138 | */ | ||
139 | void erase() | ||
140 | { | 193 | { |
141 | if( bFilled ) | 194 | init(); |
195 | |||
196 | uint32_t nCur = hash%nCapacity; | ||
197 | |||
198 | // First we scan to see if the key is already there, abort if we | ||
199 | // run out of probing room, or we find a non-filled entry | ||
200 | int8_t j; | ||
201 | for( j = 0; | ||
202 | isFilled( nCur ) && j < 32; | ||
203 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
204 | ) | ||
205 | { | ||
206 | // Is this the same hash code we were looking for? | ||
207 | if( hash == aHashCodes[nCur] ) | ||
208 | { | ||
209 | // Skip over deleted entries. Deleted entries are also filled, | ||
210 | // so we only have to do this check here. | ||
211 | if( isDeleted( nCur ) ) | ||
212 | continue; | ||
213 | |||
214 | // Is it really the same key? (for safety) | ||
215 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
216 | { | ||
217 | bFill = true; | ||
218 | return nCur; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | // This is our insurance, if the table is full, then go ahead and | ||
224 | // rehash, then try again. | ||
225 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
142 | { | 226 | { |
143 | hsh._erase( nPos ); | 227 | reHash( szCalc( nCapacity, nFilled, nDeleted ) ); |
144 | hsh.onDelete(); | 228 | |
229 | // This is potentially dangerous, and could cause an infinite loop. | ||
230 | // Be careful writing probe, eh? | ||
231 | return probe( hash, k, bFill ); | ||
145 | } | 232 | } |
233 | |||
234 | bFill = false; | ||
235 | return nCur; | ||
146 | } | 236 | } |
237 | |||
238 | uint32_t probe( uint32_t hash, key k, bool &bFill ) const | ||
239 | { | ||
240 | if( nCapacity == 0 ) | ||
241 | throw Bu::ExceptionBase("Probe in empty hash table."); | ||
147 | 242 | ||
148 | /** | 243 | uint32_t nCur = hash%nCapacity; |
149 | * Assign data to this point in the hash table. | 244 | |
150 | *@param nval (value_type) the data to assign. | 245 | // First we scan to see if the key is already there, abort if we |
151 | */ | 246 | // run out of probing room, or we find a non-filled entry |
152 | _value operator=( _value nval ) | 247 | for( int8_t j = 0; |
248 | isFilled( nCur ) && j < 32; | ||
249 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
250 | ) | ||
251 | { | ||
252 | // Is this the same hash code we were looking for? | ||
253 | if( hash == aHashCodes[nCur] ) | ||
254 | { | ||
255 | // Skip over deleted entries. Deleted entries are also filled, | ||
256 | // so we only have to do this check here. | ||
257 | if( isDeleted( nCur ) ) | ||
258 | continue; | ||
259 | |||
260 | // Is it really the same key? (for safety) | ||
261 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
262 | { | ||
263 | bFill = true; | ||
264 | return nCur; | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | bFill = false; | ||
270 | return nCur; | ||
271 | } | ||
272 | |||
273 | void insert( const key &k, const value &v ) | ||
153 | { | 274 | { |
154 | if( bFilled ) | 275 | uint32_t hash = __calcHashCode( k ); |
276 | bool bFill; | ||
277 | uint32_t nPos = probe( hash, k, bFill ); | ||
278 | |||
279 | if( bFill ) | ||
155 | { | 280 | { |
156 | hsh.va.destroy( &hsh.aValues[nPos] ); | 281 | va.destroy( &aValues[nPos] ); |
157 | hsh.va.construct( &hsh.aValues[nPos], nval ); | 282 | va.construct( &aValues[nPos], v ); |
158 | hsh.onUpdate(); | ||
159 | } | 283 | } |
160 | else | 284 | else |
161 | { | 285 | { |
162 | hsh.fill( nPos, *pKey, nval, hash ); | 286 | fill( nPos, k, v, hash ); |
163 | hsh.onInsert(); | 287 | } |
288 | } | ||
289 | |||
290 | void reHash( uint32_t nNewSize ) | ||
291 | { | ||
292 | //printf("---REHASH---"); | ||
293 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
294 | // nFilled, nDeleted, nCapacity ); | ||
295 | |||
296 | // Save all the old data | ||
297 | uint32_t nOldCapacity = nCapacity; | ||
298 | uint32_t *bOldFilled = bFilled; | ||
299 | uint32_t *aOldHashCodes = aHashCodes; | ||
300 | uint32_t nOldKeysSize = nKeysSize; | ||
301 | uint32_t *bOldDeleted = bDeleted; | ||
302 | value *aOldValues = aValues; | ||
303 | key *aOldKeys = aKeys; | ||
304 | |||
305 | // Calculate new sizes | ||
306 | nCapacity = nNewSize; | ||
307 | nKeysSize = bitsToBytes( nCapacity ); | ||
308 | |||
309 | // Allocate new memory + prep | ||
310 | bFilled = ca.allocate( nKeysSize ); | ||
311 | bDeleted = ca.allocate( nKeysSize ); | ||
312 | clearBits(); | ||
313 | |||
314 | aHashCodes = ca.allocate( nCapacity ); | ||
315 | aKeys = ka.allocate( nCapacity ); | ||
316 | aValues = va.allocate( nCapacity ); | ||
317 | |||
318 | nDeleted = nFilled = 0; | ||
319 | |||
320 | // Re-insert all of the old data (except deleted items) | ||
321 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
322 | { | ||
323 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
324 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
325 | { | ||
326 | insert( aOldKeys[j], aOldValues[j] ); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | // Delete all of the old data | ||
331 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
332 | { | ||
333 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
334 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
335 | { | ||
336 | va.destroy( &aOldValues[j] ); | ||
337 | ka.destroy( &aOldKeys[j] ); | ||
338 | } | ||
164 | } | 339 | } |
340 | va.deallocate( aOldValues, nOldCapacity ); | ||
341 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
342 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
343 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
344 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
345 | } | ||
165 | 346 | ||
166 | return nval; | 347 | bool isFilled( uint32_t loc ) const |
348 | { | ||
349 | if( loc >= nCapacity ) | ||
350 | throw HashException("Referenced position invalid."); | ||
351 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
167 | } | 352 | } |
168 | 353 | ||
169 | /** | 354 | bool isDeleted( uint32_t loc ) const |
170 | * Pointer extraction operator. Access to members of data pointed to | ||
171 | * by HashProxy. | ||
172 | *@returns (value_type *) | ||
173 | */ | ||
174 | _value *operator->() | ||
175 | { | 355 | { |
176 | if( bFilled == false ) | 356 | if( loc >= nCapacity ) |
177 | throw HashException( | 357 | throw HashException("Referenced position invalid."); |
178 | excodeNotFilled, | 358 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; |
179 | "No data assosiated with that key." | 359 | } |
180 | ); | 360 | |
181 | return pValue; | 361 | void clear() |
362 | { | ||
363 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
364 | { | ||
365 | if( isFilled( j ) ) | ||
366 | if( !isDeleted( j ) ) | ||
367 | { | ||
368 | va.destroy( &aValues[j] ); | ||
369 | ka.destroy( &aKeys[j] ); | ||
370 | } | ||
371 | } | ||
372 | va.deallocate( aValues, nCapacity ); | ||
373 | ka.deallocate( aKeys, nCapacity ); | ||
374 | ca.deallocate( bFilled, nKeysSize ); | ||
375 | ca.deallocate( bDeleted, nKeysSize ); | ||
376 | ca.deallocate( aHashCodes, nCapacity ); | ||
377 | |||
378 | bFilled = NULL; | ||
379 | bDeleted = NULL; | ||
380 | aKeys = NULL; | ||
381 | aValues = NULL; | ||
382 | aHashCodes = NULL; | ||
383 | |||
384 | nCapacity = 0; | ||
385 | nFilled = 0; | ||
386 | nDeleted = 0; | ||
182 | } | 387 | } |
388 | |||
389 | uint32_t nCapacity; | ||
390 | uint32_t nFilled; | ||
391 | uint32_t nDeleted; | ||
392 | uint32_t *bFilled; | ||
393 | uint32_t *bDeleted; | ||
394 | uint32_t nKeysSize; | ||
395 | key *aKeys; | ||
396 | value *aValues; | ||
397 | uint32_t *aHashCodes; | ||
398 | valuealloc va; | ||
399 | keyalloc ka; | ||
400 | challoc ca; | ||
401 | sizecalc szCalc; | ||
183 | }; | 402 | }; |
403 | /** @endcond */ | ||
184 | 404 | ||
185 | /** | 405 | /** |
186 | * Libbu++ Template Hash Table. This is your average hash table, that uses | 406 | * Libbu++ Template Hash Table. This is your average hash table, that uses |
@@ -224,119 +444,38 @@ namespace Bu | |||
224 | *@param challoc (typename) Byte allocator for bitflags | 444 | *@param challoc (typename) Byte allocator for bitflags |
225 | *@ingroup Containers | 445 | *@ingroup Containers |
226 | */ | 446 | */ |
227 | template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > | 447 | template<typename key, typename value, |
228 | class Hash | 448 | typename sizecalc = __calcNextTSize_fast, |
449 | typename keyalloc = std::allocator<key>, | ||
450 | typename valuealloc = std::allocator<value>, | ||
451 | typename challoc = std::allocator<uint32_t> | ||
452 | > | ||
453 | class Hash : public SharedCore< | ||
454 | Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>, | ||
455 | HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> | ||
456 | > | ||
229 | { | 457 | { |
230 | friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>; | 458 | private: |
459 | typedef class HashCore<key, value, sizecalc, keyalloc, valuealloc, challoc> Core; | ||
231 | typedef class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> MyType; | 460 | typedef class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> MyType; |
461 | protected: | ||
462 | using SharedCore<MyType, Core>::core; | ||
463 | using SharedCore<MyType, Core>::_hardCopy; | ||
464 | using SharedCore<MyType, Core>::_resetCore; | ||
465 | using SharedCore<MyType, Core>::_allocateCore; | ||
466 | |||
232 | public: | 467 | public: |
233 | Hash() : | 468 | Hash() |
234 | nCapacity( 11 ), | ||
235 | nFilled( 0 ), | ||
236 | nDeleted( 0 ), | ||
237 | bFilled( NULL ), | ||
238 | bDeleted( NULL ), | ||
239 | aKeys( NULL ), | ||
240 | aValues( NULL ), | ||
241 | aHashCodes( NULL ) | ||
242 | { | ||
243 | nKeysSize = bitsToBytes( nCapacity ); | ||
244 | bFilled = ca.allocate( nKeysSize ); | ||
245 | bDeleted = ca.allocate( nKeysSize ); | ||
246 | clearBits(); | ||
247 | |||
248 | aHashCodes = ca.allocate( nCapacity ); | ||
249 | aKeys = ka.allocate( nCapacity ); | ||
250 | aValues = va.allocate( nCapacity ); | ||
251 | } | ||
252 | |||
253 | Hash( const Hash &src ) : | ||
254 | nCapacity( src.nCapacity ), | ||
255 | nFilled( 0 ), | ||
256 | nDeleted( 0 ), | ||
257 | bFilled( NULL ), | ||
258 | bDeleted( NULL ), | ||
259 | aKeys( NULL ), | ||
260 | aValues( NULL ), | ||
261 | aHashCodes( NULL ) | ||
262 | { | 469 | { |
263 | nKeysSize = bitsToBytes( nCapacity ); | ||
264 | bFilled = ca.allocate( nKeysSize ); | ||
265 | bDeleted = ca.allocate( nKeysSize ); | ||
266 | clearBits(); | ||
267 | |||
268 | aHashCodes = ca.allocate( nCapacity ); | ||
269 | aKeys = ka.allocate( nCapacity ); | ||
270 | aValues = va.allocate( nCapacity ); | ||
271 | |||
272 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
273 | { | ||
274 | if( src.isFilled( j ) && !src.isDeleted( j ) ) | ||
275 | { | ||
276 | insert( src.aKeys[j], src.aValues[j] ); | ||
277 | } | ||
278 | } | ||
279 | } | 470 | } |
280 | 471 | ||
281 | /** | 472 | Hash( const MyType &src ) : |
282 | * Hashtable assignment operator. Clears this hashtable and | 473 | SharedCore<MyType, Core >( src ) |
283 | * copies RH into it. | ||
284 | */ | ||
285 | Hash &operator=( const Hash &src ) | ||
286 | { | 474 | { |
287 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
288 | { | ||
289 | if( isFilled( j ) && !isDeleted( j ) ) | ||
290 | { | ||
291 | va.destroy( &aValues[j] ); | ||
292 | ka.destroy( &aKeys[j] ); | ||
293 | } | ||
294 | } | ||
295 | va.deallocate( aValues, nCapacity ); | ||
296 | ka.deallocate( aKeys, nCapacity ); | ||
297 | ca.deallocate( bFilled, nKeysSize ); | ||
298 | ca.deallocate( bDeleted, nKeysSize ); | ||
299 | ca.deallocate( aHashCodes, nCapacity ); | ||
300 | |||
301 | nFilled = 0; | ||
302 | nDeleted = 0; | ||
303 | nCapacity = src.nCapacity; | ||
304 | nKeysSize = bitsToBytes( nCapacity ); | ||
305 | bFilled = ca.allocate( nKeysSize ); | ||
306 | bDeleted = ca.allocate( nKeysSize ); | ||
307 | clearBits(); | ||
308 | |||
309 | aHashCodes = ca.allocate( nCapacity ); | ||
310 | aKeys = ka.allocate( nCapacity ); | ||
311 | aValues = va.allocate( nCapacity ); | ||
312 | |||
313 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
314 | { | ||
315 | if( src.isFilled( j ) && !src.isDeleted( j ) ) | ||
316 | { | ||
317 | insert( src.aKeys[j], src.aValues[j] ); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | return *this; | ||
322 | } | 475 | } |
323 | 476 | ||
324 | virtual ~Hash() | 477 | virtual ~Hash() |
325 | { | 478 | { |
326 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
327 | { | ||
328 | if( isFilled( j ) ) | ||
329 | if( !isDeleted( j ) ) | ||
330 | { | ||
331 | va.destroy( &aValues[j] ); | ||
332 | ka.destroy( &aKeys[j] ); | ||
333 | } | ||
334 | } | ||
335 | va.deallocate( aValues, nCapacity ); | ||
336 | ka.deallocate( aKeys, nCapacity ); | ||
337 | ca.deallocate( bFilled, nKeysSize ); | ||
338 | ca.deallocate( bDeleted, nKeysSize ); | ||
339 | ca.deallocate( aHashCodes, nCapacity ); | ||
340 | } | 479 | } |
341 | 480 | ||
342 | /** | 481 | /** |
@@ -345,7 +484,7 @@ namespace Bu | |||
345 | */ | 484 | */ |
346 | uint32_t getCapacity() const | 485 | uint32_t getCapacity() const |
347 | { | 486 | { |
348 | return nCapacity; | 487 | return core->nCapacity; |
349 | } | 488 | } |
350 | 489 | ||
351 | /** | 490 | /** |
@@ -355,7 +494,7 @@ namespace Bu | |||
355 | */ | 494 | */ |
356 | uint32_t getFill() const | 495 | uint32_t getFill() const |
357 | { | 496 | { |
358 | return nFilled; | 497 | return core->nFilled; |
359 | } | 498 | } |
360 | 499 | ||
361 | /** | 500 | /** |
@@ -364,12 +503,12 @@ namespace Bu | |||
364 | */ | 503 | */ |
365 | uint32_t getSize() const | 504 | uint32_t getSize() const |
366 | { | 505 | { |
367 | return nFilled-nDeleted; | 506 | return core->nFilled-core->nDeleted; |
368 | } | 507 | } |
369 | 508 | ||
370 | bool isEmpty() const | 509 | bool isEmpty() const |
371 | { | 510 | { |
372 | return (nFilled-nDeleted) == 0; | 511 | return (core->nFilled-core->nDeleted) == 0; |
373 | } | 512 | } |
374 | 513 | ||
375 | /** | 514 | /** |
@@ -379,27 +518,140 @@ namespace Bu | |||
379 | */ | 518 | */ |
380 | uint32_t getDeleted() const | 519 | uint32_t getDeleted() const |
381 | { | 520 | { |
382 | return nDeleted; | 521 | return core->nDeleted; |
383 | } | 522 | } |
384 | 523 | ||
524 | struct HashProxy | ||
525 | { | ||
526 | friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; | ||
527 | private: | ||
528 | HashProxy( MyType &h, const key *k, uint32_t nPos, uint32_t hash ) : | ||
529 | hsh( h ), | ||
530 | pKey( k ), | ||
531 | nPos( nPos ), | ||
532 | hash( hash ), | ||
533 | bFilled( false ) | ||
534 | { | ||
535 | } | ||
536 | |||
537 | HashProxy( MyType &h, uint32_t nPos, value *pValue ) : | ||
538 | hsh( h ), | ||
539 | nPos( nPos ), | ||
540 | pValue( pValue ), | ||
541 | bFilled( true ) | ||
542 | { | ||
543 | } | ||
544 | |||
545 | MyType &hsh; | ||
546 | const key *pKey; | ||
547 | uint32_t nPos; | ||
548 | value *pValue; | ||
549 | uint32_t hash; | ||
550 | bool bFilled; | ||
551 | |||
552 | public: | ||
553 | /** | ||
554 | * Cast operator for HashProxy. | ||
555 | *@returns (value_type &) The value the HashProxy is pointing to. | ||
556 | */ | ||
557 | operator value &() | ||
558 | { | ||
559 | if( bFilled == false ) | ||
560 | throw HashException( | ||
561 | excodeNotFilled, | ||
562 | "No data assosiated with that key." | ||
563 | ); | ||
564 | return *pValue; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * Direct function for retrieving a value out of the HashProxy. | ||
569 | *@returns (value_type &) The value pointed to by this HashProxy. | ||
570 | */ | ||
571 | value &getValue() | ||
572 | { | ||
573 | if( bFilled == false ) | ||
574 | throw HashException( | ||
575 | excodeNotFilled, | ||
576 | "No data assosiated with that key." | ||
577 | ); | ||
578 | return *pValue; | ||
579 | } | ||
580 | |||
581 | /** | ||
582 | * Whether this HashProxy points to something real or not. | ||
583 | */ | ||
584 | bool isFilled() | ||
585 | { | ||
586 | return bFilled; | ||
587 | } | ||
588 | |||
589 | /** | ||
590 | * Erase the data pointed to by this HashProxy. | ||
591 | */ | ||
592 | void erase() | ||
593 | { | ||
594 | if( bFilled ) | ||
595 | { | ||
596 | hsh.core->_erase( nPos ); | ||
597 | } | ||
598 | } | ||
599 | |||
600 | /** | ||
601 | * Assign data to this point in the hash table. | ||
602 | *@param nval (value_type) the data to assign. | ||
603 | */ | ||
604 | value operator=( value nval ) | ||
605 | { | ||
606 | if( bFilled ) | ||
607 | { | ||
608 | hsh.core->va.destroy( &hsh.core->aValues[nPos] ); | ||
609 | hsh.core->va.construct( &hsh.core->aValues[nPos], nval ); | ||
610 | } | ||
611 | else | ||
612 | { | ||
613 | hsh.core->fill( nPos, *pKey, nval, hash ); | ||
614 | } | ||
615 | |||
616 | return nval; | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * Pointer extraction operator. Access to members of data pointed to | ||
621 | * by HashProxy. | ||
622 | *@returns (value_type *) | ||
623 | */ | ||
624 | value *operator->() | ||
625 | { | ||
626 | if( bFilled == false ) | ||
627 | throw HashException( | ||
628 | excodeNotFilled, | ||
629 | "No data assosiated with that key." | ||
630 | ); | ||
631 | return pValue; | ||
632 | } | ||
633 | }; | ||
634 | |||
385 | /** | 635 | /** |
386 | * Hash table index operator | 636 | * Hash table index operator |
387 | *@param k (key_type) Key of data to be retrieved. | 637 | *@param k (key_type) Key of data to be retrieved. |
388 | *@returns (HashProxy) Proxy pointing to the data. | 638 | *@returns (HashProxy) Proxy pointing to the data. |
389 | */ | 639 | */ |
390 | virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( const key &k ) | 640 | HashProxy operator[]( const key &k ) |
391 | { | 641 | { |
642 | _hardCopy(); | ||
643 | |||
392 | uint32_t hash = __calcHashCode( k ); | 644 | uint32_t hash = __calcHashCode( k ); |
393 | bool bFill; | 645 | bool bFill; |
394 | uint32_t nPos = probe( hash, k, bFill ); | 646 | uint32_t nPos = core->probe( hash, k, bFill ); |
395 | 647 | ||
396 | if( bFill ) | 648 | if( bFill ) |
397 | { | 649 | { |
398 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); | 650 | return HashProxy( *this, nPos, &core->aValues[nPos] ); |
399 | } | 651 | } |
400 | else | 652 | else |
401 | { | 653 | { |
402 | return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); | 654 | return HashProxy( *this, &k, nPos, hash ); |
403 | } | 655 | } |
404 | } | 656 | } |
405 | 657 | ||
@@ -408,39 +660,28 @@ namespace Bu | |||
408 | *@param k (key_type) Key to list the value under. | 660 | *@param k (key_type) Key to list the value under. |
409 | *@param v (value_type) Value to store in the hash table. | 661 | *@param v (value_type) Value to store in the hash table. |
410 | */ | 662 | */ |
411 | virtual void insert( const key &k, const value &v ) | 663 | void insert( const key &k, const value &v ) |
412 | { | 664 | { |
413 | uint32_t hash = __calcHashCode( k ); | 665 | _hardCopy(); |
414 | bool bFill; | ||
415 | uint32_t nPos = probe( hash, k, bFill ); | ||
416 | 666 | ||
417 | if( bFill ) | 667 | core->insert( k, v ); |
418 | { | ||
419 | va.destroy( &aValues[nPos] ); | ||
420 | va.construct( &aValues[nPos], v ); | ||
421 | onUpdate(); | ||
422 | } | ||
423 | else | ||
424 | { | ||
425 | fill( nPos, k, v, hash ); | ||
426 | onInsert(); | ||
427 | } | ||
428 | } | 668 | } |
429 | 669 | ||
430 | /** | 670 | /** |
431 | * Remove a value from the hash table. | 671 | * Remove a value from the hash table. |
432 | *@param k (key_type) The data under this key will be erased. | 672 | *@param k (key_type) The data under this key will be erased. |
433 | */ | 673 | */ |
434 | virtual void erase( const key &k ) | 674 | void erase( const key &k ) |
435 | { | 675 | { |
676 | _hardCopy(); | ||
677 | |||
436 | uint32_t hash = __calcHashCode( k ); | 678 | uint32_t hash = __calcHashCode( k ); |
437 | bool bFill; | 679 | bool bFill; |
438 | uint32_t nPos = probe( hash, k, bFill ); | 680 | uint32_t nPos = core->probe( hash, k, bFill ); |
439 | 681 | ||
440 | if( bFill ) | 682 | if( bFill ) |
441 | { | 683 | { |
442 | _erase( nPos ); | 684 | core->_erase( nPos ); |
443 | onDelete(); | ||
444 | } | 685 | } |
445 | } | 686 | } |
446 | 687 | ||
@@ -450,14 +691,16 @@ namespace Bu | |||
450 | * Remove a value from the hash pointed to from an iterator. | 691 | * Remove a value from the hash pointed to from an iterator. |
451 | *@param i (iterator &) The data to be erased. | 692 | *@param i (iterator &) The data to be erased. |
452 | */ | 693 | */ |
453 | virtual void erase( struct iterator &i ) | 694 | void erase( struct iterator &i ) |
454 | { | 695 | { |
455 | if( this != i.hsh ) | 696 | if( this != i.hsh ) |
456 | throw HashException("This iterator didn't come from this Hash."); | 697 | throw HashException("This iterator didn't come from this Hash."); |
457 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) | 698 | |
699 | _hardCopy(); | ||
700 | |||
701 | if( core->isFilled( i.nPos ) && !core->isDeleted( i.nPos ) ) | ||
458 | { | 702 | { |
459 | _erase( i.nPos ); | 703 | core->_erase( i.nPos ); |
460 | onDelete(); | ||
461 | } | 704 | } |
462 | } | 705 | } |
463 | 706 | ||
@@ -466,17 +709,7 @@ namespace Bu | |||
466 | */ | 709 | */ |
467 | virtual void clear() | 710 | virtual void clear() |
468 | { | 711 | { |
469 | for( uint32_t j = 0; j < nCapacity; j++ ) | 712 | _resetCore(); |
470 | { | ||
471 | if( isFilled( j ) ) | ||
472 | if( !isDeleted( j ) ) | ||
473 | { | ||
474 | _erase( j ); | ||
475 | onDelete(); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | clearBits(); | ||
480 | } | 713 | } |
481 | 714 | ||
482 | /** | 715 | /** |
@@ -484,15 +717,17 @@ namespace Bu | |||
484 | *@param k (key_type) Key pointing to the data to be retrieved. | 717 | *@param k (key_type) Key pointing to the data to be retrieved. |
485 | *@returns (value_type &) The data pointed to by (k). | 718 | *@returns (value_type &) The data pointed to by (k). |
486 | */ | 719 | */ |
487 | virtual value &get( const key &k ) | 720 | value &get( const key &k ) |
488 | { | 721 | { |
722 | _hardCopy(); | ||
723 | |||
489 | uint32_t hash = __calcHashCode( k ); | 724 | uint32_t hash = __calcHashCode( k ); |
490 | bool bFill; | 725 | bool bFill; |
491 | uint32_t nPos = probe( hash, k, bFill, false ); | 726 | uint32_t nPos = core->probe( hash, k, bFill, false ); |
492 | 727 | ||
493 | if( bFill ) | 728 | if( bFill ) |
494 | { | 729 | { |
495 | return aValues[nPos]; | 730 | return core->aValues[nPos]; |
496 | } | 731 | } |
497 | else | 732 | else |
498 | { | 733 | { |
@@ -509,15 +744,15 @@ namespace Bu | |||
509 | *@returns (const value_type &) A const version of the data pointed | 744 | *@returns (const value_type &) A const version of the data pointed |
510 | * to by (k). | 745 | * to by (k). |
511 | */ | 746 | */ |
512 | virtual const value &get( const key &k ) const | 747 | const value &get( const key &k ) const |
513 | { | 748 | { |
514 | uint32_t hash = __calcHashCode( k ); | 749 | uint32_t hash = __calcHashCode( k ); |
515 | bool bFill; | 750 | bool bFill; |
516 | uint32_t nPos = probe( hash, k, bFill ); | 751 | uint32_t nPos = core->probe( hash, k, bFill ); |
517 | 752 | ||
518 | if( bFill ) | 753 | if( bFill ) |
519 | { | 754 | { |
520 | return aValues[nPos]; | 755 | return core->aValues[nPos]; |
521 | } | 756 | } |
522 | else | 757 | else |
523 | { | 758 | { |
@@ -533,18 +768,10 @@ namespace Bu | |||
533 | *@param k (key_type) The key to check. | 768 | *@param k (key_type) The key to check. |
534 | *@returns (bool) Whether there was an item in the hash under key (k). | 769 | *@returns (bool) Whether there was an item in the hash under key (k). |
535 | */ | 770 | */ |
536 | virtual bool has( const key &k ) | 771 | bool has( const key &k ) const |
537 | { | 772 | { |
538 | bool bFill; | 773 | bool bFill; |
539 | probe( __calcHashCode( k ), k, bFill, false ); | 774 | core->probe( __calcHashCode( k ), k, bFill ); |
540 | |||
541 | return bFill; | ||
542 | } | ||
543 | |||
544 | virtual bool has( const key &k ) const | ||
545 | { | ||
546 | bool bFill; | ||
547 | probe( __calcHashCode( k ), k, bFill ); | ||
548 | 775 | ||
549 | return bFill; | 776 | return bFill; |
550 | } | 777 | } |
@@ -561,7 +788,7 @@ namespace Bu | |||
561 | nPos( 0 ), | 788 | nPos( 0 ), |
562 | bFinished( false ) | 789 | bFinished( false ) |
563 | { | 790 | { |
564 | nPos = hsh->getFirstPos( bFinished ); | 791 | nPos = hsh->core->getFirstPos( bFinished ); |
565 | } | 792 | } |
566 | 793 | ||
567 | iterator( MyType *hsh, bool bDone ) : | 794 | iterator( MyType *hsh, bool bDone ) : |
@@ -590,11 +817,6 @@ namespace Bu | |||
590 | { | 817 | { |
591 | } | 818 | } |
592 | 819 | ||
593 | DEPRECATED bool isActive() const | ||
594 | { | ||
595 | return !bFinished; | ||
596 | } | ||
597 | |||
598 | bool isValid() const | 820 | bool isValid() const |
599 | { | 821 | { |
600 | return !bFinished; | 822 | return !bFinished; |
@@ -611,7 +833,7 @@ namespace Bu | |||
611 | iterator operator++( int ) | 833 | iterator operator++( int ) |
612 | { | 834 | { |
613 | if( bFinished == false ) | 835 | if( bFinished == false ) |
614 | nPos = hsh->getNextPos( nPos, bFinished ); | 836 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
615 | 837 | ||
616 | return *this; | 838 | return *this; |
617 | } | 839 | } |
@@ -622,7 +844,7 @@ namespace Bu | |||
622 | iterator operator++() | 844 | iterator operator++() |
623 | { | 845 | { |
624 | if( bFinished == false ) | 846 | if( bFinished == false ) |
625 | nPos = hsh->getNextPos( nPos, bFinished ); | 847 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
626 | 848 | ||
627 | return *this; | 849 | return *this; |
628 | } | 850 | } |
@@ -671,21 +893,22 @@ namespace Bu | |||
671 | */ | 893 | */ |
672 | value &operator *() | 894 | value &operator *() |
673 | { | 895 | { |
674 | return hsh->getValueAtPos( nPos ); | 896 | hsh->_hardCopy(); |
897 | return hsh->core->getValueAtPos( nPos ); | ||
675 | } | 898 | } |
676 | 899 | ||
677 | const value &operator *() const | 900 | const value &operator *() const |
678 | { | 901 | { |
679 | return hsh->getValueAtPos( nPos ); | 902 | return hsh->core->getValueAtPos( nPos ); |
680 | } | 903 | } |
681 | 904 | ||
682 | /** | 905 | /** |
683 | * Get the key behind this iterator. | 906 | * Get the key behind this iterator. |
684 | *@returns (key_type &) The key behind this iterator. | 907 | *@returns (key_type &) The key behind this iterator. |
685 | */ | 908 | */ |
686 | key &getKey() | 909 | const key &getKey() const |
687 | { | 910 | { |
688 | return hsh->getKeyAtPos( nPos ); | 911 | return hsh->core->getKeyAtPos( nPos ); |
689 | } | 912 | } |
690 | 913 | ||
691 | /** | 914 | /** |
@@ -694,7 +917,17 @@ namespace Bu | |||
694 | */ | 917 | */ |
695 | value &getValue() | 918 | value &getValue() |
696 | { | 919 | { |
697 | return hsh->getValueAtPos( nPos ); | 920 | hsh->_hardCopy(); |
921 | return hsh->core->getValueAtPos( nPos ); | ||
922 | } | ||
923 | |||
924 | /** | ||
925 | * Get the value behind this iterator. | ||
926 | *@returns (value_type &) The value behind this iterator. | ||
927 | */ | ||
928 | const value &getValue() const | ||
929 | { | ||
930 | return hsh->core->getValueAtPos( nPos ); | ||
698 | } | 931 | } |
699 | } iterator; | 932 | } iterator; |
700 | 933 | ||
@@ -710,7 +943,7 @@ namespace Bu | |||
710 | nPos( 0 ), | 943 | nPos( 0 ), |
711 | bFinished( false ) | 944 | bFinished( false ) |
712 | { | 945 | { |
713 | nPos = hsh->getFirstPos( bFinished ); | 946 | nPos = hsh->core->getFirstPos( bFinished ); |
714 | } | 947 | } |
715 | 948 | ||
716 | const_iterator( const MyType *hsh, bool bDone ) : | 949 | const_iterator( const MyType *hsh, bool bDone ) : |
@@ -762,7 +995,7 @@ namespace Bu | |||
762 | const_iterator operator++( int ) | 995 | const_iterator operator++( int ) |
763 | { | 996 | { |
764 | if( bFinished == false ) | 997 | if( bFinished == false ) |
765 | nPos = hsh->getNextPos( nPos, bFinished ); | 998 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
766 | 999 | ||
767 | return *this; | 1000 | return *this; |
768 | } | 1001 | } |
@@ -773,7 +1006,7 @@ namespace Bu | |||
773 | const_iterator operator++() | 1006 | const_iterator operator++() |
774 | { | 1007 | { |
775 | if( bFinished == false ) | 1008 | if( bFinished == false ) |
776 | nPos = hsh->getNextPos( nPos, bFinished ); | 1009 | nPos = hsh->core->getNextPos( nPos, bFinished ); |
777 | 1010 | ||
778 | return *this; | 1011 | return *this; |
779 | } | 1012 | } |
@@ -822,7 +1055,7 @@ namespace Bu | |||
822 | */ | 1055 | */ |
823 | const value &operator *() const | 1056 | const value &operator *() const |
824 | { | 1057 | { |
825 | return hsh->getValueAtPos( nPos ); | 1058 | return hsh->core->getValueAtPos( nPos ); |
826 | } | 1059 | } |
827 | 1060 | ||
828 | /** | 1061 | /** |
@@ -831,7 +1064,7 @@ namespace Bu | |||
831 | */ | 1064 | */ |
832 | const key &getKey() const | 1065 | const key &getKey() const |
833 | { | 1066 | { |
834 | return hsh->getKeyAtPos( nPos ); | 1067 | return hsh->core->getKeyAtPos( nPos ); |
835 | } | 1068 | } |
836 | 1069 | ||
837 | /** | 1070 | /** |
@@ -840,7 +1073,7 @@ namespace Bu | |||
840 | */ | 1073 | */ |
841 | const value &getValue() const | 1074 | const value &getValue() const |
842 | { | 1075 | { |
843 | return hsh->getValueAtPos( nPos ); | 1076 | return hsh->core->getValueAtPos( nPos ); |
844 | } | 1077 | } |
845 | } const_iterator; | 1078 | } const_iterator; |
846 | 1079 | ||
@@ -883,13 +1116,13 @@ namespace Bu | |||
883 | { | 1116 | { |
884 | Bu::List<key> lKeys; | 1117 | Bu::List<key> lKeys; |
885 | 1118 | ||
886 | for( uint32_t j = 0; j < nCapacity; j++ ) | 1119 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
887 | { | 1120 | { |
888 | if( isFilled( j ) ) | 1121 | if( core->isFilled( j ) ) |
889 | { | 1122 | { |
890 | if( !isDeleted( j ) ) | 1123 | if( !core->isDeleted( j ) ) |
891 | { | 1124 | { |
892 | lKeys.append( aKeys[j] ); | 1125 | lKeys.append( core->aKeys[j] ); |
893 | } | 1126 | } |
894 | } | 1127 | } |
895 | } | 1128 | } |
@@ -901,13 +1134,13 @@ namespace Bu | |||
901 | { | 1134 | { |
902 | Bu::List<value> lValues; | 1135 | Bu::List<value> lValues; |
903 | 1136 | ||
904 | for( uint32_t j = 0; j < nCapacity; j++ ) | 1137 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
905 | { | 1138 | { |
906 | if( isFilled( j ) ) | 1139 | if( core->isFilled( j ) ) |
907 | { | 1140 | { |
908 | if( !isDeleted( j ) ) | 1141 | if( !core->isDeleted( j ) ) |
909 | { | 1142 | { |
910 | lValues.append( aValues[j] ); | 1143 | lValues.append( core->aValues[j] ); |
911 | } | 1144 | } |
912 | } | 1145 | } |
913 | } | 1146 | } |
@@ -915,244 +1148,74 @@ namespace Bu | |||
915 | return lValues; | 1148 | return lValues; |
916 | } | 1149 | } |
917 | 1150 | ||
918 | protected: | 1151 | bool operator==( const MyType &rhs ) const |
919 | virtual void onInsert() {} | ||
920 | virtual void onUpdate() {} | ||
921 | virtual void onDelete() {} | ||
922 | virtual void onReHash() {} | ||
923 | |||
924 | virtual void clearBits() | ||
925 | { | ||
926 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
927 | { | ||
928 | bFilled[j] = bDeleted[j] = 0; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | virtual void fill( uint32_t loc, const key &k, const value &v, uint32_t hash ) | ||
933 | { | ||
934 | bFilled[loc/32] |= (1<<(loc%32)); | ||
935 | va.construct( &aValues[loc], v ); | ||
936 | ka.construct( &aKeys[loc], k ); | ||
937 | aHashCodes[loc] = hash; | ||
938 | nFilled++; | ||
939 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
940 | // nFilled, nDeleted, nCapacity ); | ||
941 | } | ||
942 | |||
943 | virtual void _erase( uint32_t loc ) | ||
944 | { | ||
945 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
946 | va.destroy( &aValues[loc] ); | ||
947 | ka.destroy( &aKeys[loc] ); | ||
948 | nDeleted++; | ||
949 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
950 | // nFilled, nDeleted, nCapacity ); | ||
951 | } | ||
952 | |||
953 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
954 | { | ||
955 | return aKeys[nPos]; | ||
956 | } | ||
957 | |||
958 | virtual const key &getKeyAtPos( uint32_t nPos ) const | ||
959 | { | ||
960 | return aKeys[nPos]; | ||
961 | } | ||
962 | |||
963 | virtual value &getValueAtPos( uint32_t nPos ) | ||
964 | { | ||
965 | return aValues[nPos]; | ||
966 | } | ||
967 | |||
968 | virtual const value &getValueAtPos( uint32_t nPos ) const | ||
969 | { | ||
970 | return aValues[nPos]; | ||
971 | } | ||
972 | |||
973 | virtual uint32_t getFirstPos( bool &bFinished ) const | ||
974 | { | ||
975 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
976 | { | ||
977 | if( isFilled( j ) ) | ||
978 | if( !isDeleted( j ) ) | ||
979 | return j; | ||
980 | } | ||
981 | |||
982 | bFinished = true; | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
987 | { | 1152 | { |
988 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) | 1153 | if( this == &rhs ) |
989 | { | 1154 | return true; |
990 | if( isFilled( j ) ) | 1155 | if( core == rhs.core ) |
991 | if( !isDeleted( j ) ) | 1156 | return true; |
992 | return j; | 1157 | if( core == NULL || rhs.core == NULL ) |
993 | } | 1158 | return false; |
994 | 1159 | if( getSize() != rhs.getSize() ) | |
995 | bFinished = true; | 1160 | return false; |
996 | return 0; | 1161 | |
997 | } | 1162 | for( uint32_t j = 0; j < core->nCapacity; j++ ) |
998 | |||
999 | uint32_t probe( uint32_t hash, const key &k, bool &bFill, bool rehash=true ) | ||
1000 | { | ||
1001 | uint32_t nCur = hash%nCapacity; | ||
1002 | |||
1003 | // First we scan to see if the key is already there, abort if we | ||
1004 | // run out of probing room, or we find a non-filled entry | ||
1005 | int8_t j; | ||
1006 | for( j = 0; | ||
1007 | isFilled( nCur ) && j < 32; | ||
1008 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
1009 | ) | ||
1010 | { | 1163 | { |
1011 | // Is this the same hash code we were looking for? | 1164 | if( core->isFilled( j ) ) |
1012 | if( hash == aHashCodes[nCur] ) | ||
1013 | { | 1165 | { |
1014 | // Skip over deleted entries. Deleted entries are also filled, | 1166 | if( !core->isDeleted( j ) ) |
1015 | // so we only have to do this check here. | ||
1016 | if( isDeleted( nCur ) ) | ||
1017 | continue; | ||
1018 | |||
1019 | // Is it really the same key? (for safety) | ||
1020 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
1021 | { | 1167 | { |
1022 | bFill = true; | 1168 | // Check to see if this key is in the other hash |
1023 | return nCur; | 1169 | if( rhs.has( core->aKeys[j] ) ) |
1170 | { | ||
1171 | if( !(core->aValues[j] == rhs.get( core->aKeys[j]) ) ) | ||
1172 | { | ||
1173 | return false; | ||
1174 | } | ||
1175 | } | ||
1176 | else | ||
1177 | { | ||
1178 | return false; | ||
1179 | } | ||
1024 | } | 1180 | } |
1025 | } | 1181 | } |
1026 | } | 1182 | } |
1027 | 1183 | ||
1028 | // This is our insurance, if the table is full, then go ahead and | 1184 | return true; |
1029 | // rehash, then try again. | ||
1030 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
1031 | { | ||
1032 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | ||
1033 | |||
1034 | // This is potentially dangerous, and could cause an infinite loop. | ||
1035 | // Be careful writing probe, eh? | ||
1036 | return probe( hash, k, bFill ); | ||
1037 | } | ||
1038 | |||
1039 | bFill = false; | ||
1040 | return nCur; | ||
1041 | } | 1185 | } |
1042 | |||
1043 | uint32_t probe( uint32_t hash, key k, bool &bFill ) const | ||
1044 | { | ||
1045 | uint32_t nCur = hash%nCapacity; | ||
1046 | |||
1047 | // First we scan to see if the key is already there, abort if we | ||
1048 | // run out of probing room, or we find a non-filled entry | ||
1049 | for( int8_t j = 0; | ||
1050 | isFilled( nCur ) && j < 32; | ||
1051 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
1052 | ) | ||
1053 | { | ||
1054 | // Is this the same hash code we were looking for? | ||
1055 | if( hash == aHashCodes[nCur] ) | ||
1056 | { | ||
1057 | // Skip over deleted entries. Deleted entries are also filled, | ||
1058 | // so we only have to do this check here. | ||
1059 | if( isDeleted( nCur ) ) | ||
1060 | continue; | ||
1061 | |||
1062 | // Is it really the same key? (for safety) | ||
1063 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
1064 | { | ||
1065 | bFill = true; | ||
1066 | return nCur; | ||
1067 | } | ||
1068 | } | ||
1069 | } | ||
1070 | 1186 | ||
1071 | bFill = false; | 1187 | bool operator!=( const MyType &rhs ) const |
1072 | return nCur; | 1188 | { |
1189 | return !(*this == rhs); | ||
1073 | } | 1190 | } |
1074 | 1191 | ||
1075 | void reHash( uint32_t nNewSize ) | 1192 | protected: |
1193 | virtual Core *_copyCore( Core *src ) | ||
1076 | { | 1194 | { |
1077 | //printf("---REHASH---"); | 1195 | Core *pRet = _allocateCore(); |
1078 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
1079 | // nFilled, nDeleted, nCapacity ); | ||
1080 | |||
1081 | // Save all the old data | ||
1082 | uint32_t nOldCapacity = nCapacity; | ||
1083 | uint32_t *bOldFilled = bFilled; | ||
1084 | uint32_t *aOldHashCodes = aHashCodes; | ||
1085 | uint32_t nOldKeysSize = nKeysSize; | ||
1086 | uint32_t *bOldDeleted = bDeleted; | ||
1087 | value *aOldValues = aValues; | ||
1088 | key *aOldKeys = aKeys; | ||
1089 | |||
1090 | // Calculate new sizes | ||
1091 | nCapacity = nNewSize; | ||
1092 | nKeysSize = bitsToBytes( nCapacity ); | ||
1093 | |||
1094 | // Allocate new memory + prep | ||
1095 | bFilled = ca.allocate( nKeysSize ); | ||
1096 | bDeleted = ca.allocate( nKeysSize ); | ||
1097 | clearBits(); | ||
1098 | 1196 | ||
1099 | aHashCodes = ca.allocate( nCapacity ); | 1197 | pRet->nFilled = 0; |
1100 | aKeys = ka.allocate( nCapacity ); | 1198 | pRet->nDeleted = 0; |
1101 | aValues = va.allocate( nCapacity ); | 1199 | pRet->nCapacity = src->nCapacity; |
1102 | 1200 | pRet->nKeysSize = bitsToBytes( pRet->nCapacity ); | |
1103 | nDeleted = nFilled = 0; | 1201 | pRet->bFilled = pRet->ca.allocate( pRet->nKeysSize ); |
1202 | pRet->bDeleted = pRet->ca.allocate( pRet->nKeysSize ); | ||
1203 | pRet->clearBits(); | ||
1104 | 1204 | ||
1105 | // Re-insert all of the old data (except deleted items) | 1205 | pRet->aHashCodes = pRet->ca.allocate( pRet->nCapacity ); |
1106 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | 1206 | pRet->aKeys = pRet->ka.allocate( pRet->nCapacity ); |
1107 | { | 1207 | pRet->aValues = pRet->va.allocate( pRet->nCapacity ); |
1108 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
1109 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
1110 | { | ||
1111 | insert( aOldKeys[j], aOldValues[j] ); | ||
1112 | } | ||
1113 | } | ||
1114 | 1208 | ||
1115 | // Delete all of the old data | 1209 | for( uint32_t j = 0; j < src->nCapacity; j++ ) |
1116 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
1117 | { | 1210 | { |
1118 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | 1211 | if( src->isFilled( j ) && !src->isDeleted( j ) ) |
1119 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
1120 | { | 1212 | { |
1121 | va.destroy( &aOldValues[j] ); | 1213 | pRet->insert( src->aKeys[j], src->aValues[j] ); |
1122 | ka.destroy( &aOldKeys[j] ); | ||
1123 | } | 1214 | } |
1124 | } | 1215 | } |
1125 | va.deallocate( aOldValues, nOldCapacity ); | ||
1126 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
1127 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
1128 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
1129 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
1130 | } | ||
1131 | 1216 | ||
1132 | virtual bool isFilled( uint32_t loc ) const | 1217 | return pRet; |
1133 | { | ||
1134 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
1135 | } | ||
1136 | |||
1137 | virtual bool isDeleted( uint32_t loc ) const | ||
1138 | { | ||
1139 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; | ||
1140 | } | 1218 | } |
1141 | |||
1142 | protected: | ||
1143 | uint32_t nCapacity; | ||
1144 | uint32_t nFilled; | ||
1145 | uint32_t nDeleted; | ||
1146 | uint32_t *bFilled; | ||
1147 | uint32_t *bDeleted; | ||
1148 | uint32_t nKeysSize; | ||
1149 | key *aKeys; | ||
1150 | value *aValues; | ||
1151 | uint32_t *aHashCodes; | ||
1152 | valuealloc va; | ||
1153 | keyalloc ka; | ||
1154 | challoc ca; | ||
1155 | sizecalc szCalc; | ||
1156 | }; | 1219 | }; |
1157 | 1220 | ||
1158 | template<typename T> uint32_t __calcHashCode( const T &k ) | 1221 | template<typename T> uint32_t __calcHashCode( const T &k ) |
@@ -13,76 +13,93 @@ | |||
13 | #include "bu/exceptionbase.h" | 13 | #include "bu/exceptionbase.h" |
14 | #include "bu/util.h" | 14 | #include "bu/util.h" |
15 | #include "bu/queue.h" | 15 | #include "bu/queue.h" |
16 | #include "bu/sharedcore.h" | ||
16 | 17 | ||
17 | namespace Bu | 18 | namespace Bu |
18 | { | 19 | { |
19 | subExceptionDecl( HeapException ); | 20 | subExceptionDecl( HeapException ); |
20 | 21 | ||
21 | /** | 22 | template<typename item, typename cmpfunc, typename itemalloc> |
22 | * A priority queue that allows for an unlimited number of priorities. All | 23 | class Heap; |
23 | * objects enqueued must support less-than-comparison. Then every time an | 24 | |
24 | * item is dequeued it is always the least item in the heap. The heap | 25 | /** @cond DEVEL */ |
25 | * operates using a binary tree for storage, which allows most operations | 26 | template<typename item, typename cmpfunc, typename itemalloc> |
26 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | 27 | class HeapCore |
27 | * whereas peeking is constant time. | ||
28 | * | ||
29 | * This heap implementation allows iterating, however please note that any | ||
30 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
31 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
32 | * the items are not stored in memory in order, they are optomized into a | ||
33 | * tree. This means that the items will be in effectively random order | ||
34 | * while iterating through them, and the order cannot be trusted. Also, | ||
35 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
36 | * If you want to change the position of an item in the heap you will have | ||
37 | * to dequeue every item before it, dequeue that item, change it, and | ||
38 | * re-enqueue all of the items removed. | ||
39 | */ | ||
40 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
41 | class Heap : public Queue<item> | ||
42 | { | 28 | { |
43 | public: | 29 | friend class Heap<item, cmpfunc, itemalloc>; |
44 | Heap() : | 30 | friend class SharedCore< |
45 | iSize( 7 ), | 31 | Heap<item, cmpfunc, itemalloc>, HeapCore<item, cmpfunc, itemalloc> |
32 | >; | ||
33 | private: | ||
34 | HeapCore() : | ||
35 | iSize( 0 ), | ||
46 | iFill( 0 ), | 36 | iFill( 0 ), |
47 | aItem( ia.allocate( iSize ) ) | 37 | aItem( NULL ) |
48 | { | 38 | { |
49 | } | 39 | } |
50 | 40 | ||
51 | Heap( cmpfunc cmpin ) : | 41 | virtual ~HeapCore() |
52 | iSize( 7 ), | ||
53 | iFill( 0 ), | ||
54 | aItem( ia.allocate( iSize ) ), | ||
55 | cmp( cmpin ) | ||
56 | { | 42 | { |
43 | clear(); | ||
57 | } | 44 | } |
58 | 45 | ||
59 | Heap( int iInitialCapacity ) : | 46 | void init() |
60 | iSize( 0 ), | ||
61 | iFill( 0 ), | ||
62 | aItem( NULL ) | ||
63 | { | 47 | { |
64 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 48 | if( iSize > 0 ) |
49 | return; | ||
50 | |||
51 | iSize = 7; | ||
52 | iFill = 0; | ||
65 | aItem = ia.allocate( iSize ); | 53 | aItem = ia.allocate( iSize ); |
66 | } | 54 | } |
67 | 55 | ||
68 | Heap( cmpfunc cmpin, int iInitialCapacity ) : | 56 | void init( int iCap ) |
69 | iSize( 0 ), | ||
70 | iFill( 0 ), | ||
71 | aItem( NULL ), | ||
72 | cmp( cmpin ) | ||
73 | { | 57 | { |
74 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 58 | if( iSize > 0 ) |
59 | return; | ||
60 | |||
61 | for( iSize = 1; iSize < iCap; iSize=iSize*2+1 ) { } | ||
62 | iFill = 0; | ||
75 | aItem = ia.allocate( iSize ); | 63 | aItem = ia.allocate( iSize ); |
76 | } | 64 | } |
77 | 65 | ||
78 | virtual ~Heap() | 66 | void clear() |
79 | { | 67 | { |
68 | if( iSize == 0 ) | ||
69 | return; | ||
70 | |||
80 | for( int j = 0; j < iFill; j++ ) | 71 | for( int j = 0; j < iFill; j++ ) |
81 | ia.destroy( &aItem[j] ); | 72 | ia.destroy( &aItem[j] ); |
82 | ia.deallocate( aItem, iSize ); | 73 | ia.deallocate( aItem, iSize ); |
83 | aItem = NULL; | 74 | aItem = NULL; |
75 | iSize = 0; | ||
76 | iFill = 0; | ||
84 | } | 77 | } |
78 | |||
79 | void upSize() | ||
80 | { | ||
81 | if( iSize == 0 ) | ||
82 | { | ||
83 | init(); | ||
84 | return; | ||
85 | } | ||
85 | 86 | ||
87 | item *aNewItems = ia.allocate( iSize*2+1 ); | ||
88 | // | ||
89 | // We cannot use a memcopy here because we don't know what kind | ||
90 | // of datastructures are being used, we have to copy them one at | ||
91 | // a time. | ||
92 | // | ||
93 | for( int j = 0; j < iFill; j++ ) | ||
94 | { | ||
95 | ia.construct( &aNewItems[j], aItem[j] ); | ||
96 | ia.destroy( &aItem[j] ); | ||
97 | } | ||
98 | ia.deallocate( aItem, iSize ); | ||
99 | aItem = aNewItems; | ||
100 | iSize = iSize*2+1; | ||
101 | } | ||
102 | |||
86 | virtual void enqueue( const item &it ) | 103 | virtual void enqueue( const item &it ) |
87 | { | 104 | { |
88 | item i = it; // TODO: This is a silly workaround, put the i item | 105 | item i = it; // TODO: This is a silly workaround, put the i item |
@@ -126,20 +143,6 @@ namespace Bu | |||
126 | iFill++; | 143 | iFill++; |
127 | } | 144 | } |
128 | 145 | ||
129 | virtual item &peek() | ||
130 | { | ||
131 | if( iFill == 0 ) | ||
132 | throw HeapException("Heap empty."); | ||
133 | return aItem[0]; | ||
134 | } | ||
135 | |||
136 | virtual const item &peek() const | ||
137 | { | ||
138 | if( iFill == 0 ) | ||
139 | throw HeapException("Heap empty."); | ||
140 | return aItem[0]; | ||
141 | } | ||
142 | |||
143 | virtual item dequeue() | 146 | virtual item dequeue() |
144 | { | 147 | { |
145 | if( iFill == 0 ) | 148 | if( iFill == 0 ) |
@@ -174,14 +177,118 @@ namespace Bu | |||
174 | return iRet; | 177 | return iRet; |
175 | } | 178 | } |
176 | 179 | ||
180 | private: | ||
181 | int iSize; | ||
182 | int iFill; | ||
183 | item *aItem; | ||
184 | cmpfunc cmp; | ||
185 | itemalloc ia; | ||
186 | }; | ||
187 | /** @endcond */ | ||
188 | |||
189 | /** | ||
190 | * A priority queue that allows for an unlimited number of priorities. All | ||
191 | * objects enqueued must support less-than-comparison. Then every time an | ||
192 | * item is dequeued it is always the least item in the heap. The heap | ||
193 | * operates using a binary tree for storage, which allows most operations | ||
194 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | ||
195 | * whereas peeking is constant time. | ||
196 | * | ||
197 | * This heap implementation allows iterating, however please note that any | ||
198 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
199 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
200 | * the items are not stored in memory in order, they are optomized into a | ||
201 | * tree. This means that the items will be in effectively random order | ||
202 | * while iterating through them, and the order cannot be trusted. Also, | ||
203 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
204 | * If you want to change the position of an item in the heap you will have | ||
205 | * to dequeue every item before it, dequeue that item, change it, and | ||
206 | * re-enqueue all of the items removed. | ||
207 | */ | ||
208 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
209 | class Heap : public Queue<item>, public SharedCore< | ||
210 | Heap<item, cmpfunc, itemalloc>, | ||
211 | HeapCore<item, cmpfunc, itemalloc> | ||
212 | > | ||
213 | { | ||
214 | private: | ||
215 | typedef class Heap<item,cmpfunc,itemalloc> MyType; | ||
216 | typedef class HeapCore<item,cmpfunc,itemalloc> Core; | ||
217 | |||
218 | protected: | ||
219 | using SharedCore<MyType, Core>::core; | ||
220 | using SharedCore<MyType, Core>::_hardCopy; | ||
221 | using SharedCore<MyType, Core>::_resetCore; | ||
222 | using SharedCore<MyType, Core>::_allocateCore; | ||
223 | |||
224 | public: | ||
225 | Heap() | ||
226 | { | ||
227 | } | ||
228 | |||
229 | Heap( cmpfunc cmpin ) | ||
230 | { | ||
231 | core->cmp = cmpin; | ||
232 | } | ||
233 | |||
234 | Heap( int iInitialCapacity ) | ||
235 | { | ||
236 | core->init( iInitialCapacity ); | ||
237 | } | ||
238 | |||
239 | Heap( cmpfunc cmpin, int iInitialCapacity ) | ||
240 | { | ||
241 | core->cmp = cmpin; | ||
242 | core->init( iInitialCapacity ); | ||
243 | } | ||
244 | |||
245 | Heap( const MyType &rSrc ) : | ||
246 | SharedCore<MyType, Core>( rSrc ) | ||
247 | { | ||
248 | } | ||
249 | |||
250 | virtual ~Heap() | ||
251 | { | ||
252 | } | ||
253 | |||
254 | virtual void enqueue( const item &it ) | ||
255 | { | ||
256 | _hardCopy(); | ||
257 | |||
258 | core->enqueue( it ); | ||
259 | } | ||
260 | |||
261 | virtual item &peek() | ||
262 | { | ||
263 | _hardCopy(); | ||
264 | |||
265 | if( core->iFill == 0 ) | ||
266 | throw HeapException("Heap empty."); | ||
267 | return core->aItem[0]; | ||
268 | } | ||
269 | |||
270 | virtual const item &peek() const | ||
271 | { | ||
272 | if( core->iFill == 0 ) | ||
273 | throw HeapException("Heap empty."); | ||
274 | return core->aItem[0]; | ||
275 | } | ||
276 | |||
277 | virtual item dequeue() | ||
278 | { | ||
279 | _hardCopy(); | ||
280 | |||
281 | return core->dequeue(); | ||
282 | } | ||
283 | |||
177 | virtual bool isEmpty() const | 284 | virtual bool isEmpty() const |
178 | { | 285 | { |
179 | return (iFill==0); | 286 | return (core->iFill==0); |
180 | } | 287 | } |
181 | 288 | ||
182 | virtual int getSize() const | 289 | virtual int getSize() const |
183 | { | 290 | { |
184 | return iFill; | 291 | return core->iFill; |
185 | } | 292 | } |
186 | 293 | ||
187 | class iterator | 294 | class iterator |
@@ -201,7 +308,7 @@ namespace Bu | |||
201 | { | 308 | { |
202 | if( pHeap == NULL ) | 309 | if( pHeap == NULL ) |
203 | throw Bu::ExceptionBase("Iterator not initialized."); | 310 | throw Bu::ExceptionBase("Iterator not initialized."); |
204 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 311 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
205 | throw Bu::ExceptionBase("Iterator out of bounds."); | 312 | throw Bu::ExceptionBase("Iterator out of bounds."); |
206 | } | 313 | } |
207 | 314 | ||
@@ -230,12 +337,16 @@ namespace Bu | |||
230 | 337 | ||
231 | item &operator*() | 338 | item &operator*() |
232 | { | 339 | { |
233 | return pHeap->aItem[iIndex]; | 340 | pHeap->_hardCopy(); |
341 | |||
342 | return pHeap->core->aItem[iIndex]; | ||
234 | } | 343 | } |
235 | 344 | ||
236 | item *operator->() | 345 | item *operator->() |
237 | { | 346 | { |
238 | return &(pHeap->aItem[iIndex]); | 347 | pHeap->_hardCopy(); |
348 | |||
349 | return &(pHeap->core->aItem[iIndex]); | ||
239 | } | 350 | } |
240 | 351 | ||
241 | iterator &operator++() | 352 | iterator &operator++() |
@@ -260,7 +371,7 @@ namespace Bu | |||
260 | { | 371 | { |
261 | checkValid(); | 372 | checkValid(); |
262 | iIndex++; | 373 | iIndex++; |
263 | if( iIndex >= pHeap->iFill ) | 374 | if( iIndex >= pHeap->core->iFill ) |
264 | iIndex = -1; | 375 | iIndex = -1; |
265 | 376 | ||
266 | return *this; | 377 | return *this; |
@@ -279,7 +390,7 @@ namespace Bu | |||
279 | checkValid(); | 390 | checkValid(); |
280 | iterator ret( *this ); | 391 | iterator ret( *this ); |
281 | ret.iIndex += iDelta; | 392 | ret.iIndex += iDelta; |
282 | if( ret.iIndex >= pHeap->iFill ) | 393 | if( ret.iIndex >= pHeap->core->iFill ) |
283 | ret.iIndex = -1; | 394 | ret.iIndex = -1; |
284 | return ret; | 395 | return ret; |
285 | } | 396 | } |
@@ -294,12 +405,12 @@ namespace Bu | |||
294 | return ret; | 405 | return ret; |
295 | } | 406 | } |
296 | 407 | ||
297 | operator bool() | 408 | operator bool() const |
298 | { | 409 | { |
299 | return iIndex != -1; | 410 | return iIndex != -1; |
300 | } | 411 | } |
301 | 412 | ||
302 | bool isValid() | 413 | bool isValid() const |
303 | { | 414 | { |
304 | return iIndex != -1; | 415 | return iIndex != -1; |
305 | } | 416 | } |
@@ -328,7 +439,7 @@ namespace Bu | |||
328 | { | 439 | { |
329 | if( pHeap == NULL ) | 440 | if( pHeap == NULL ) |
330 | throw Bu::ExceptionBase("Iterator not initialized."); | 441 | throw Bu::ExceptionBase("Iterator not initialized."); |
331 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 442 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
332 | throw Bu::ExceptionBase("Iterator out of bounds."); | 443 | throw Bu::ExceptionBase("Iterator out of bounds."); |
333 | } | 444 | } |
334 | 445 | ||
@@ -363,19 +474,23 @@ namespace Bu | |||
363 | 474 | ||
364 | const item &operator*() | 475 | const item &operator*() |
365 | { | 476 | { |
366 | return pHeap->aItem[iIndex]; | 477 | pHeap->_hardCopy(); |
478 | |||
479 | return pHeap->core->aItem[iIndex]; | ||
367 | } | 480 | } |
368 | 481 | ||
369 | const item *operator->() | 482 | const item *operator->() |
370 | { | 483 | { |
371 | return &(pHeap->aItem[iIndex]); | 484 | pHeap->_hardCopy(); |
485 | |||
486 | return &(pHeap->core->aItem[iIndex]); | ||
372 | } | 487 | } |
373 | 488 | ||
374 | const_iterator &operator++() | 489 | const_iterator &operator++() |
375 | { | 490 | { |
376 | checkValid(); | 491 | checkValid(); |
377 | iIndex++; | 492 | iIndex++; |
378 | if( iIndex >= pHeap->iFill ) | 493 | if( iIndex >= pHeap->core->iFill ) |
379 | iIndex = -1; | 494 | iIndex = -1; |
380 | 495 | ||
381 | return *this; | 496 | return *this; |
@@ -393,7 +508,7 @@ namespace Bu | |||
393 | { | 508 | { |
394 | checkValid(); | 509 | checkValid(); |
395 | iIndex++; | 510 | iIndex++; |
396 | if( iIndex >= pHeap->iFill ) | 511 | if( iIndex >= pHeap->core->iFill ) |
397 | iIndex = -1; | 512 | iIndex = -1; |
398 | 513 | ||
399 | return *this; | 514 | return *this; |
@@ -427,12 +542,12 @@ namespace Bu | |||
427 | return ret; | 542 | return ret; |
428 | } | 543 | } |
429 | 544 | ||
430 | operator bool() | 545 | operator bool() const |
431 | { | 546 | { |
432 | return iIndex != -1; | 547 | return iIndex != -1; |
433 | } | 548 | } |
434 | 549 | ||
435 | bool isValid() | 550 | bool isValid() const |
436 | { | 551 | { |
437 | return iIndex != -1; | 552 | return iIndex != -1; |
438 | } | 553 | } |
@@ -452,14 +567,14 @@ namespace Bu | |||
452 | 567 | ||
453 | iterator begin() | 568 | iterator begin() |
454 | { | 569 | { |
455 | if( iFill == 0 ) | 570 | if( core->iFill == 0 ) |
456 | return end(); | 571 | return end(); |
457 | return iterator( this, 0 ); | 572 | return iterator( this, 0 ); |
458 | } | 573 | } |
459 | 574 | ||
460 | const_iterator begin() const | 575 | const_iterator begin() const |
461 | { | 576 | { |
462 | if( iFill == 0 ) | 577 | if( core->iFill == 0 ) |
463 | return end(); | 578 | return end(); |
464 | return const_iterator( this, 0 ); | 579 | return const_iterator( this, 0 ); |
465 | } | 580 | } |
@@ -475,31 +590,22 @@ namespace Bu | |||
475 | } | 590 | } |
476 | 591 | ||
477 | 592 | ||
478 | private: | 593 | protected: |
479 | void upSize() | 594 | virtual Core *_copyCore( Core *src ) |
480 | { | 595 | { |
481 | item *aNewItems = ia.allocate( iSize*2+1 ); | 596 | Core *pRet = _allocateCore(); |
482 | // | 597 | |
483 | // We cannot use a memcopy here because we don't know what kind | 598 | pRet->iSize = src->iSize; |
484 | // of datastructures are being used, we have to copy them one at | 599 | pRet->iFill = src->iFill; |
485 | // a time. | 600 | pRet->cmp = src->cmp; |
486 | // | 601 | pRet->aItem = pRet->ia.allocate( pRet->iSize ); |
487 | for( int j = 0; j < iFill; j++ ) | 602 | for( int j = 0; j < pRet->iFill; j++ ) |
488 | { | 603 | { |
489 | ia.construct( &aNewItems[j], aItem[j] ); | 604 | pRet->ia.construct( &pRet->aItem[j], src->aItem[j] ); |
490 | ia.destroy( &aItem[j] ); | ||
491 | } | 605 | } |
492 | ia.deallocate( aItem, iSize ); | ||
493 | aItem = aNewItems; | ||
494 | iSize = iSize*2+1; | ||
495 | } | ||
496 | 606 | ||
497 | private: | 607 | return pRet; |
498 | int iSize; | 608 | } |
499 | int iFill; | ||
500 | item *aItem; | ||
501 | cmpfunc cmp; | ||
502 | itemalloc ia; | ||
503 | }; | 609 | }; |
504 | }; | 610 | }; |
505 | 611 | ||
diff --git a/src/httpget.h b/src/httpget.h index 410914c..783f880 100644 --- a/src/httpget.h +++ b/src/httpget.h | |||
@@ -11,7 +11,7 @@ | |||
11 | #include "bu/stream.h" | 11 | #include "bu/stream.h" |
12 | #include "bu/fstring.h" | 12 | #include "bu/fstring.h" |
13 | #include "bu/url.h" | 13 | #include "bu/url.h" |
14 | #include "bu/socket.h" | 14 | #include "bu/tcpsocket.h" |
15 | #include "bu/hash.h" | 15 | #include "bu/hash.h" |
16 | 16 | ||
17 | namespace Bu | 17 | namespace Bu |
@@ -52,7 +52,7 @@ namespace Bu | |||
52 | private: | 52 | private: |
53 | Bu::Url uSrc; | 53 | Bu::Url uSrc; |
54 | Bu::FString sMethod; | 54 | Bu::FString sMethod; |
55 | Bu::Socket sSrv; | 55 | Bu::TcpSocket sSrv; |
56 | typedef Bu::Hash<Bu::FString,Bu::FString> MimeHash; | 56 | typedef Bu::Hash<Bu::FString,Bu::FString> MimeHash; |
57 | MimeHash hMimeIn; | 57 | MimeHash hMimeIn; |
58 | MimeHash hMimeOut; | 58 | MimeHash hMimeOut; |
diff --git a/src/itoserver.cpp b/src/itoserver.cpp index a1d804a..ea737bf 100644 --- a/src/itoserver.cpp +++ b/src/itoserver.cpp | |||
@@ -7,9 +7,9 @@ | |||
7 | 7 | ||
8 | #include "bu/itoserver.h" | 8 | #include "bu/itoserver.h" |
9 | #include <errno.h> | 9 | #include <errno.h> |
10 | #include "bu/serversocket.h" | 10 | #include "bu/tcpserversocket.h" |
11 | #include "bu/client.h" | 11 | #include "bu/client.h" |
12 | #include "bu/socket.h" | 12 | #include "bu/tcpsocket.h" |
13 | 13 | ||
14 | #include "bu/config.h" | 14 | #include "bu/config.h" |
15 | 15 | ||
@@ -41,7 +41,7 @@ Bu::ItoServer::~ItoServer() | |||
41 | 41 | ||
42 | void Bu::ItoServer::addPort( int nPort, int nPoolSize ) | 42 | void Bu::ItoServer::addPort( int nPort, int nPoolSize ) |
43 | { | 43 | { |
44 | ServerSocket *s = new ServerSocket( nPort, nPoolSize ); | 44 | TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); |
45 | int nSocket = s->getSocket(); | 45 | int nSocket = s->getSocket(); |
46 | FD_SET( nSocket, &fdActive ); | 46 | FD_SET( nSocket, &fdActive ); |
47 | hServers.insert( nSocket, s ); | 47 | hServers.insert( nSocket, s ); |
@@ -49,7 +49,7 @@ void Bu::ItoServer::addPort( int nPort, int nPoolSize ) | |||
49 | 49 | ||
50 | void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) | 50 | void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) |
51 | { | 51 | { |
52 | ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); | 52 | TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); |
53 | int nSocket = s->getSocket(); | 53 | int nSocket = s->getSocket(); |
54 | FD_SET( nSocket, &fdActive ); | 54 | FD_SET( nSocket, &fdActive ); |
55 | hServers.insert( nSocket, s ); | 55 | hServers.insert( nSocket, s ); |
@@ -92,7 +92,7 @@ void Bu::ItoServer::run() | |||
92 | { | 92 | { |
93 | if( FD_ISSET( i.getKey(), &fdRead ) ) | 93 | if( FD_ISSET( i.getKey(), &fdRead ) ) |
94 | { | 94 | { |
95 | ServerSocket *pSrv = i.getValue(); | 95 | TcpServerSocket *pSrv = i.getValue(); |
96 | addClient( pSrv->accept(), pSrv->getPort() ); | 96 | addClient( pSrv->accept(), pSrv->getPort() ); |
97 | } | 97 | } |
98 | } | 98 | } |
@@ -126,7 +126,7 @@ Bu::ItoServer::ItoClient::ItoClient( ItoServer &rSrv, int iSocket, int iPort, | |||
126 | FD_SET( iSocket, &fdActive ); | 126 | FD_SET( iSocket, &fdActive ); |
127 | 127 | ||
128 | pClient = new Client( | 128 | pClient = new Client( |
129 | new Bu::Socket( iSocket ), | 129 | new Bu::TcpSocket( iSocket ), |
130 | new SrvClientLinkFactory( rSrv ) | 130 | new SrvClientLinkFactory( rSrv ) |
131 | ); | 131 | ); |
132 | } | 132 | } |
diff --git a/src/itoserver.h b/src/itoserver.h index c08d453..81e42cc 100644 --- a/src/itoserver.h +++ b/src/itoserver.h | |||
@@ -26,8 +26,8 @@ | |||
26 | 26 | ||
27 | namespace Bu | 27 | namespace Bu |
28 | { | 28 | { |
29 | class ServerSocket; | 29 | class TcpServerSocket; |
30 | class Socket; | 30 | class TcpSocket; |
31 | class Client; | 31 | class Client; |
32 | 32 | ||
33 | /** | 33 | /** |
@@ -126,7 +126,7 @@ namespace Bu | |||
126 | int nTimeoutSec; | 126 | int nTimeoutSec; |
127 | int nTimeoutUSec; | 127 | int nTimeoutUSec; |
128 | fd_set fdActive; | 128 | fd_set fdActive; |
129 | typedef Hash<int,ServerSocket *> ServerHash; | 129 | typedef Hash<int,TcpServerSocket *> ServerHash; |
130 | ServerHash hServers; | 130 | ServerHash hServers; |
131 | typedef Hash<int,ItoClient *> ClientHash; | 131 | typedef Hash<int,ItoClient *> ClientHash; |
132 | typedef ItoQueue<ItoClient *> ClientQueue; | 132 | typedef ItoQueue<ItoClient *> ClientQueue; |
diff --git a/src/lexer.h b/src/lexer.h index 2cb5f51..9840afe 100644 --- a/src/lexer.h +++ b/src/lexer.h | |||
@@ -36,6 +36,10 @@ namespace Bu | |||
36 | } | 36 | } |
37 | TokenType iToken; | 37 | TokenType iToken; |
38 | Bu::Variant vExtra; | 38 | Bu::Variant vExtra; |
39 | int iStartCol; | ||
40 | int iStartRow; | ||
41 | int iEndCol; | ||
42 | int iEndRow; | ||
39 | }; | 43 | }; |
40 | 44 | ||
41 | virtual Token *nextToken()=0; | 45 | virtual Token *nextToken()=0; |
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | namespace Bu | 17 | namespace Bu |
18 | { | 18 | { |
19 | /** @cond DEVEL */ | ||
19 | template<typename value> | 20 | template<typename value> |
20 | struct ListLink | 21 | struct ListLink |
21 | { | 22 | { |
@@ -24,10 +25,18 @@ namespace Bu | |||
24 | ListLink *pPrev; | 25 | ListLink *pPrev; |
25 | }; | 26 | }; |
26 | 27 | ||
27 | template<typename value, typename valuealloc, | 28 | template<typename value, typename valuealloc, typename linkalloc> |
28 | typename linkalloc> | 29 | class List; |
30 | |||
31 | template<typename value, typename valuealloc, typename linkalloc> | ||
29 | struct ListCore | 32 | struct ListCore |
30 | { | 33 | { |
34 | friend class List<value, valuealloc, linkalloc>; | ||
35 | friend class SharedCore< | ||
36 | List<value, valuealloc, linkalloc>, | ||
37 | ListCore<value, valuealloc, linkalloc> | ||
38 | >; | ||
39 | private: | ||
31 | typedef struct ListLink<value> Link; | 40 | typedef struct ListLink<value> Link; |
32 | ListCore() : | 41 | ListCore() : |
33 | pFirst( NULL ), | 42 | pFirst( NULL ), |
@@ -177,6 +186,7 @@ namespace Bu | |||
177 | } | 186 | } |
178 | } | 187 | } |
179 | }; | 188 | }; |
189 | /** @endcond */ | ||
180 | 190 | ||
181 | /** | 191 | /** |
182 | * Linked list template container. This class is similar to the stl list | 192 | * Linked list template container. This class is similar to the stl list |
@@ -189,12 +199,15 @@ namespace Bu | |||
189 | *@param value (typename) The type of data to store in your list | 199 | *@param value (typename) The type of data to store in your list |
190 | *@param valuealloc (typename) Memory Allocator for your value type | 200 | *@param valuealloc (typename) Memory Allocator for your value type |
191 | *@param linkalloc (typename) Memory Allocator for the list links. | 201 | *@param linkalloc (typename) Memory Allocator for the list links. |
202 | *@extends SharedCore | ||
192 | *@ingroup Containers | 203 | *@ingroup Containers |
193 | */ | 204 | */ |
194 | template<typename value, typename valuealloc=std::allocator<value>, | 205 | template<typename value, typename valuealloc=std::allocator<value>, |
195 | typename linkalloc=std::allocator<struct ListLink<value> > > | 206 | typename linkalloc=std::allocator<struct ListLink<value> > > |
196 | class List : public SharedCore< struct ListCore<value, valuealloc, | 207 | class List /** @cond */ : public SharedCore< |
197 | linkalloc> > | 208 | List<value, valuealloc, linkalloc>, |
209 | ListCore<value, valuealloc, linkalloc> | ||
210 | > /** @endcond */ | ||
198 | { | 211 | { |
199 | private: | 212 | private: |
200 | typedef struct ListLink<value> Link; | 213 | typedef struct ListLink<value> Link; |
@@ -202,9 +215,9 @@ namespace Bu | |||
202 | typedef struct ListCore<value, valuealloc, linkalloc> Core; | 215 | typedef struct ListCore<value, valuealloc, linkalloc> Core; |
203 | 216 | ||
204 | protected: | 217 | protected: |
205 | using SharedCore< Core >::core; | 218 | using SharedCore<MyType, Core>::core; |
206 | using SharedCore< Core >::_hardCopy; | 219 | using SharedCore<MyType, Core>::_hardCopy; |
207 | using SharedCore< Core >::_allocateCore; | 220 | using SharedCore<MyType, Core>::_allocateCore; |
208 | 221 | ||
209 | public: | 222 | public: |
210 | struct const_iterator; | 223 | struct const_iterator; |
@@ -215,7 +228,7 @@ namespace Bu | |||
215 | } | 228 | } |
216 | 229 | ||
217 | List( const MyType &src ) : | 230 | List( const MyType &src ) : |
218 | SharedCore< Core >( src ) | 231 | SharedCore<MyType, Core >( src ) |
219 | { | 232 | { |
220 | } | 233 | } |
221 | 234 | ||
diff --git a/src/listhash.cpp b/src/listhash.cpp deleted file mode 100644 index b798a1f..0000000 --- a/src/listhash.cpp +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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 | |||
diff --git a/src/listhash.h b/src/listhash.h deleted file mode 100644 index e5ec4ee..0000000 --- a/src/listhash.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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_LIST_HASH_H | ||
9 | #define BU_LIST_HASH_H | ||
10 | |||
11 | #include "bu/hash.h" | ||
12 | #include "bu/list.h" | ||
13 | |||
14 | namespace Bu | ||
15 | { | ||
16 | template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<Bu::List<value> >, typename challoc = std::allocator<uint32_t> > | ||
17 | class ListHash : public Hash<key, Bu::List<value>, sizecalc, keyalloc, valuealloc, challoc> | ||
18 | { | ||
19 | typedef Hash<key, Bu::List<value>, sizecalc, keyalloc, valuealloc, challoc> ParentType; | ||
20 | public: | ||
21 | ListHash() | ||
22 | { | ||
23 | } | ||
24 | |||
25 | ListHash( const ListHash &src ) : | ||
26 | ParentType( src ) | ||
27 | { | ||
28 | } | ||
29 | |||
30 | virtual ~ListHash() | ||
31 | { | ||
32 | } | ||
33 | |||
34 | ListHash &operator=( const ListHash &src ) | ||
35 | { | ||
36 | *dynamic_cast<ParentType *>(this) = | ||
37 | dynamic_cast<ParentType &>(src); | ||
38 | } | ||
39 | |||
40 | virtual void insert( const key &k, const value &v ) | ||
41 | { | ||
42 | if( !has( k ) ) | ||
43 | { | ||
44 | ParentType::insert( k, List<value>() ); | ||
45 | } | ||
46 | get( k ).append( v ); | ||
47 | } | ||
48 | |||
49 | private: | ||
50 | }; | ||
51 | |||
52 | }; | ||
53 | |||
54 | #endif | ||
diff --git a/src/myriad.h b/src/myriad.h index 3d203bb..582d310 100644 --- a/src/myriad.h +++ b/src/myriad.h | |||
@@ -46,7 +46,7 @@ namespace Bu | |||
46 | * Header format is as follows: | 46 | * Header format is as follows: |
47 | * | 47 | * |
48 | * MMMMvBssssSSSS* | 48 | * MMMMvBssssSSSS* |
49 | * M = Magic number (FFC399BD) | 49 | * M = Magic number (0AD3FA84) |
50 | * v = version number | 50 | * v = version number |
51 | * B = Bits per int | 51 | * B = Bits per int |
52 | * s = Blocksize in bytes | 52 | * s = Blocksize in bytes |
diff --git a/src/myriadfs.cpp b/src/myriadfs.cpp new file mode 100644 index 0000000..af60c08 --- /dev/null +++ b/src/myriadfs.cpp | |||
@@ -0,0 +1,78 @@ | |||
1 | #include "bu/myriadfs.h" | ||
2 | #include "bu/myriadstream.h" | ||
3 | |||
4 | #include <string.h> | ||
5 | #include <unistd.h> | ||
6 | |||
7 | namespace Bu { subExceptionDef( MyriadFsException ) } | ||
8 | |||
9 | #define Myriad_Fs_MAGIC_CODE ((char *)"\xa7\x18\x8b\x39") | ||
10 | |||
11 | Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : | ||
12 | rStore( rStore ), | ||
13 | mStore( rStore, iBlockSize ) | ||
14 | { | ||
15 | if( mStore.hasStream( 1 ) ) | ||
16 | { | ||
17 | // Check to see if this is a MyriadFs stream. | ||
18 | Bu::MyriadStream ms = mStore.openStream( 1 ); | ||
19 | char sMagic[4]; | ||
20 | if( ms.read( sMagic, 4 ) < 4 ) | ||
21 | throw MyriadFsException("The provided stream does not appear to be " | ||
22 | "a MyriadFs stream."); | ||
23 | if( ::strncmp( sMagic, Myriad_Fs_MAGIC_CODE, 4 ) ) | ||
24 | throw MyriadFsException("The provided stream does not appear to be " | ||
25 | "a MyriadFs stream."); | ||
26 | |||
27 | int8_t iVer; | ||
28 | } | ||
29 | else | ||
30 | { | ||
31 | // Create initial header stream | ||
32 | { | ||
33 | mStore.createStream( 1 ); | ||
34 | Bu::MyriadStream ms = mStore.openStream( 1 ); | ||
35 | ms.write( Myriad_Fs_MAGIC_CODE, 4 ); | ||
36 | int8_t iVer = 1; | ||
37 | int32_t iTmp = 1; | ||
38 | ms.write( &iVer, 1 ); | ||
39 | ms.write( &iBlockSize, 4 ); | ||
40 | ms.write( &iTmp, 4 ); // iNumNodes | ||
41 | iTmp = 0; | ||
42 | ms.write( &iTmp, 4 ); // iInode | ||
43 | ms.write( &iTmp, 0 ); // iPosition | ||
44 | } | ||
45 | |||
46 | // Create initial inode stream, with one root node. | ||
47 | { | ||
48 | mStore.createStream( 2 ); | ||
49 | Bu::MyriadStream ms = mStore.openStream( 2 ); | ||
50 | int32_t iUser = 0, iGroup = 0; | ||
51 | #ifndef WIN32 | ||
52 | iUser = getuid(); | ||
53 | iGroup = getgid(); | ||
54 | #endif | ||
55 | int32_t iTmp32 = 0; | ||
56 | int16_t iTmp16 = 0; | ||
57 | ms.write( &iUser, 4 ); | ||
58 | ms.write( &iGroup, 4 ); | ||
59 | ms.write( &iTmp16, 2 ); | ||
60 | ms.write( &iTmp16, 2 ); | ||
61 | iTmp32 = 3; | ||
62 | ms.write( &iTmp32, 4 ); | ||
63 | iTmp32 = 0; | ||
64 | ms.write( &iTmp32, 4 ); | ||
65 | ms.write( &iTmp16, 2 ); | ||
66 | } | ||
67 | |||
68 | // Create inode 0's storage stream. | ||
69 | { | ||
70 | mStore.createStream( 3 ); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | Bu::MyriadFs::~MyriadFs() | ||
76 | { | ||
77 | } | ||
78 | |||
diff --git a/src/myriadfs.h b/src/myriadfs.h new file mode 100644 index 0000000..42a3493 --- /dev/null +++ b/src/myriadfs.h | |||
@@ -0,0 +1,54 @@ | |||
1 | #ifndef MYRIAD_FS_H | ||
2 | #define MYRIAD_FS_H | ||
3 | |||
4 | #include "bu/myriad.h" | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | class Stream; | ||
9 | |||
10 | subExceptionDecl( MyriadFsException ); | ||
11 | |||
12 | /** | ||
13 | * A POSIX compliant, node based filesystem built on top of Myriad. | ||
14 | * | ||
15 | * A header is placed into stream 1. | ||
16 | * Header format: | ||
17 | * int32_t iMagicHeader (A7188B39) | ||
18 | * int8_t iVersion (1) | ||
19 | * int32_t iNodeSize | ||
20 | * int32_t iNumNodes | ||
21 | * NodeLookup[iNumNodes] nNode | ||
22 | * | ||
23 | * Node lookup: | ||
24 | * int32_t iInode | ||
25 | * int32_t iPosition | ||
26 | * | ||
27 | * The node headers or inode structures have a base size of 22 bytes. | ||
28 | * Everything else in the block is used for the name. I.e. if you have | ||
29 | * a blocksize of 512 bytes then you wind up with a max name size of | ||
30 | * 512-22=490 characters, or a blocksize of 256 gives you 234 chraacters | ||
31 | * as a max. The node headers are all stored in stream 2. | ||
32 | * Basic node header format: | ||
33 | * int32_t iUser | ||
34 | * int32_t iGroup | ||
35 | * int16_t iMeta | ||
36 | * int16_t iPerms | ||
37 | * int32_t iStreamIndex | ||
38 | * int32_t iParentNode | ||
39 | * int16_t iNameSize | ||
40 | * char[iNameSize] sName | ||
41 | */ | ||
42 | class MyriadFs | ||
43 | { | ||
44 | public: | ||
45 | MyriadFs( Bu::Stream &rStore, int iBlockSize=512 ); | ||
46 | virtual ~MyriadFs(); | ||
47 | |||
48 | private: | ||
49 | Bu::Stream &rStore; | ||
50 | Bu::Myriad mStore; | ||
51 | }; | ||
52 | }; | ||
53 | |||
54 | #endif | ||
diff --git a/src/newline.h b/src/newline.h index b69cdb5..243c876 100644 --- a/src/newline.h +++ b/src/newline.h | |||
@@ -14,7 +14,7 @@ namespace Bu | |||
14 | { | 14 | { |
15 | /** | 15 | /** |
16 | * Converts new-line characters from any standard convention into linefeeds | 16 | * Converts new-line characters from any standard convention into linefeeds |
17 | * (\n) on reading, and converts them to either your OS's standard or a | 17 | * (\\n) on reading, and converts them to either your OS's standard or a |
18 | * specified standard, depending on how you construct the class. | 18 | * specified standard, depending on how you construct the class. |
19 | * | 19 | * |
20 | * If you're reading in a text file, then this filter is practically | 20 | * If you're reading in a text file, then this filter is practically |
diff --git a/src/paramproc.cpp b/src/paramproc.cpp deleted file mode 100644 index f4fd36e..0000000 --- a/src/paramproc.cpp +++ /dev/null | |||
@@ -1,523 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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/paramproc.h" | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | #define ptrtype( iitype, iiname ) \ | ||
14 | Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ | ||
15 | type( vt ##iiname ) { val.iiname = iiname; } | ||
16 | |||
17 | Bu::ParamProc::ParamPtr::ParamPtr() | ||
18 | { | ||
19 | val.str = NULL; | ||
20 | type = vtunset; | ||
21 | } | ||
22 | |||
23 | ptrtype( Bu::FString, str ); | ||
24 | ptrtype( uint64_t, uint64 ); | ||
25 | ptrtype( uint32_t, uint32 ); | ||
26 | ptrtype( uint16_t, uint16 ); | ||
27 | ptrtype( uint8_t, uint8 ); | ||
28 | ptrtype( int64_t, int64 ); | ||
29 | ptrtype( int32_t, int32 ); | ||
30 | ptrtype( int16_t, int16 ); | ||
31 | ptrtype( int8_t, int8 ); | ||
32 | ptrtype( float, float32 ); | ||
33 | ptrtype( double, float64 ); | ||
34 | ptrtype( long double, float96 ); | ||
35 | ptrtype( bool, bln ); | ||
36 | |||
37 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) | ||
38 | { | ||
39 | val = ptr.val; | ||
40 | type = ptr.type; | ||
41 | |||
42 | return *this; | ||
43 | } | ||
44 | |||
45 | bool Bu::ParamProc::ParamPtr::isSet() | ||
46 | { | ||
47 | return type != vtunset; | ||
48 | } | ||
49 | |||
50 | Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) | ||
51 | { | ||
52 | if( !isSet() ) return *this; | ||
53 | switch( type ) | ||
54 | { | ||
55 | case vtstr: | ||
56 | (*val.str) = str; | ||
57 | break; | ||
58 | |||
59 | case vtuint64: | ||
60 | (*val.uint64) = strtoull( str, NULL, 10 ); | ||
61 | break; | ||
62 | |||
63 | case vtuint32: | ||
64 | (*val.uint32) = strtoul( str, NULL, 10 ); | ||
65 | break; | ||
66 | |||
67 | case vtuint16: | ||
68 | (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); | ||
69 | break; | ||
70 | |||
71 | case vtuint8: | ||
72 | (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); | ||
73 | break; | ||
74 | |||
75 | case vtint64: | ||
76 | (*val.int64) = strtoll( str, NULL, 10 ); | ||
77 | break; | ||
78 | |||
79 | case vtint32: | ||
80 | (*val.int32) = strtol( str, NULL, 10 ); | ||
81 | break; | ||
82 | |||
83 | case vtint16: | ||
84 | (*val.int16) = (int16_t)strtol( str, NULL, 10 ); | ||
85 | break; | ||
86 | |||
87 | case vtint8: | ||
88 | (*val.int8) = (int8_t)strtol( str, NULL, 10 ); | ||
89 | break; | ||
90 | |||
91 | case vtfloat32: | ||
92 | (*val.float32) = strtof( str, NULL ); | ||
93 | break; | ||
94 | |||
95 | case vtfloat64: | ||
96 | (*val.float64) = strtod( str, NULL ); | ||
97 | break; | ||
98 | |||
99 | case vtfloat96: | ||
100 | (*val.float96) = strtold( str, NULL ); | ||
101 | break; | ||
102 | |||
103 | case vtbln: | ||
104 | if( strcasecmp("yes", str ) == 0 || | ||
105 | strcasecmp("true", str ) == 0 ) | ||
106 | { | ||
107 | (*val.bln) = true; | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | (*val.bln) = false; | ||
112 | } | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | return *this; | ||
117 | } | ||
118 | |||
119 | Bu::ParamProc::ParamProc() | ||
120 | { | ||
121 | } | ||
122 | |||
123 | Bu::ParamProc::~ParamProc() | ||
124 | { | ||
125 | for( Bu::List<ArgSpec *>::iterator i = lArg.begin(); | ||
126 | i != lArg.end(); i++ ) | ||
127 | { | ||
128 | delete *i; | ||
129 | } | ||
130 | |||
131 | for( Bu::List<Banner *>::iterator i = lBan.begin(); | ||
132 | i != lBan.end(); i++ ) | ||
133 | { | ||
134 | delete *i; | ||
135 | } | ||
136 | |||
137 | } | ||
138 | /* | ||
139 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) | ||
140 | { | ||
141 | printf("Calling callback...\n"); | ||
142 | val = "Hello there, this is set in the ParamProc"; | ||
143 | (this->*proc)(); | ||
144 | }*/ | ||
145 | |||
146 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | ||
147 | ParamPtr val, const char *lpDesc, const char *lpExtra, | ||
148 | const char *lpValue ) | ||
149 | { | ||
150 | ArgSpec *as = new ArgSpec; | ||
151 | if( lpWord ) | ||
152 | as->sWord = lpWord; | ||
153 | |||
154 | as->cChar = cChar; | ||
155 | as->proc = proc; | ||
156 | as->val = val; | ||
157 | if( lpDesc ) | ||
158 | as->sDesc = lpDesc; | ||
159 | if( lpExtra ) | ||
160 | as->sExtra = lpExtra; | ||
161 | if( lpValue ) | ||
162 | as->sValue = lpValue; | ||
163 | |||
164 | lArg.append( as ); | ||
165 | |||
166 | if( !lBan.isEmpty() ) | ||
167 | { | ||
168 | if( lBan.last()->pBefore == NULL ) | ||
169 | lBan.last()->pBefore = as; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, | ||
174 | const char *lpDesc, const char *lpExtra, | ||
175 | const char *lpValue ) | ||
176 | { | ||
177 | addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
178 | } | ||
179 | |||
180 | void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, | ||
181 | const char *lpDesc, const char *lpExtra, | ||
182 | const char *lpValue ) | ||
183 | { | ||
184 | addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | ||
185 | } | ||
186 | |||
187 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, | ||
188 | const char *lpDesc, const char *lpExtra, | ||
189 | const char *lpValue ) | ||
190 | { | ||
191 | addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); | ||
192 | } | ||
193 | |||
194 | void Bu::ParamProc::addParam( const char *lpWord, Proc proc, | ||
195 | const char *lpDesc, const char *lpExtra, | ||
196 | const char *lpValue ) | ||
197 | { | ||
198 | addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
199 | } | ||
200 | |||
201 | void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, | ||
202 | const char *lpDesc, const char *lpExtra, | ||
203 | const char *lpValue ) | ||
204 | { | ||
205 | addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); | ||
206 | } | ||
207 | |||
208 | void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, | ||
209 | const char *lpDesc, const char *lpExtra, | ||
210 | const char *lpValue ) | ||
211 | { | ||
212 | addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); | ||
213 | } | ||
214 | |||
215 | void Bu::ParamProc::addParam( char cChar, Proc proc, | ||
216 | const char *lpDesc, const char *lpExtra, | ||
217 | const char *lpValue ) | ||
218 | { | ||
219 | addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); | ||
220 | } | ||
221 | |||
222 | void Bu::ParamProc::addParam( char cChar, ParamPtr val, | ||
223 | const char *lpDesc, const char *lpExtra, | ||
224 | const char *lpValue ) | ||
225 | { | ||
226 | addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); | ||
227 | } | ||
228 | |||
229 | void Bu::ParamProc::process( int argc, char *argv[] ) | ||
230 | { | ||
231 | for( int arg = 1; arg < argc; arg++ ) | ||
232 | { | ||
233 | //printf(":::%d:::%s\n", arg, argv[arg] ); | ||
234 | if( argv[arg][0] == '-' ) | ||
235 | { | ||
236 | if( argv[arg][1] == '-' ) | ||
237 | { | ||
238 | ArgSpec *s = checkWord( argv[arg]+2 ); | ||
239 | if( s ) | ||
240 | { | ||
241 | if( argv[arg][s->sWord.getSize()+2] == '=' ) | ||
242 | { | ||
243 | if( s->val.isSet() ) | ||
244 | { | ||
245 | if( s->sValue == "" ) | ||
246 | { | ||
247 | s->val = argv[arg]+s->sWord.getSize()+3; | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | s->val = s->sValue.getStr(); | ||
252 | } | ||
253 | } | ||
254 | if( s->proc ) | ||
255 | { | ||
256 | char **tmp = new char*[argc-arg]; | ||
257 | tmp[0] = argv[arg]+s->sWord.getSize()+3; | ||
258 | for( int k = 1; k < argc-arg; k++ ) | ||
259 | tmp[k] = argv[arg+k]; | ||
260 | int ret = (this->*s->proc)( argc-arg, tmp ); | ||
261 | if( ret > 0 ) | ||
262 | { | ||
263 | arg += ret-1; | ||
264 | } | ||
265 | delete tmp; | ||
266 | } | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | int add = 0; | ||
271 | if( s->val.isSet() ) | ||
272 | { | ||
273 | if( s->sValue == "" ) | ||
274 | { | ||
275 | if( arg+1 >= argc ) | ||
276 | { | ||
277 | return; | ||
278 | } | ||
279 | s->val = argv[arg+1]; | ||
280 | add++; | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | s->val = s->sValue.getStr(); | ||
285 | } | ||
286 | } | ||
287 | if( s->proc ) | ||
288 | { | ||
289 | int ret = (this->*s->proc)( | ||
290 | argc-arg-1, argv+arg+1 ); | ||
291 | |||
292 | if( ret > add ) | ||
293 | add = 0; | ||
294 | else | ||
295 | add -= ret; | ||
296 | arg += ret; | ||
297 | } | ||
298 | arg += add; | ||
299 | } | ||
300 | continue; | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | unknownParam( argc-arg, argv+arg ); | ||
305 | } | ||
306 | } | ||
307 | else | ||
308 | { | ||
309 | for( int chr = 1; argv[arg][chr]; chr++ ) | ||
310 | { | ||
311 | ArgSpec *s = checkLetr( argv[arg][chr] ); | ||
312 | if( s ) | ||
313 | { | ||
314 | if( argv[arg][chr+1] != '\0' ) | ||
315 | { | ||
316 | bool bUsed = false; | ||
317 | if( s->val.isSet() ) | ||
318 | { | ||
319 | if( s->sValue == "" ) | ||
320 | { | ||
321 | s->val = argv[arg]+chr+1; | ||
322 | bUsed = true; | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | s->val = s->sValue.getStr(); | ||
327 | } | ||
328 | } | ||
329 | if( s->proc ) | ||
330 | { | ||
331 | char **tmp = new char*[argc-arg]; | ||
332 | tmp[0] = argv[arg]+chr+1; | ||
333 | for( int k = 1; k < argc-arg; k++ ) | ||
334 | tmp[k] = argv[arg+k]; | ||
335 | int ret = (this->*s->proc)( argc-arg, tmp ); | ||
336 | if( ret > 0 ) | ||
337 | { | ||
338 | arg += ret - 1; | ||
339 | delete tmp; | ||
340 | break; | ||
341 | } | ||
342 | delete tmp; | ||
343 | } | ||
344 | if( bUsed ) | ||
345 | { | ||
346 | break; | ||
347 | } | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | bool bUsed = false; | ||
352 | if( s->val.isSet() ) | ||
353 | { | ||
354 | if( s->sValue == "" ) | ||
355 | { | ||
356 | s->val = argv[arg+1]; | ||
357 | bUsed = true; | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | s->val = s->sValue.getStr(); | ||
362 | } | ||
363 | } | ||
364 | if( s->proc ) | ||
365 | { | ||
366 | int ret = (this->*s->proc)( | ||
367 | argc-arg-1, argv+arg+1 | ||
368 | ); | ||
369 | if( ret > 0 ) | ||
370 | { | ||
371 | arg += ret; | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | if( bUsed ) | ||
376 | { | ||
377 | arg++; | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | unknownParam( argc-arg, argv+arg ); | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | cmdParam( argc-arg, argv+arg ); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | |||
396 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) | ||
397 | { | ||
398 | //printf("Checking \"%s\"...\n", arg ); | ||
399 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
400 | for( ; i != lArg.end(); i++ ) | ||
401 | { | ||
402 | if( (*i)->sWord == "" ) | ||
403 | continue; | ||
404 | |||
405 | if( !strcmp( (*i)->sWord.getStr(), arg ) ) | ||
406 | return *i; | ||
407 | |||
408 | if( (*i)->val.isSet() ) | ||
409 | { | ||
410 | if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && | ||
411 | arg[(*i)->sWord.getSize()] == '=' ) | ||
412 | { | ||
413 | return *i; | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | |||
418 | return NULL; | ||
419 | } | ||
420 | |||
421 | Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) | ||
422 | { | ||
423 | //printf("Checking \'%c\'...\n", arg ); | ||
424 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
425 | for( ; i != lArg.end(); i++ ) | ||
426 | { | ||
427 | if( (*i)->cChar == '\0' ) | ||
428 | continue; | ||
429 | |||
430 | if( (*i)->cChar == arg ) | ||
431 | { | ||
432 | return *i; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | return NULL; | ||
437 | } | ||
438 | |||
439 | int Bu::ParamProc::cmdParam( int /*argc*/, char *argv[] ) | ||
440 | { | ||
441 | printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | int Bu::ParamProc::unknownParam( int /*argc*/, char *argv[] ) | ||
446 | { | ||
447 | printf("Unknown parameter \"%s\" found!\n", argv[0] ); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | int Bu::ParamProc::help( int /*argc*/, char * /*argv*/ [] ) | ||
452 | { | ||
453 | Bu::List<Banner *>::const_iterator b = lBan.begin(); | ||
454 | Bu::List<ArgSpec *>::const_iterator i = lArg.begin(); | ||
455 | int len=0; | ||
456 | for( ; i != lArg.end(); i++ ) | ||
457 | { | ||
458 | if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) | ||
459 | len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); | ||
460 | } | ||
461 | char fmt[10]; | ||
462 | sprintf( fmt, "%%-%ds ", len ); | ||
463 | |||
464 | for( i = lArg.begin(); i != lArg.end(); i++ ) | ||
465 | { | ||
466 | if( b != lBan.end() ) | ||
467 | { | ||
468 | if( (*b)->pBefore == (*i) ) | ||
469 | { | ||
470 | printf( (*b)->sBanner.getStr() ); | ||
471 | b++; | ||
472 | } | ||
473 | } | ||
474 | printf(" "); | ||
475 | if( (*i)->cChar ) | ||
476 | { | ||
477 | if( (*i)->sWord.getStr() ) | ||
478 | { | ||
479 | printf("-%c, ", (*i)->cChar ); | ||
480 | } | ||
481 | else | ||
482 | { | ||
483 | printf("-%c ", (*i)->cChar ); | ||
484 | } | ||
485 | } | ||
486 | else | ||
487 | { | ||
488 | printf(" "); | ||
489 | } | ||
490 | if( (*i)->sWord.getStr() ) | ||
491 | { | ||
492 | printf("--"); | ||
493 | Bu::FString sTmp = (*i)->sWord.getStr(); | ||
494 | if( (*i)->sExtra.getStr() ) | ||
495 | sTmp += (*i)->sExtra.getStr(); | ||
496 | printf( fmt, sTmp.getStr() ); | ||
497 | } | ||
498 | else | ||
499 | { | ||
500 | printf(" "); | ||
501 | printf(fmt, "" ); | ||
502 | } | ||
503 | printf("%s\n", (*i)->sDesc.getStr() ); | ||
504 | } | ||
505 | if( b != lBan.end() ) | ||
506 | { | ||
507 | if( (*b)->pBefore == NULL ) | ||
508 | { | ||
509 | printf( (*b)->sBanner.getStr() ); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | exit( 0 ); | ||
514 | } | ||
515 | |||
516 | void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) | ||
517 | { | ||
518 | Banner *pBan = new Banner; | ||
519 | pBan->sBanner = sHelpBanner; | ||
520 | pBan->pBefore = NULL; | ||
521 | lBan.append( pBan ); | ||
522 | } | ||
523 | |||
diff --git a/src/paramproc.h b/src/paramproc.h deleted file mode 100644 index ddc1876..0000000 --- a/src/paramproc.h +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 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_PARAM_PROC_H | ||
9 | #define BU_PARAM_PROC_H | ||
10 | |||
11 | #include <stdint.h> | ||
12 | #include "bu/list.h" | ||
13 | #include "bu/fstring.h" | ||
14 | |||
15 | namespace Bu | ||
16 | { | ||
17 | class ParamProc | ||
18 | { | ||
19 | public: | ||
20 | class ParamPtr | ||
21 | { | ||
22 | public: | ||
23 | ParamPtr(); | ||
24 | ParamPtr( Bu::FString *str ); | ||
25 | ParamPtr( uint64_t *uint64 ); | ||
26 | ParamPtr( uint32_t *uint32 ); | ||
27 | ParamPtr( uint16_t *uint16 ); | ||
28 | ParamPtr( uint8_t *uint8 ); | ||
29 | ParamPtr( int64_t *int64 ); | ||
30 | ParamPtr( int32_t *int32 ); | ||
31 | ParamPtr( int16_t *int16 ); | ||
32 | ParamPtr( int8_t *int8 ); | ||
33 | ParamPtr( float *float32 ); | ||
34 | ParamPtr( double *float64 ); | ||
35 | ParamPtr( long double *float96 ); | ||
36 | ParamPtr( bool *bln ); | ||
37 | |||
38 | enum | ||
39 | { | ||
40 | vtunset, | ||
41 | vtstr, | ||
42 | vtuint64, | ||
43 | vtuint32, | ||
44 | vtuint16, | ||
45 | vtuint8, | ||
46 | vtint64, | ||
47 | vtint32, | ||
48 | vtint16, | ||
49 | vtint8, | ||
50 | vtfloat32, | ||
51 | vtfloat64, | ||
52 | vtfloat96, | ||
53 | vtbln, | ||
54 | }; | ||
55 | ParamPtr &operator=( ParamPtr &ptr ); | ||
56 | ParamPtr &operator=( const char *str ); | ||
57 | |||
58 | bool isSet(); | ||
59 | |||
60 | private: | ||
61 | int type; | ||
62 | union | ||
63 | { | ||
64 | Bu::FString *str; | ||
65 | uint64_t *uint64; | ||
66 | uint32_t *uint32; | ||
67 | uint16_t *uint16; | ||
68 | uint8_t *uint8; | ||
69 | int64_t *int64; | ||
70 | int32_t *int32; | ||
71 | int16_t *int16; | ||
72 | int8_t *int8; | ||
73 | float *float32; | ||
74 | double *float64; | ||
75 | long double *float96; | ||
76 | bool *bln; | ||
77 | } val; | ||
78 | }; | ||
79 | |||
80 | typedef int (ParamProc::*Proc)( int, char *[] ); | ||
81 | |||
82 | typedef struct ArgSpec | ||
83 | { | ||
84 | uint8_t nFlags; | ||
85 | Bu::FString sWord; | ||
86 | char cChar; | ||
87 | Proc proc; | ||
88 | ParamProc::ParamPtr val; | ||
89 | Bu::FString sExtra; | ||
90 | Bu::FString sDesc; | ||
91 | Bu::FString sValue; | ||
92 | } ArgSpec; | ||
93 | |||
94 | public: | ||
95 | DEPRECATED | ||
96 | ParamProc(); | ||
97 | virtual ~ParamProc(); | ||
98 | |||
99 | void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, | ||
100 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
101 | const char *lpValue=NULL | ||
102 | ); | ||
103 | void addParam( const char *lpWord, char cChar, Proc proc, | ||
104 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
105 | const char *lpValue=NULL | ||
106 | ); | ||
107 | void addParam( const char *lpWord, char cChar, ParamPtr val, | ||
108 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
109 | const char *lpValue=NULL | ||
110 | ); | ||
111 | |||
112 | void addParam( const char *lpWord, Proc proc, ParamPtr val, | ||
113 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
114 | const char *lpValue=NULL | ||
115 | ); | ||
116 | void addParam( const char *lpWord, Proc proc, | ||
117 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
118 | const char *lpValue=NULL | ||
119 | ); | ||
120 | void addParam( const char *lpWord, ParamPtr val, | ||
121 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
122 | const char *lpValue=NULL | ||
123 | ); | ||
124 | |||
125 | void addParam( char cChar, Proc proc, ParamPtr val, | ||
126 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
127 | const char *lpValue=NULL | ||
128 | ); | ||
129 | void addParam( char cChar, Proc proc, | ||
130 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
131 | const char *lpValue=NULL | ||
132 | ); | ||
133 | void addParam( char cChar, ParamPtr val, | ||
134 | const char *lpDesc=NULL, const char *lpExtra=NULL, | ||
135 | const char *lpValue=NULL | ||
136 | ); | ||
137 | |||
138 | void process( int argc, char *argv[] ); | ||
139 | void addHelpBanner( const char *sHelpBanner ); | ||
140 | |||
141 | private: | ||
142 | ArgSpec *checkWord( const char *arg ); | ||
143 | ArgSpec *checkLetr( const char arg ); | ||
144 | |||
145 | public: | ||
146 | virtual int cmdParam( int argc, char *argv[] ); | ||
147 | virtual int unknownParam( int argc, char *argv[] ); | ||
148 | virtual int help( int argc, char *argv[] ); | ||
149 | |||
150 | private: | ||
151 | typedef struct Banner | ||
152 | { | ||
153 | Bu::FString sBanner; | ||
154 | ArgSpec *pBefore; | ||
155 | } Banner; | ||
156 | Bu::List<Banner *> lBan; | ||
157 | Bu::List<ArgSpec *> lArg; | ||
158 | }; | ||
159 | } | ||
160 | |||
161 | #define mkproc( cls ) static_cast<int (Bu::ParamProc::*)( int, char *[])>(&cls) | ||
162 | |||
163 | #endif | ||
diff --git a/src/parser.cpp b/src/parser.cpp index e4e8ae5..4ad4ff9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp | |||
@@ -22,16 +22,25 @@ void Bu::Parser::popLexer() | |||
22 | delete sLexer.peekPop(); | 22 | delete sLexer.peekPop(); |
23 | } | 23 | } |
24 | 24 | ||
25 | Lexer::Token *Bu::Parser::popToken() | ||
26 | { | ||
27 | return sToken.peekPop(); | ||
28 | } | ||
29 | |||
30 | void Bu::Parser::pushToken( Lexer::Token *pTok ) | ||
31 | { | ||
32 | sToken.push( pTok ); | ||
33 | } | ||
34 | |||
25 | void Bu::Parser::parse() | 35 | void Bu::Parser::parse() |
26 | { | 36 | { |
27 | int iCurNt = iRootNonTerminal; | 37 | int iCurNt = iRootNonTerminal; |
28 | Lexer::Token *ptCur = sLexer.peek()->nextToken(); | 38 | Lexer::Token *ptCur = sLexer.peek()->nextToken(); |
29 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 39 | sio << "Token(a): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
30 | selectProduction( iCurNt, ptCur ); | 40 | selectProduction( iCurNt, ptCur ); |
31 | 41 | ||
32 | while( !sState.isEmpty() ) | 42 | while( !sState.isEmpty() ) |
33 | { | 43 | { |
34 | sio << "Currently: " << *sState.peek() << sio.nl; | ||
35 | switch( (*sState.peek()).eType ) | 44 | switch( (*sState.peek()).eType ) |
36 | { | 45 | { |
37 | case State::typeTerminal: | 46 | case State::typeTerminal: |
@@ -42,7 +51,7 @@ void Bu::Parser::parse() | |||
42 | advanceState(); | 51 | advanceState(); |
43 | delete ptCur; | 52 | delete ptCur; |
44 | ptCur = sLexer.peek()->nextToken(); | 53 | ptCur = sLexer.peek()->nextToken(); |
45 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 54 | sio << "Token(b): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
46 | } | 55 | } |
47 | else | 56 | else |
48 | { | 57 | { |
@@ -59,7 +68,7 @@ void Bu::Parser::parse() | |||
59 | sToken.push( ptCur ); | 68 | sToken.push( ptCur ); |
60 | 69 | ||
61 | ptCur = sLexer.peek()->nextToken(); | 70 | ptCur = sLexer.peek()->nextToken(); |
62 | sio << "Token: " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; | 71 | sio << "Token(c): " << sLexer.peek()->tokenToString( *ptCur ) << sio.nl; |
63 | } | 72 | } |
64 | else | 73 | else |
65 | { | 74 | { |
@@ -72,7 +81,7 @@ void Bu::Parser::parse() | |||
72 | << (*sState.peek()).iIndex << sio.nl; | 81 | << (*sState.peek()).iIndex << sio.nl; |
73 | { | 82 | { |
74 | int iNt = (*sState.peek()).iIndex; | 83 | int iNt = (*sState.peek()).iIndex; |
75 | advanceState(); | 84 | sio << "Current state: " << *sState.peek() << sio.nl; |
76 | if( !selectProduction( iNt, ptCur ) ) | 85 | if( !selectProduction( iNt, ptCur ) ) |
77 | { | 86 | { |
78 | throw Bu::ExceptionBase("Error parsing code."); | 87 | throw Bu::ExceptionBase("Error parsing code."); |
@@ -132,7 +141,11 @@ bool Bu::Parser::selectProduction( int iNt, Lexer::Token *ptCur ) | |||
132 | } | 141 | } |
133 | } | 142 | } |
134 | if( nt.bCanSkip ) | 143 | if( nt.bCanSkip ) |
144 | { | ||
145 | sio << "Nothing matches, skipping non-terminal." << sio.nl; | ||
146 | advanceState(); | ||
135 | return true; | 147 | return true; |
148 | } | ||
136 | sio << "-->(Found nothing)" << sio.nl; | 149 | sio << "-->(Found nothing)" << sio.nl; |
137 | return false; | 150 | return false; |
138 | } | 151 | } |
@@ -148,6 +161,7 @@ void Bu::Parser::advanceState() | |||
148 | sio.decIndent(); | 161 | sio.decIndent(); |
149 | sState.pop(); | 162 | sState.pop(); |
150 | sio << "State advanced, End of production." << sio.nl; | 163 | sio << "State advanced, End of production." << sio.nl; |
164 | advanceState(); | ||
151 | return; | 165 | return; |
152 | } | 166 | } |
153 | sio << "State advanced, now: " << *(sState.peek()) << sio.nl; | 167 | sio << "State advanced, now: " << *(sState.peek()) << sio.nl; |
@@ -191,6 +205,11 @@ int Bu::Parser::getNonTerminalId( const Bu::FString &sName ) | |||
191 | return hNonTerminalName.get( sName ); | 205 | return hNonTerminalName.get( sName ); |
192 | } | 206 | } |
193 | 207 | ||
208 | bool Bu::Parser::hasNonTerminal( const Bu::FString &sName ) | ||
209 | { | ||
210 | return hNonTerminalName.has( sName ); | ||
211 | } | ||
212 | |||
194 | int Bu::Parser::addReduction( const Bu::FString &sName, const Reduction &r ) | 213 | int Bu::Parser::addReduction( const Bu::FString &sName, const Reduction &r ) |
195 | { | 214 | { |
196 | int iId = aReduction.getSize(); | 215 | int iId = aReduction.getSize(); |
@@ -217,6 +236,11 @@ int Bu::Parser::getReductionId( const Bu::FString &sName ) | |||
217 | return hReductionName.get( sName ); | 236 | return hReductionName.get( sName ); |
218 | } | 237 | } |
219 | 238 | ||
239 | bool Bu::Parser::hasReduction( const Bu::FString &sName ) | ||
240 | { | ||
241 | return hReductionName.has( sName ); | ||
242 | } | ||
243 | |||
220 | // | 244 | // |
221 | // Bu::Parser::State | 245 | // Bu::Parser::State |
222 | // | 246 | // |
diff --git a/src/parser.h b/src/parser.h index 5b5d4a8..a925188 100644 --- a/src/parser.h +++ b/src/parser.h | |||
@@ -34,6 +34,9 @@ namespace Bu | |||
34 | */ | 34 | */ |
35 | void popLexer(); | 35 | void popLexer(); |
36 | 36 | ||
37 | Lexer::Token *popToken(); | ||
38 | void pushToken( Lexer::Token *pTok ); | ||
39 | |||
37 | /** | 40 | /** |
38 | * Execute a parse. | 41 | * Execute a parse. |
39 | */ | 42 | */ |
@@ -88,11 +91,13 @@ namespace Bu | |||
88 | int addNonTerminal( const Bu::FString &sName ); | 91 | int addNonTerminal( const Bu::FString &sName ); |
89 | void setNonTerminal( const Bu::FString &sName, NonTerminal &nt ); | 92 | void setNonTerminal( const Bu::FString &sName, NonTerminal &nt ); |
90 | int getNonTerminalId( const Bu::FString &sName ); | 93 | int getNonTerminalId( const Bu::FString &sName ); |
94 | bool hasNonTerminal( const Bu::FString &sName ); | ||
91 | 95 | ||
92 | int addReduction( const Bu::FString &sName, const Reduction &r ); | 96 | int addReduction( const Bu::FString &sName, const Reduction &r ); |
93 | int addReduction( const Bu::FString &sName ); | 97 | int addReduction( const Bu::FString &sName ); |
94 | void setReduction( const Bu::FString &sName, const Reduction &r ); | 98 | void setReduction( const Bu::FString &sName, const Reduction &r ); |
95 | int getReductionId( const Bu::FString &sName ); | 99 | int getReductionId( const Bu::FString &sName ); |
100 | bool hasReduction( const Bu::FString &sName ); | ||
96 | 101 | ||
97 | private: | 102 | private: |
98 | bool selectProduction( int iNt, Lexer::Token *ptCur ); | 103 | bool selectProduction( int iNt, Lexer::Token *ptCur ); |
diff --git a/src/ringbuffer.h b/src/ringbuffer.h index e984d18..f4fd58c 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h | |||
@@ -10,97 +10,218 @@ | |||
10 | 10 | ||
11 | #include <memory> | 11 | #include <memory> |
12 | #include "bu/exceptionbase.h" | 12 | #include "bu/exceptionbase.h" |
13 | #include "bu/queue.h" | ||
14 | #include "bu/sharedcore.h" | ||
13 | 15 | ||
14 | namespace Bu | 16 | namespace Bu |
15 | { | 17 | { |
16 | /** | 18 | template<typename value, typename valuealloc> class RingBuffer; |
17 | *@ingroup Containers | 19 | |
18 | */ | 20 | /** @cond DEVEL */ |
19 | template<typename value, typename valuealloc=std::allocator<value> > | 21 | template<typename value, typename valuealloc> |
20 | class RingBuffer | 22 | class RingBufferCore |
21 | { | 23 | { |
22 | public: | 24 | friend class RingBuffer<value, valuealloc>; |
23 | RingBuffer( int nCapacity ) : | 25 | friend class SharedCore<RingBuffer<value, valuealloc>, |
24 | nCapacity( nCapacity ), | 26 | RingBufferCore<value, valuealloc> >; |
25 | nStart( -1 ), | 27 | private: |
26 | nEnd( -2 ) | 28 | RingBufferCore() : |
29 | iCapacity( 0 ), | ||
30 | iStart( -1 ), | ||
31 | iEnd( -2 ), | ||
32 | aData( NULL ) | ||
27 | { | 33 | { |
28 | aData = va.allocate( nCapacity ); | ||
29 | } | 34 | } |
30 | 35 | ||
31 | virtual ~RingBuffer() | 36 | virtual ~RingBufferCore() |
32 | { | 37 | { |
33 | for( int j = nStart; j < nEnd; j=(j+1%nCapacity) ) | 38 | clear(); |
34 | { | ||
35 | va.destroy( &aData[j] ); | ||
36 | } | ||
37 | va.deallocate( aData, nCapacity ); | ||
38 | } | 39 | } |
39 | 40 | ||
40 | int getCapacity() | 41 | void init( int iNewCapacity ) |
41 | { | 42 | { |
42 | return nCapacity; | 43 | if( iCapacity > 0 ) |
43 | } | 44 | return; |
44 | 45 | ||
45 | bool isFilled() | 46 | iCapacity = iNewCapacity; |
46 | { | 47 | iStart = -1; |
47 | return (nStart == nEnd); | 48 | iEnd = -2; |
49 | aData = va.allocate( iCapacity ); | ||
48 | } | 50 | } |
49 | 51 | ||
50 | bool isEmpty() | 52 | void clear() |
51 | { | 53 | { |
52 | return (nStart == -1); | 54 | for( int j = iStart; j < iEnd; j=(j+1%iCapacity) ) |
55 | { | ||
56 | va.destroy( &aData[j] ); | ||
57 | } | ||
58 | va.deallocate( aData, iCapacity ); | ||
59 | aData = NULL; | ||
60 | iCapacity = 0; | ||
53 | } | 61 | } |
54 | 62 | ||
55 | void enqueue( const value &v ) | 63 | void enqueue( const value &v ) |
56 | { | 64 | { |
57 | if( nStart == -1 ) | 65 | if( iStart == -1 ) |
58 | { | 66 | { |
59 | nStart = 0; | 67 | iStart = 0; |
60 | nEnd = 1; | 68 | iEnd = 1; |
61 | va.construct( &aData[0], v ); | 69 | va.construct( &aData[0], v ); |
62 | } | 70 | } |
63 | else if( nStart == nEnd ) | 71 | else if( iStart == iEnd ) |
64 | { | 72 | { |
65 | throw ExceptionBase("Hey, it's full!"); | 73 | throw ExceptionBase("Hey, it's full!"); |
66 | } | 74 | } |
67 | else | 75 | else |
68 | { | 76 | { |
69 | va.construct( &aData[nEnd], v ); | 77 | va.construct( &aData[iEnd], v ); |
70 | nEnd = (nEnd+1)%nCapacity; | 78 | iEnd = (iEnd+1)%iCapacity; |
71 | } | 79 | } |
72 | } | 80 | } |
73 | 81 | ||
74 | value dequeue() | 82 | value dequeue() |
75 | { | 83 | { |
76 | if( nStart == -1 ) | 84 | if( iStart == -1 ) |
77 | { | 85 | { |
78 | throw ExceptionBase("No data"); | 86 | throw ExceptionBase("No data"); |
79 | } | 87 | } |
80 | else | 88 | else |
81 | { | 89 | { |
82 | value &v = aData[nStart]; | 90 | value &v = aData[iStart]; |
83 | va.destroy( &aData[nStart] ); | 91 | va.destroy( &aData[iStart] ); |
84 | nStart = (nStart+1)%nCapacity; | 92 | iStart = (iStart+1)%iCapacity; |
85 | if( nStart == nEnd ) | 93 | if( iStart == iEnd ) |
86 | { | 94 | { |
87 | nStart = -1; | 95 | iStart = -1; |
88 | nEnd = -2; | 96 | iEnd = -2; |
89 | } | 97 | } |
90 | return v; | 98 | return v; |
91 | } | 99 | } |
92 | } | 100 | } |
93 | 101 | ||
94 | value &operator[]( int nIndex ) | 102 | value &get( int iIndex ) |
95 | { | 103 | { |
96 | return aData[(nIndex+nStart)%nCapacity]; | 104 | return aData[(iIndex+iStart)%iCapacity]; |
97 | } | 105 | } |
98 | 106 | ||
99 | private: | 107 | int getSize() |
100 | int nCapacity; | 108 | { |
109 | if( iStart < 0 ) | ||
110 | return 0; | ||
111 | if( iEnd == iStart ) | ||
112 | return iCapacity; | ||
113 | if( iEnd < iStart ) | ||
114 | return iEnd-iStart; | ||
115 | return iCapacity-(iEnd-iStart); | ||
116 | } | ||
117 | |||
118 | int iCapacity; | ||
119 | int iStart, iEnd; | ||
101 | value *aData; | 120 | value *aData; |
102 | valuealloc va; | 121 | valuealloc va; |
103 | int nStart, nEnd; | 122 | }; |
123 | /** @endcond */ | ||
124 | |||
125 | /** | ||
126 | *@ingroup Containers | ||
127 | */ | ||
128 | template<typename value, typename valuealloc=std::allocator<value> > | ||
129 | class RingBuffer : public Queue<value>, public SharedCore< | ||
130 | RingBuffer<value, valuealloc>, | ||
131 | RingBufferCore<value, valuealloc> | ||
132 | > | ||
133 | { | ||
134 | private: | ||
135 | typedef RingBuffer<value, valuealloc> MyType; | ||
136 | typedef RingBufferCore<value, valuealloc> Core; | ||
137 | |||
138 | protected: | ||
139 | using SharedCore<MyType, Core>::core; | ||
140 | using SharedCore<MyType, Core>::_hardCopy; | ||
141 | using SharedCore<MyType, Core>::_allocateCore; | ||
142 | |||
143 | public: | ||
144 | RingBuffer( int iCapacity ) | ||
145 | { | ||
146 | core->init( iCapacity ); | ||
147 | } | ||
148 | |||
149 | RingBuffer( const RingBuffer &rSrc ) : | ||
150 | SharedCore<MyType, Core>( rSrc ) | ||
151 | { | ||
152 | } | ||
153 | |||
154 | virtual ~RingBuffer() | ||
155 | { | ||
156 | } | ||
157 | |||
158 | int getCapacity() const | ||
159 | { | ||
160 | return core->iCapacity; | ||
161 | } | ||
162 | |||
163 | bool isFilled() const | ||
164 | { | ||
165 | return (core->iStart == core->iEnd); | ||
166 | } | ||
167 | |||
168 | bool isEmpty() const | ||
169 | { | ||
170 | return (core->iStart == -1); | ||
171 | } | ||
172 | |||
173 | virtual void enqueue( const value &v ) | ||
174 | { | ||
175 | _hardCopy(); | ||
176 | |||
177 | core->enqueue( v ); | ||
178 | } | ||
179 | |||
180 | virtual value dequeue() | ||
181 | { | ||
182 | _hardCopy(); | ||
183 | |||
184 | return core->dequeue(); | ||
185 | } | ||
186 | |||
187 | virtual int getSize() const | ||
188 | { | ||
189 | return core->getSize(); | ||
190 | } | ||
191 | |||
192 | virtual value &peek() | ||
193 | { | ||
194 | _hardCopy(); | ||
195 | |||
196 | return core->get( 0 ); | ||
197 | } | ||
198 | |||
199 | virtual const value &peek() const | ||
200 | { | ||
201 | return core->get( 0 ); | ||
202 | } | ||
203 | |||
204 | value &operator[]( int iIndex ) | ||
205 | { | ||
206 | _hardCopy(); | ||
207 | |||
208 | return core->get( iIndex ); | ||
209 | } | ||
210 | |||
211 | protected: | ||
212 | virtual Core *_copyCore( Core *src ) | ||
213 | { | ||
214 | Core *pRet = _allocateCore(); | ||
215 | |||
216 | pRet->init( src->iCapacity ); | ||
217 | int iSize = src->getSize(); | ||
218 | for( int j = 0; j < iSize; j++ ) | ||
219 | { | ||
220 | pRet->enqueue( src->get( j ) ); | ||
221 | } | ||
222 | |||
223 | return pRet; | ||
224 | } | ||
104 | }; | 225 | }; |
105 | } | 226 | } |
106 | 227 | ||
diff --git a/src/server.cpp b/src/server.cpp index 51c056a..e701a69 100644 --- a/src/server.cpp +++ b/src/server.cpp | |||
@@ -8,9 +8,9 @@ | |||
8 | #include "bu/server.h" | 8 | #include "bu/server.h" |
9 | #include <errno.h> | 9 | #include <errno.h> |
10 | #include <unistd.h> | 10 | #include <unistd.h> |
11 | #include "bu/serversocket.h" | 11 | #include "bu/tcpserversocket.h" |
12 | #include "bu/client.h" | 12 | #include "bu/client.h" |
13 | #include "bu/socket.h" | 13 | #include "bu/tcpsocket.h" |
14 | #include "bu/config.h" | 14 | #include "bu/config.h" |
15 | 15 | ||
16 | Bu::Server::Server() : | 16 | Bu::Server::Server() : |
@@ -28,7 +28,7 @@ Bu::Server::~Server() | |||
28 | 28 | ||
29 | void Bu::Server::addPort( int nPort, int nPoolSize ) | 29 | void Bu::Server::addPort( int nPort, int nPoolSize ) |
30 | { | 30 | { |
31 | ServerSocket *s = new ServerSocket( nPort, nPoolSize ); | 31 | TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); |
32 | int nSocket = s->getSocket(); | 32 | int nSocket = s->getSocket(); |
33 | FD_SET( nSocket, &fdActive ); | 33 | FD_SET( nSocket, &fdActive ); |
34 | hServers.insert( nSocket, s ); | 34 | hServers.insert( nSocket, s ); |
@@ -36,7 +36,7 @@ void Bu::Server::addPort( int nPort, int nPoolSize ) | |||
36 | 36 | ||
37 | void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) | 37 | void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) |
38 | { | 38 | { |
39 | ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); | 39 | TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); |
40 | int nSocket = s->getSocket(); | 40 | int nSocket = s->getSocket(); |
41 | FD_SET( nSocket, &fdActive ); | 41 | FD_SET( nSocket, &fdActive ); |
42 | hServers.insert( nSocket, s ); | 42 | hServers.insert( nSocket, s ); |
@@ -75,7 +75,7 @@ void Bu::Server::scan() | |||
75 | { | 75 | { |
76 | if( hServers.has( j ) ) | 76 | if( hServers.has( j ) ) |
77 | { | 77 | { |
78 | ServerSocket *pSrv = hServers.get( j ); | 78 | TcpServerSocket *pSrv = hServers.get( j ); |
79 | addClient( pSrv->accept(), pSrv->getPort() ); | 79 | addClient( pSrv->accept(), pSrv->getPort() ); |
80 | } | 80 | } |
81 | else | 81 | else |
@@ -97,7 +97,7 @@ void Bu::Server::scan() | |||
97 | { | 97 | { |
98 | pClient->processOutput(); | 98 | pClient->processOutput(); |
99 | } | 99 | } |
100 | catch( Bu::SocketException &e ) | 100 | catch( Bu::TcpSocketException &e ) |
101 | { | 101 | { |
102 | closeClient( j ); | 102 | closeClient( j ); |
103 | } | 103 | } |
@@ -136,7 +136,7 @@ void Bu::Server::addClient( int nSocket, int nPort ) | |||
136 | FD_SET( nSocket, &fdActive ); | 136 | FD_SET( nSocket, &fdActive ); |
137 | 137 | ||
138 | Client *c = new Client( | 138 | Client *c = new Client( |
139 | new Bu::Socket( nSocket ), | 139 | new Bu::TcpSocket( nSocket ), |
140 | new SrvClientLinkFactory() | 140 | new SrvClientLinkFactory() |
141 | ); | 141 | ); |
142 | hClients.insert( nSocket, c ); | 142 | hClients.insert( nSocket, c ); |
diff --git a/src/server.h b/src/server.h index 74ee99a..d6726fd 100644 --- a/src/server.h +++ b/src/server.h | |||
@@ -25,8 +25,8 @@ | |||
25 | 25 | ||
26 | namespace Bu | 26 | namespace Bu |
27 | { | 27 | { |
28 | class ServerSocket; | 28 | class TcpServerSocket; |
29 | class Socket; | 29 | class TcpSocket; |
30 | class Client; | 30 | class Client; |
31 | 31 | ||
32 | /** | 32 | /** |
@@ -97,7 +97,7 @@ namespace Bu | |||
97 | int nTimeoutSec; | 97 | int nTimeoutSec; |
98 | int nTimeoutUSec; | 98 | int nTimeoutUSec; |
99 | fd_set fdActive; | 99 | fd_set fdActive; |
100 | typedef Hash<int,ServerSocket *> SrvHash; | 100 | typedef Hash<int,TcpServerSocket *> SrvHash; |
101 | SrvHash hServers; | 101 | SrvHash hServers; |
102 | typedef Hash<int,Client *> ClientHash; | 102 | typedef Hash<int,Client *> ClientHash; |
103 | ClientHash hClients; | 103 | ClientHash hClients; |
@@ -24,17 +24,10 @@ namespace Bu | |||
24 | { | 24 | { |
25 | subExceptionDecl( SetException ) | 25 | subExceptionDecl( SetException ) |
26 | 26 | ||
27 | template<typename T> | ||
28 | uint32_t __calcHashCode( const T &k ); | ||
29 | |||
30 | template<typename T> | ||
31 | bool __cmpHashKeys( const T &a, const T &b ); | ||
32 | |||
33 | template<typename key, typename sizecalc = struct __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename challoc = std::allocator<uint32_t> > | ||
34 | class Set; | ||
35 | |||
36 | /** | 27 | /** |
37 | * Libbu Template Set | 28 | *@todo Set should be rewritten, possibly using a b-tree as ordered storage |
29 | * in the backend. It should use either a b-tree or array for storage and | ||
30 | * allow set intersections, unions, etc. | ||
38 | *@param key (typename) The datatype of the hashtable keys | 31 | *@param key (typename) The datatype of the hashtable keys |
39 | *@param sizecalc (typename) Functor to compute new table size on rehash | 32 | *@param sizecalc (typename) Functor to compute new table size on rehash |
40 | *@param keyalloc (typename) Memory allocator for hashtable keys | 33 | *@param keyalloc (typename) Memory allocator for hashtable keys |
@@ -45,754 +38,7 @@ namespace Bu | |||
45 | class Set | 38 | class Set |
46 | { | 39 | { |
47 | public: | 40 | public: |
48 | Set() : | ||
49 | nCapacity( 11 ), | ||
50 | nFilled( 0 ), | ||
51 | nDeleted( 0 ), | ||
52 | bFilled( NULL ), | ||
53 | bDeleted( NULL ), | ||
54 | aKeys( NULL ), | ||
55 | aHashCodes( NULL ) | ||
56 | { | ||
57 | nKeysSize = bitsToBytes( nCapacity ); | ||
58 | bFilled = ca.allocate( nKeysSize ); | ||
59 | bDeleted = ca.allocate( nKeysSize ); | ||
60 | clearBits(); | ||
61 | |||
62 | aHashCodes = ca.allocate( nCapacity ); | ||
63 | aKeys = ka.allocate( nCapacity ); | ||
64 | } | ||
65 | |||
66 | Set( const Set &src ) : | ||
67 | nCapacity( src.nCapacity ), | ||
68 | nFilled( 0 ), | ||
69 | nDeleted( 0 ), | ||
70 | bFilled( NULL ), | ||
71 | bDeleted( NULL ), | ||
72 | aKeys( NULL ), | ||
73 | aHashCodes( NULL ) | ||
74 | { | ||
75 | nKeysSize = bitsToBytes( nCapacity ); | ||
76 | bFilled = ca.allocate( nKeysSize ); | ||
77 | bDeleted = ca.allocate( nKeysSize ); | ||
78 | clearBits(); | ||
79 | |||
80 | aHashCodes = ca.allocate( nCapacity ); | ||
81 | aKeys = ka.allocate( nCapacity ); | ||
82 | |||
83 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
84 | { | ||
85 | if( src.isFilled( j ) ) | ||
86 | { | ||
87 | insert( src.aKeys[j] ); | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Set assignment operator. Clears this hashtable and | ||
94 | * copies RH into it. | ||
95 | */ | ||
96 | Set &operator=( const Set &src ) | ||
97 | { | ||
98 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
99 | { | ||
100 | if( isFilled( j ) ) | ||
101 | if( !isDeleted( j ) ) | ||
102 | { | ||
103 | ka.destroy( &aKeys[j] ); | ||
104 | } | ||
105 | } | ||
106 | ka.deallocate( aKeys, nCapacity ); | ||
107 | ca.deallocate( bFilled, nKeysSize ); | ||
108 | ca.deallocate( bDeleted, nKeysSize ); | ||
109 | ca.deallocate( aHashCodes, nCapacity ); | ||
110 | |||
111 | nFilled = 0; | ||
112 | nDeleted = 0; | ||
113 | nCapacity = src.nCapacity; | ||
114 | nKeysSize = bitsToBytes( nCapacity ); | ||
115 | bFilled = ca.allocate( nKeysSize ); | ||
116 | bDeleted = ca.allocate( nKeysSize ); | ||
117 | clearBits(); | ||
118 | |||
119 | aHashCodes = ca.allocate( nCapacity ); | ||
120 | aKeys = ka.allocate( nCapacity ); | ||
121 | |||
122 | for( uint32_t j = 0; j < src.nCapacity; j++ ) | ||
123 | { | ||
124 | if( src.isFilled( j ) ) | ||
125 | { | ||
126 | insert( src.aKeys[j] ); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return *this; | ||
131 | } | ||
132 | |||
133 | virtual ~Set() | ||
134 | { | ||
135 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
136 | { | ||
137 | if( isFilled( j ) ) | ||
138 | if( !isDeleted( j ) ) | ||
139 | { | ||
140 | ka.destroy( &aKeys[j] ); | ||
141 | } | ||
142 | } | ||
143 | ka.deallocate( aKeys, nCapacity ); | ||
144 | ca.deallocate( bFilled, nKeysSize ); | ||
145 | ca.deallocate( bDeleted, nKeysSize ); | ||
146 | ca.deallocate( aHashCodes, nCapacity ); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * Get the current hash table capacity. (Changes at re-hash) | ||
151 | *@returns (uint32_t) The current capacity. | ||
152 | */ | ||
153 | uint32_t getCapacity() | ||
154 | { | ||
155 | return nCapacity; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * Get the number of hash locations spoken for. (Including | ||
160 | * not-yet-cleaned-up deleted items.) | ||
161 | *@returns (uint32_t) The current fill state. | ||
162 | */ | ||
163 | uint32_t getFill() | ||
164 | { | ||
165 | return nFilled; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * Get the number of items stored in the hash table. | ||
170 | *@returns (uint32_t) The number of items stored in the hash table. | ||
171 | */ | ||
172 | uint32_t getSize() | ||
173 | { | ||
174 | return nFilled-nDeleted; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * Get the number of items which have been deleted, but not yet | ||
179 | * cleaned up. | ||
180 | *@returns (uint32_t) The number of deleted items. | ||
181 | */ | ||
182 | uint32_t getDeleted() | ||
183 | { | ||
184 | return nDeleted; | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Insert key (k) into the set | ||
189 | *@param k (key_type) Key to list the value under. | ||
190 | */ | ||
191 | virtual void insert( key k ) | ||
192 | { | ||
193 | uint32_t hash = __calcHashCode( k ); | ||
194 | bool bFill; | ||
195 | uint32_t nPos = probe( hash, k, bFill ); | ||
196 | |||
197 | if( bFill ) | ||
198 | { | ||
199 | onUpdate(); | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | fill( nPos, k, hash ); | ||
204 | onInsert(); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * Remove a value from the hash table. | ||
210 | *@param k (key_type) The data under this key will be erased. | ||
211 | */ | ||
212 | virtual void erase( key k ) | ||
213 | { | ||
214 | uint32_t hash = __calcHashCode( k ); | ||
215 | bool bFill; | ||
216 | uint32_t nPos = probe( hash, k, bFill ); | ||
217 | |||
218 | if( bFill ) | ||
219 | { | ||
220 | _erase( nPos ); | ||
221 | onDelete(); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | struct iterator; | ||
226 | |||
227 | /** | ||
228 | * Remove a value from the hash pointed to from an iterator. | ||
229 | *@param i (iterator &) The data to be erased. | ||
230 | */ | ||
231 | virtual void erase( struct iterator &i ) | ||
232 | { | ||
233 | if( this != &i.hsh ) | ||
234 | throw SetException("This iterator didn't come from this Hash."); | ||
235 | if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) | ||
236 | { | ||
237 | _erase( i.nPos ); | ||
238 | onDelete(); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Remove all data from the hash table. | ||
244 | */ | ||
245 | virtual void clear() | ||
246 | { | ||
247 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
248 | { | ||
249 | if( isFilled( j ) ) | ||
250 | if( !isDeleted( j ) ) | ||
251 | { | ||
252 | _erase( j ); | ||
253 | onDelete(); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | clearBits(); | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * Does the hash table contain an item under key (k). | ||
262 | *@param k (key_type) The key to check. | ||
263 | *@returns (bool) Whether there was an item in the hash under key (k). | ||
264 | */ | ||
265 | virtual bool has( key k ) | ||
266 | { | ||
267 | bool bFill; | ||
268 | probe( __calcHashCode( k ), k, bFill, false ); | ||
269 | |||
270 | return bFill; | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * Iteration structure for iterating through the hash. | ||
275 | */ | ||
276 | typedef struct iterator | ||
277 | { | ||
278 | friend class Set<key, sizecalc, keyalloc, challoc>; | ||
279 | private: | ||
280 | iterator( Set<key, sizecalc, keyalloc, challoc> &hsh ) : | ||
281 | hsh( hsh ), | ||
282 | nPos( 0 ), | ||
283 | bFinished( false ) | ||
284 | { | ||
285 | nPos = hsh.getFirstPos( bFinished ); | ||
286 | } | ||
287 | |||
288 | iterator( Set<key, sizecalc, keyalloc, challoc> &hsh, bool bDone ) : | ||
289 | hsh( hsh ), | ||
290 | nPos( 0 ), | ||
291 | bFinished( bDone ) | ||
292 | { | ||
293 | } | ||
294 | |||
295 | Set<key, sizecalc, keyalloc, challoc> &hsh; | ||
296 | uint32_t nPos; | ||
297 | bool bFinished; | ||
298 | |||
299 | public: | ||
300 | /** | ||
301 | * Iterator incrementation operator. Move the iterator forward. | ||
302 | */ | ||
303 | iterator operator++( int ) | ||
304 | { | ||
305 | if( bFinished == false ) | ||
306 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
307 | |||
308 | return *this; | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * Iterator incrementation operator. Move the iterator forward. | ||
313 | */ | ||
314 | iterator operator++() | ||
315 | { | ||
316 | if( bFinished == false ) | ||
317 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
318 | |||
319 | return *this; | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * Iterator equality comparison operator. Iterators the same? | ||
324 | */ | ||
325 | bool operator==( const iterator &oth ) const | ||
326 | { | ||
327 | if( bFinished != oth.bFinished ) | ||
328 | return false; | ||
329 | if( bFinished == true ) | ||
330 | { | ||
331 | return true; | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | if( oth.nPos == nPos ) | ||
336 | return true; | ||
337 | return false; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * Iterator not equality comparison operator. Not the same? | ||
343 | */ | ||
344 | bool operator!=( const iterator &oth ) const | ||
345 | { | ||
346 | return !(*this == oth ); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * Iterator assignment operator. | ||
351 | */ | ||
352 | iterator operator=( const iterator &oth ) | ||
353 | { | ||
354 | if( &hsh != &oth.hsh ) | ||
355 | throw SetException( | ||
356 | "Cannot mix iterators from different set objects."); | ||
357 | nPos = oth.nPos; | ||
358 | bFinished = oth.bFinished; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * Iterator dereference operator... err.. get the value | ||
363 | *@returns (value_type &) The value behind this iterator. | ||
364 | */ | ||
365 | key &operator *() | ||
366 | { | ||
367 | return hsh.getKeyAtPos( nPos ); | ||
368 | } | ||
369 | |||
370 | const key &operator *() const | ||
371 | { | ||
372 | return hsh.getKeyAtPos( nPos ); | ||
373 | } | ||
374 | |||
375 | bool isValid() const | ||
376 | { | ||
377 | return !bFinished; | ||
378 | } | ||
379 | |||
380 | operator bool() const | ||
381 | { | ||
382 | return !bFinished; | ||
383 | } | ||
384 | } iterator; | ||
385 | |||
386 | /** | ||
387 | * Iteration structure for iterating through the set (const). | ||
388 | */ | ||
389 | typedef struct const_iterator | ||
390 | { | ||
391 | friend class Set<key, sizecalc, keyalloc, challoc>; | ||
392 | private: | ||
393 | const_iterator( const Set<key, sizecalc, keyalloc, challoc> &hsh ) : | ||
394 | hsh( hsh ), | ||
395 | nPos( 0 ), | ||
396 | bFinished( false ) | ||
397 | { | ||
398 | nPos = hsh.getFirstPos( bFinished ); | ||
399 | } | ||
400 | |||
401 | const_iterator( const Set<key, sizecalc, keyalloc, challoc> &hsh, bool bDone ) : | ||
402 | hsh( hsh ), | ||
403 | nPos( 0 ), | ||
404 | bFinished( bDone ) | ||
405 | { | ||
406 | } | ||
407 | |||
408 | const Set<key, sizecalc, keyalloc, challoc> &hsh; | ||
409 | uint32_t nPos; | ||
410 | bool bFinished; | ||
411 | |||
412 | public: | ||
413 | /** | ||
414 | * Iterator incrementation operator. Move the iterator forward. | ||
415 | */ | ||
416 | const_iterator operator++( int ) | ||
417 | { | ||
418 | if( bFinished == false ) | ||
419 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
420 | |||
421 | return *this; | ||
422 | } | ||
423 | |||
424 | /** | ||
425 | * Iterator incrementation operator. Move the iterator forward. | ||
426 | */ | ||
427 | const_iterator operator++() | ||
428 | { | ||
429 | if( bFinished == false ) | ||
430 | nPos = hsh.getNextPos( nPos, bFinished ); | ||
431 | |||
432 | return *this; | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * Iterator equality comparison operator. Iterators the same? | ||
437 | */ | ||
438 | bool operator==( const const_iterator &oth ) const | ||
439 | { | ||
440 | if( bFinished != oth.bFinished ) | ||
441 | return false; | ||
442 | if( bFinished == true ) | ||
443 | { | ||
444 | return true; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | if( oth.nPos == nPos ) | ||
449 | return true; | ||
450 | return false; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * Iterator not equality comparison operator. Not the same? | ||
456 | */ | ||
457 | bool operator!=( const const_iterator &oth ) const | ||
458 | { | ||
459 | return !(*this == oth ); | ||
460 | } | ||
461 | |||
462 | /** | ||
463 | * Iterator assignment operator. | ||
464 | */ | ||
465 | const_iterator operator=( const const_iterator &oth ) | ||
466 | { | ||
467 | if( &hsh != &oth.hsh ) | ||
468 | throw SetException( | ||
469 | "Cannot mix iterators from different hash objects."); | ||
470 | nPos = oth.nPos; | ||
471 | bFinished = oth.bFinished; | ||
472 | } | ||
473 | |||
474 | /** | ||
475 | * Iterator dereference operator... err.. get the value | ||
476 | *@returns (value_type &) The value behind this iterator. | ||
477 | */ | ||
478 | const key &operator *() const | ||
479 | { | ||
480 | return hsh.getKeyAtPos( nPos ); | ||
481 | } | ||
482 | |||
483 | bool isValid() const | ||
484 | { | ||
485 | return !bFinished; | ||
486 | } | ||
487 | |||
488 | operator bool() const | ||
489 | { | ||
490 | return !bFinished; | ||
491 | } | ||
492 | } const_iterator; | ||
493 | |||
494 | /** | ||
495 | * Get an iterator pointing to the first item in the hash table. | ||
496 | *@returns (iterator) An iterator pointing to the first item in the | ||
497 | * hash table. | ||
498 | */ | ||
499 | iterator begin() | ||
500 | { | ||
501 | return iterator( *this ); | ||
502 | } | ||
503 | |||
504 | const_iterator begin() const | ||
505 | { | ||
506 | return const_iterator( *this ); | ||
507 | } | ||
508 | |||
509 | /** | ||
510 | * Get an iterator pointing to a point just past the last item in the | ||
511 | * hash table. | ||
512 | *@returns (iterator) An iterator pointing to a point just past the | ||
513 | * last item in the hash table. | ||
514 | */ | ||
515 | iterator end() | ||
516 | { | ||
517 | return iterator( *this, true ); | ||
518 | } | ||
519 | |||
520 | const_iterator end() const | ||
521 | { | ||
522 | return const_iterator( *this, true ); | ||
523 | } | ||
524 | |||
525 | /** | ||
526 | * Get a list of all the keys in the hash table. | ||
527 | *@returns (std::list<key_type>) The list of keys in the hash table. | ||
528 | */ | ||
529 | Bu::List<key> getKeys() const | ||
530 | { | ||
531 | Bu::List<key> lKeys; | ||
532 | |||
533 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
534 | { | ||
535 | if( isFilled( j ) ) | ||
536 | { | ||
537 | if( !isDeleted( j ) ) | ||
538 | { | ||
539 | lKeys.append( aKeys[j] ); | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | |||
544 | return lKeys; | ||
545 | } | ||
546 | |||
547 | protected: | ||
548 | virtual void onInsert() {} | ||
549 | virtual void onUpdate() {} | ||
550 | virtual void onDelete() {} | ||
551 | virtual void onReHash() {} | ||
552 | |||
553 | virtual void clearBits() | ||
554 | { | ||
555 | for( uint32_t j = 0; j < nKeysSize; j++ ) | ||
556 | { | ||
557 | bFilled[j] = bDeleted[j] = 0; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | virtual void fill( uint32_t loc, key &k, uint32_t hash ) | ||
562 | { | ||
563 | bFilled[loc/32] |= (1<<(loc%32)); | ||
564 | ka.construct( &aKeys[loc], k ); | ||
565 | aHashCodes[loc] = hash; | ||
566 | nFilled++; | ||
567 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
568 | // nFilled, nDeleted, nCapacity ); | ||
569 | } | ||
570 | |||
571 | virtual void _erase( uint32_t loc ) | ||
572 | { | ||
573 | bDeleted[loc/32] |= (1<<(loc%32)); | ||
574 | ka.destroy( &aKeys[loc] ); | ||
575 | nDeleted++; | ||
576 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
577 | // nFilled, nDeleted, nCapacity ); | ||
578 | } | ||
579 | |||
580 | virtual key &getKeyAtPos( uint32_t nPos ) | ||
581 | { | ||
582 | return aKeys[nPos]; | ||
583 | } | ||
584 | |||
585 | virtual const key &getKeyAtPos( uint32_t nPos ) const | ||
586 | { | ||
587 | return aKeys[nPos]; | ||
588 | } | ||
589 | |||
590 | virtual uint32_t getFirstPos( bool &bFinished ) const | ||
591 | { | ||
592 | for( uint32_t j = 0; j < nCapacity; j++ ) | ||
593 | { | ||
594 | if( isFilled( j ) ) | ||
595 | if( !isDeleted( j ) ) | ||
596 | return j; | ||
597 | } | ||
598 | |||
599 | bFinished = true; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const | ||
604 | { | ||
605 | for( uint32_t j = nPos+1; j < nCapacity; j++ ) | ||
606 | { | ||
607 | if( isFilled( j ) ) | ||
608 | if( !isDeleted( j ) ) | ||
609 | return j; | ||
610 | } | ||
611 | |||
612 | bFinished = true; | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) | ||
617 | { | ||
618 | uint32_t nCur = hash%nCapacity; | ||
619 | |||
620 | // First we scan to see if the key is already there, abort if we | ||
621 | // run out of probing room, or we find a non-filled entry | ||
622 | int8_t j; | ||
623 | for( j = 0; | ||
624 | isFilled( nCur ) && j < 32; | ||
625 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
626 | ) | ||
627 | { | ||
628 | // Is this the same hash code we were looking for? | ||
629 | if( hash == aHashCodes[nCur] ) | ||
630 | { | ||
631 | // Skip over deleted entries. Deleted entries are also filled, | ||
632 | // so we only have to do this check here. | ||
633 | if( isDeleted( nCur ) ) | ||
634 | continue; | ||
635 | |||
636 | // Is it really the same key? (for safety) | ||
637 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
638 | { | ||
639 | bFill = true; | ||
640 | return nCur; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | |||
645 | // This is our insurance, if the table is full, then go ahead and | ||
646 | // rehash, then try again. | ||
647 | if( (isFilled( nCur ) || j == 32) && rehash == true ) | ||
648 | { | ||
649 | reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); | ||
650 | |||
651 | // This is potentially dangerous, and could cause an infinite loop. | ||
652 | // Be careful writing probe, eh? | ||
653 | return probe( hash, k, bFill ); | ||
654 | } | ||
655 | |||
656 | bFill = false; | ||
657 | return nCur; | ||
658 | } | ||
659 | |||
660 | uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) const | ||
661 | { | ||
662 | uint32_t nCur = hash%nCapacity; | ||
663 | |||
664 | // First we scan to see if the key is already there, abort if we | ||
665 | // run out of probing room, or we find a non-filled entry | ||
666 | for( int8_t j = 0; | ||
667 | isFilled( nCur ) && j < 32; | ||
668 | nCur = (nCur + (1<<j))%nCapacity, j++ | ||
669 | ) | ||
670 | { | ||
671 | // Is this the same hash code we were looking for? | ||
672 | if( hash == aHashCodes[nCur] ) | ||
673 | { | ||
674 | // Skip over deleted entries. Deleted entries are also filled, | ||
675 | // so we only have to do this check here. | ||
676 | if( isDeleted( nCur ) ) | ||
677 | continue; | ||
678 | |||
679 | // Is it really the same key? (for safety) | ||
680 | if( __cmpHashKeys( aKeys[nCur], k ) == true ) | ||
681 | { | ||
682 | bFill = true; | ||
683 | return nCur; | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | |||
688 | bFill = false; | ||
689 | return nCur; | ||
690 | } | ||
691 | |||
692 | void reHash( uint32_t nNewSize ) | ||
693 | { | ||
694 | //printf("---REHASH---"); | ||
695 | //printf("Filled: %d, Deleted: %d, Capacity: %d\n", | ||
696 | // nFilled, nDeleted, nCapacity ); | ||
697 | |||
698 | // Save all the old data | ||
699 | uint32_t nOldCapacity = nCapacity; | ||
700 | uint32_t *bOldFilled = bFilled; | ||
701 | uint32_t *aOldHashCodes = aHashCodes; | ||
702 | uint32_t nOldKeysSize = nKeysSize; | ||
703 | uint32_t *bOldDeleted = bDeleted; | ||
704 | key *aOldKeys = aKeys; | ||
705 | |||
706 | // Calculate new sizes | ||
707 | nCapacity = nNewSize; | ||
708 | nKeysSize = bitsToBytes( nCapacity ); | ||
709 | |||
710 | // Allocate new memory + prep | ||
711 | bFilled = ca.allocate( nKeysSize ); | ||
712 | bDeleted = ca.allocate( nKeysSize ); | ||
713 | clearBits(); | ||
714 | |||
715 | aHashCodes = ca.allocate( nCapacity ); | ||
716 | aKeys = ka.allocate( nCapacity ); | ||
717 | |||
718 | nDeleted = nFilled = 0; | ||
719 | |||
720 | // Re-insert all of the old data (except deleted items) | ||
721 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
722 | { | ||
723 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && | ||
724 | (bOldDeleted[j/32]&(1<<(j%32)))==0 ) | ||
725 | { | ||
726 | insert( aOldKeys[j] ); | ||
727 | } | ||
728 | } | ||
729 | |||
730 | // Delete all of the old data | ||
731 | for( uint32_t j = 0; j < nOldCapacity; j++ ) | ||
732 | { | ||
733 | if( (bOldFilled[j/32]&(1<<(j%32)))!=0 ) | ||
734 | { | ||
735 | ka.destroy( &aOldKeys[j] ); | ||
736 | } | ||
737 | } | ||
738 | ka.deallocate( aOldKeys, nOldCapacity ); | ||
739 | ca.deallocate( bOldFilled, nOldKeysSize ); | ||
740 | ca.deallocate( bOldDeleted, nOldKeysSize ); | ||
741 | ca.deallocate( aOldHashCodes, nOldCapacity ); | ||
742 | } | ||
743 | |||
744 | virtual bool isFilled( uint32_t loc ) const | ||
745 | { | ||
746 | return (bFilled[loc/32]&(1<<(loc%32)))!=0; | ||
747 | } | ||
748 | |||
749 | virtual bool isDeleted( uint32_t loc ) const | ||
750 | { | ||
751 | return (bDeleted[loc/32]&(1<<(loc%32)))!=0; | ||
752 | } | ||
753 | |||
754 | protected: | ||
755 | uint32_t nCapacity; | ||
756 | uint32_t nFilled; | ||
757 | uint32_t nDeleted; | ||
758 | uint32_t *bFilled; | ||
759 | uint32_t *bDeleted; | ||
760 | uint32_t nKeysSize; | ||
761 | key *aKeys; | ||
762 | uint32_t *aHashCodes; | ||
763 | keyalloc ka; | ||
764 | challoc ca; | ||
765 | sizecalc szCalc; | ||
766 | }; | 41 | }; |
767 | |||
768 | template<typename key, typename b, typename c, typename d> | ||
769 | Archive &operator<<( Archive &ar, const Set<key, b, c, d> &h ) | ||
770 | { | ||
771 | ar << h.getSize(); | ||
772 | for( typename Set<key, b, c, d>::const_iterator i = h.begin(); i != h.end(); i++ ) | ||
773 | { | ||
774 | ar << (*i); | ||
775 | } | ||
776 | |||
777 | return ar; | ||
778 | } | ||
779 | |||
780 | template<typename key, typename b, typename c, typename d> | ||
781 | Archive &operator>>( Archive &ar, Set<key, b, c, d> &h ) | ||
782 | { | ||
783 | h.clear(); | ||
784 | long nSize; | ||
785 | ar >> nSize; | ||
786 | |||
787 | for( long j = 0; j < nSize; j++ ) | ||
788 | { | ||
789 | key v; | ||
790 | ar >> v; | ||
791 | h.insert( v ); | ||
792 | } | ||
793 | |||
794 | return ar; | ||
795 | } | ||
796 | } | 42 | } |
797 | 43 | ||
798 | #endif | 44 | #endif |
diff --git a/src/sharedcore.h b/src/sharedcore.h index 5a44df9..1887ca2 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h | |||
@@ -15,10 +15,57 @@ | |||
15 | 15 | ||
16 | namespace Bu | 16 | namespace Bu |
17 | { | 17 | { |
18 | template<typename Core> | 18 | /** |
19 | * A mechanism for creating classes that perform lazy copies. The concept | ||
20 | * behind this is that instead of copying a large object when it is assigned | ||
21 | * or passed into a copy constructor we simply copy a pointer internally. | ||
22 | * The assumption is that many times when an object is passed by value we | ||
23 | * don't really want to keep the object around, we want the recipient to | ||
24 | * take ownership without allocating a new object. This allows that to | ||
25 | * happen. | ||
26 | * | ||
27 | * When used properly this makes object copying essentially free (O(1), | ||
28 | * that is) and performs the actual copy when a user tries to modify the | ||
29 | * object. | ||
30 | * | ||
31 | * For example, lets look at something like the getKeys function in | ||
32 | * Bu::Hash. When this function is called it creates a Bu::List of | ||
33 | * appropriate type, fills it with keys, and returns it. This is a good | ||
34 | * way for this function to behave, there may be additional issues if the | ||
35 | * List object were allocated with new and not on the stack. However, | ||
36 | * returning the List at the end of the function could potentially take | ||
37 | * a very long time depending on the size of the list and the type of the | ||
38 | * key. In this case the getKeys function doesn't want ownership of the | ||
39 | * List object, and when it returns it, it's local copy will be destroyed. | ||
40 | * | ||
41 | * However, List inherits from SharedCore, which means that when it is | ||
42 | * returned all we do is copy a pointer to the "core" of the list, which | ||
43 | * is a very fast operatorion. For a brief moment, before anyone can do | ||
44 | * anything else, there are two objects referencing the core of that single | ||
45 | * list. However, the getKeys() function will destroy it's local copy | ||
46 | * before the calling function can use it's new copy. That means that by | ||
47 | * the time the calling function can use it's new List of keys it is the | ||
48 | * only one with a reference to the core, and no copy will need to happen. | ||
49 | * | ||
50 | * Using SharedCore on your own classes is fairly straight forward. There | ||
51 | * are only a couple of steps. First, break the class into two classes. | ||
52 | * Move every variable from the original class (generally everything that's | ||
53 | * private) into the new class. Then make the original class inherit from | ||
54 | * SharedCore. The SharedCore template takes 2 parameters, first is the | ||
55 | * class it's inheriting from, second is the new core class. Now, in your | ||
56 | * original class you will have one class variable, a pointer named core. | ||
57 | * All of your original variables will be accessable through core. The next | ||
58 | * step is to access everything you used to through core, and to find | ||
59 | * every function that may change data in the core. At the top of every | ||
60 | * function that may change data you want to call _hardCopy(). | ||
61 | * | ||
62 | * That's more or less it. A more detailed guide will be written soon. | ||
63 | * @todo Write a guide for this. | ||
64 | */ | ||
65 | template<typename Shell, typename Core> | ||
19 | class SharedCore | 66 | class SharedCore |
20 | { | 67 | { |
21 | typedef class SharedCore<Core> _SharedType; | 68 | typedef class SharedCore<Shell, Core> _SharedType; |
22 | public: | 69 | public: |
23 | SharedCore() : | 70 | SharedCore() : |
24 | core( NULL ), | 71 | core( NULL ), |
@@ -54,6 +101,18 @@ namespace Bu | |||
54 | return *iRefCount; | 101 | return *iRefCount; |
55 | } | 102 | } |
56 | 103 | ||
104 | Shell clone() const | ||
105 | { | ||
106 | Shell s( dynamic_cast<const Shell &>(*this) ); | ||
107 | s._hardCopy(); | ||
108 | return s; | ||
109 | } | ||
110 | |||
111 | bool isCoreShared( const Shell &rOther ) const | ||
112 | { | ||
113 | return rOther.core == core; | ||
114 | } | ||
115 | |||
57 | protected: | 116 | protected: |
58 | Core *core; | 117 | Core *core; |
59 | void _hardCopy() | 118 | void _hardCopy() |
@@ -68,6 +127,20 @@ namespace Bu | |||
68 | iRefCount = new int( 1 ); | 127 | iRefCount = new int( 1 ); |
69 | } | 128 | } |
70 | 129 | ||
130 | /** | ||
131 | * Reset core acts like a hard copy, except instead of providing a | ||
132 | * standalone copy of the shared core, it provides a brand new core. | ||
133 | * | ||
134 | * Very useful in functions used to reset the state of an object. | ||
135 | */ | ||
136 | void _resetCore() | ||
137 | { | ||
138 | if( core ) | ||
139 | _deref(); | ||
140 | core = _allocateCore(); | ||
141 | iRefCount = new int( 1 ); | ||
142 | } | ||
143 | |||
71 | virtual Core *_allocateCore() | 144 | virtual Core *_allocateCore() |
72 | { | 145 | { |
73 | return new Core(); | 146 | return new Core(); |
diff --git a/src/serversocket.cpp b/src/tcpserversocket.cpp index 87d0035..7d7f6e4 100644 --- a/src/serversocket.cpp +++ b/src/tcpserversocket.cpp | |||
@@ -21,13 +21,13 @@ | |||
21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
22 | //#include <termios.h> | 22 | //#include <termios.h> |
23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
24 | #include "bu/serversocket.h" | 24 | #include "bu/tcpserversocket.h" |
25 | 25 | ||
26 | #include "bu/config.h" | 26 | #include "bu/config.h" |
27 | 27 | ||
28 | namespace Bu { subExceptionDef( ServerSocketException ) } | 28 | namespace Bu { subExceptionDef( TcpServerSocketException ) } |
29 | 29 | ||
30 | Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | 30 | Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) : |
31 | nPort( nPort ) | 31 | nPort( nPort ) |
32 | { | 32 | { |
33 | #ifdef WIN32 | 33 | #ifdef WIN32 |
@@ -48,7 +48,7 @@ Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : | |||
48 | startServer( name, nPoolSize ); | 48 | startServer( name, nPoolSize ); |
49 | } | 49 | } |
50 | 50 | ||
51 | Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | 51 | Bu::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) : |
52 | nPort( nPort ) | 52 | nPort( nPort ) |
53 | { | 53 | { |
54 | #ifdef WIN32 | 54 | #ifdef WIN32 |
@@ -72,7 +72,7 @@ Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : | |||
72 | startServer( name, nPoolSize ); | 72 | startServer( name, nPoolSize ); |
73 | } | 73 | } |
74 | 74 | ||
75 | Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : | 75 | Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) : |
76 | nServer( nServer ), | 76 | nServer( nServer ), |
77 | nPort( 0 ) | 77 | nPort( 0 ) |
78 | { | 78 | { |
@@ -95,7 +95,7 @@ Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) | 98 | Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc ) |
99 | { | 99 | { |
100 | #ifdef WIN32 | 100 | #ifdef WIN32 |
101 | Bu::Winsock2::getInstance(); | 101 | Bu::Winsock2::getInstance(); |
@@ -107,20 +107,20 @@ Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) | |||
107 | FD_SET( nServer, &fdActive ); | 107 | FD_SET( nServer, &fdActive ); |
108 | } | 108 | } |
109 | 109 | ||
110 | Bu::ServerSocket::~ServerSocket() | 110 | Bu::TcpServerSocket::~TcpServerSocket() |
111 | { | 111 | { |
112 | if( nServer > -1 ) | 112 | if( nServer > -1 ) |
113 | ::close( nServer ); | 113 | ::close( nServer ); |
114 | } | 114 | } |
115 | 115 | ||
116 | void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | 116 | void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) |
117 | { | 117 | { |
118 | /* Create the socket. */ | 118 | /* Create the socket. */ |
119 | nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); | 119 | nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); |
120 | 120 | ||
121 | if( nServer < 0 ) | 121 | if( nServer < 0 ) |
122 | { | 122 | { |
123 | throw Bu::ServerSocketException("Couldn't create a listen socket."); | 123 | throw Bu::TcpServerSocketException("Couldn't create a listen socket."); |
124 | } | 124 | } |
125 | 125 | ||
126 | int opt = 1; | 126 | int opt = 1; |
@@ -135,16 +135,16 @@ void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) | |||
135 | initServer( name, nPoolSize ); | 135 | initServer( name, nPoolSize ); |
136 | } | 136 | } |
137 | 137 | ||
138 | void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) | 138 | void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) |
139 | { | 139 | { |
140 | if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) | 140 | if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) |
141 | { | 141 | { |
142 | throw Bu::ServerSocketException("Couldn't bind to the listen socket."); | 142 | throw Bu::TcpServerSocketException("Couldn't bind to the listen socket."); |
143 | } | 143 | } |
144 | 144 | ||
145 | if( bu_listen( nServer, nPoolSize ) < 0 ) | 145 | if( bu_listen( nServer, nPoolSize ) < 0 ) |
146 | { | 146 | { |
147 | throw Bu::ServerSocketException( | 147 | throw Bu::TcpServerSocketException( |
148 | "Couldn't begin listening to the server socket." | 148 | "Couldn't begin listening to the server socket." |
149 | ); | 149 | ); |
150 | } | 150 | } |
@@ -154,12 +154,12 @@ void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) | |||
154 | FD_SET( nServer, &fdActive ); | 154 | FD_SET( nServer, &fdActive ); |
155 | } | 155 | } |
156 | 156 | ||
157 | int Bu::ServerSocket::getSocket() | 157 | int Bu::TcpServerSocket::getSocket() |
158 | { | 158 | { |
159 | return nServer; | 159 | return nServer; |
160 | } | 160 | } |
161 | 161 | ||
162 | int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | 162 | int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) |
163 | { | 163 | { |
164 | fd_set fdRead = fdActive; | 164 | fd_set fdRead = fdActive; |
165 | 165 | ||
@@ -171,7 +171,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
171 | if( TEMP_FAILURE_RETRY( | 171 | if( TEMP_FAILURE_RETRY( |
172 | bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) | 172 | bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) |
173 | { | 173 | { |
174 | throw Bu::ServerSocketException( | 174 | throw Bu::TcpServerSocketException( |
175 | "Error scanning for new connections: %s", strerror( errno ) | 175 | "Error scanning for new connections: %s", strerror( errno ) |
176 | ); | 176 | ); |
177 | } | 177 | } |
@@ -200,7 +200,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
200 | #endif /* WIN32 */ | 200 | #endif /* WIN32 */ |
201 | if( nClient < 0 ) | 201 | if( nClient < 0 ) |
202 | { | 202 | { |
203 | throw Bu::ServerSocketException( | 203 | throw Bu::TcpServerSocketException( |
204 | "Error accepting a new connection: %s", strerror( errno ) | 204 | "Error accepting a new connection: %s", strerror( errno ) |
205 | ); | 205 | ); |
206 | } | 206 | } |
@@ -219,7 +219,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
219 | flags |= O_NONBLOCK; | 219 | flags |= O_NONBLOCK; |
220 | if( fcntl( nClient, F_SETFL, flags ) < 0) | 220 | if( fcntl( nClient, F_SETFL, flags ) < 0) |
221 | { | 221 | { |
222 | throw Bu::ServerSocketException( | 222 | throw Bu::TcpServerSocketException( |
223 | "Error setting option on client socket: %s", | 223 | "Error setting option on client socket: %s", |
224 | strerror( errno ) | 224 | strerror( errno ) |
225 | ); | 225 | ); |
@@ -242,7 +242,7 @@ int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) | |||
242 | return -1; | 242 | return -1; |
243 | } | 243 | } |
244 | 244 | ||
245 | int Bu::ServerSocket::getPort() | 245 | int Bu::TcpServerSocket::getPort() |
246 | { | 246 | { |
247 | return nPort; | 247 | return nPort; |
248 | } | 248 | } |
diff --git a/src/serversocket.h b/src/tcpserversocket.h index ee357a4..b1d7e02 100644 --- a/src/serversocket.h +++ b/src/tcpserversocket.h | |||
@@ -5,8 +5,8 @@ | |||
5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #ifndef BU_SERVER_SOCKET_H | 8 | #ifndef BU_TCP_SERVER_SOCKET_H |
9 | #define BU_SERVER_SOCKET_H | 9 | #define BU_TCP_SERVER_SOCKET_H |
10 | 10 | ||
11 | #include <stdint.h> | 11 | #include <stdint.h> |
12 | #include "bu/fstring.h" | 12 | #include "bu/fstring.h" |
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | namespace Bu | 21 | namespace Bu |
22 | { | 22 | { |
23 | subExceptionDecl( ServerSocketException ); | 23 | subExceptionDecl( TcpServerSocketException ); |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * A single tcp/ip server socket. When created the server socket will bind | 26 | * A single tcp/ip server socket. When created the server socket will bind |
@@ -34,14 +34,14 @@ namespace Bu | |||
34 | * | 34 | * |
35 | *@ingroup Serving | 35 | *@ingroup Serving |
36 | */ | 36 | */ |
37 | class ServerSocket | 37 | class TcpServerSocket |
38 | { | 38 | { |
39 | public: | 39 | public: |
40 | ServerSocket( int nPort, int nPoolSize=40 ); | 40 | TcpServerSocket( int nPort, int nPoolSize=40 ); |
41 | ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); | 41 | TcpServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); |
42 | ServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); | 42 | TcpServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); |
43 | ServerSocket( const ServerSocket &rSrc ); | 43 | TcpServerSocket( const TcpServerSocket &rSrc ); |
44 | virtual ~ServerSocket(); | 44 | virtual ~TcpServerSocket(); |
45 | 45 | ||
46 | int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); | 46 | int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); |
47 | int getSocket(); | 47 | int getSocket(); |
diff --git a/src/socket.cpp b/src/tcpsocket.cpp index baf3be3..bbd9cf5 100644 --- a/src/socket.cpp +++ b/src/tcpsocket.cpp | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <sys/time.h> | 14 | #include <sys/time.h> |
15 | #include <errno.h> | 15 | #include <errno.h> |
16 | #include <fcntl.h> | 16 | #include <fcntl.h> |
17 | #include "bu/socket.h" | 17 | #include "bu/tcpsocket.h" |
18 | 18 | ||
19 | #include "bu/config.h" | 19 | #include "bu/config.h" |
20 | 20 | ||
@@ -29,10 +29,10 @@ | |||
29 | 29 | ||
30 | #define RBS (1024*2) | 30 | #define RBS (1024*2) |
31 | 31 | ||
32 | namespace Bu { subExceptionDef( SocketException ) } | 32 | namespace Bu { subExceptionDef( TcpSocketException ) } |
33 | 33 | ||
34 | Bu::Socket::Socket( int nSocket ) : | 34 | Bu::TcpSocket::TcpSocket( int nTcpSocket ) : |
35 | nSocket( nSocket ), | 35 | nTcpSocket( nTcpSocket ), |
36 | bActive( true ), | 36 | bActive( true ), |
37 | bBlocking( true ) | 37 | bBlocking( true ) |
38 | { | 38 | { |
@@ -42,8 +42,9 @@ Bu::Socket::Socket( int nSocket ) : | |||
42 | setAddress(); | 42 | setAddress(); |
43 | } | 43 | } |
44 | 44 | ||
45 | Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | 45 | Bu::TcpSocket::TcpSocket( const Bu::FString &sAddr, int nPort, int nTimeout, |
46 | nSocket( 0 ), | 46 | bool bBlocking ) : |
47 | nTcpSocket( 0 ), | ||
47 | bActive( false ), | 48 | bActive( false ), |
48 | bBlocking( true ) | 49 | bBlocking( true ) |
49 | { | 50 | { |
@@ -52,9 +53,9 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
52 | #endif | 53 | #endif |
53 | 54 | ||
54 | /* Create the socket. */ | 55 | /* Create the socket. */ |
55 | nSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); | 56 | nTcpSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); |
56 | 57 | ||
57 | if( nSocket < 0 ) | 58 | if( nTcpSocket < 0 ) |
58 | { | 59 | { |
59 | throw ExceptionBase("Couldn't create socket.\n"); | 60 | throw ExceptionBase("Couldn't create socket.\n"); |
60 | } | 61 | } |
@@ -78,12 +79,12 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
78 | sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) | 79 | sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) |
79 | { | 80 | { |
80 | close(); | 81 | close(); |
81 | throw Bu::SocketException("Couldn't resolve hostname %s (%s).\n", | 82 | throw Bu::TcpSocketException("Couldn't resolve hostname %s (%s).\n", |
82 | sAddr.getStr(), bu_gai_strerror(ret)); | 83 | sAddr.getStr(), bu_gai_strerror(ret)); |
83 | } | 84 | } |
84 | 85 | ||
85 | bu_connect( | 86 | bu_connect( |
86 | nSocket, | 87 | nTcpSocket, |
87 | pAddr->ai_addr, | 88 | pAddr->ai_addr, |
88 | pAddr->ai_addrlen | 89 | pAddr->ai_addrlen |
89 | ); | 90 | ); |
@@ -101,17 +102,17 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
101 | int retval; | 102 | int retval; |
102 | 103 | ||
103 | FD_ZERO(&rfds); | 104 | FD_ZERO(&rfds); |
104 | FD_SET(nSocket, &rfds); | 105 | FD_SET(nTcpSocket, &rfds); |
105 | FD_ZERO(&wfds); | 106 | FD_ZERO(&wfds); |
106 | FD_SET(nSocket, &wfds); | 107 | FD_SET(nTcpSocket, &wfds); |
107 | FD_ZERO(&efds); | 108 | FD_ZERO(&efds); |
108 | FD_SET(nSocket, &efds); | 109 | FD_SET(nTcpSocket, &efds); |
109 | 110 | ||
110 | struct timeval tv; | 111 | struct timeval tv; |
111 | tv.tv_sec = nTimeout; | 112 | tv.tv_sec = nTimeout; |
112 | tv.tv_usec = 0; | 113 | tv.tv_usec = 0; |
113 | 114 | ||
114 | retval = bu_select( nSocket+1, &rfds, &wfds, &efds, &tv ); | 115 | retval = bu_select( nTcpSocket+1, &rfds, &wfds, &efds, &tv ); |
115 | 116 | ||
116 | if( retval == 0 ) | 117 | if( retval == 0 ) |
117 | { | 118 | { |
@@ -120,51 +121,54 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : | |||
120 | } | 121 | } |
121 | read( NULL, 0 ); // See if we can get any errors out of the way early. | 122 | read( NULL, 0 ); // See if we can get any errors out of the way early. |
122 | } | 123 | } |
124 | |||
125 | if( bBlocking ) | ||
126 | setBlocking( bBlocking ); | ||
123 | } | 127 | } |
124 | 128 | ||
125 | Bu::Socket::~Socket() | 129 | Bu::TcpSocket::~TcpSocket() |
126 | { | 130 | { |
127 | close(); | 131 | close(); |
128 | } | 132 | } |
129 | 133 | ||
130 | void Bu::Socket::close() | 134 | void Bu::TcpSocket::close() |
131 | { | 135 | { |
132 | if( bActive ) | 136 | if( bActive ) |
133 | { | 137 | { |
134 | #ifndef WIN32 | 138 | #ifndef WIN32 |
135 | fsync( nSocket ); | 139 | fsync( nTcpSocket ); |
136 | #endif | 140 | #endif |
137 | #ifdef WIN32 | 141 | #ifdef WIN32 |
138 | #ifndef SHUT_RDWR | 142 | #ifndef SHUT_RDWR |
139 | #define SHUT_RDWR (SD_BOTH) | 143 | #define SHUT_RDWR (SD_BOTH) |
140 | #endif | 144 | #endif |
141 | #endif | 145 | #endif |
142 | bu_shutdown( nSocket, SHUT_RDWR ); | 146 | bu_shutdown( nTcpSocket, SHUT_RDWR ); |
143 | ::close( nSocket ); | 147 | ::close( nTcpSocket ); |
144 | } | 148 | } |
145 | bActive = false; | 149 | bActive = false; |
146 | } | 150 | } |
147 | 151 | ||
148 | size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | 152 | size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes ) |
149 | { | 153 | { |
150 | fd_set rfds; | 154 | fd_set rfds; |
151 | FD_ZERO(&rfds); | 155 | FD_ZERO(&rfds); |
152 | FD_SET(nSocket, &rfds); | 156 | FD_SET(nTcpSocket, &rfds); |
153 | struct timeval tv = {0, 0}; | 157 | struct timeval tv = {0, 0}; |
154 | if( bu_select( nSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) | 158 | if( bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) |
155 | { | 159 | { |
156 | int iErr = errno; | 160 | int iErr = errno; |
157 | close(); | 161 | close(); |
158 | throw SocketException( SocketException::cRead, strerror(iErr) ); | 162 | throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); |
159 | } | 163 | } |
160 | if( FD_ISSET( nSocket, &rfds ) || bBlocking ) | 164 | if( FD_ISSET( nTcpSocket, &rfds ) || bBlocking ) |
161 | { | 165 | { |
162 | int nRead = TEMP_FAILURE_RETRY( | 166 | int nRead = TEMP_FAILURE_RETRY( |
163 | bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); | 167 | bu_recv( nTcpSocket, (char *) pBuf, nBytes, 0 ) ); |
164 | if( nRead == 0 ) | 168 | if( nRead == 0 ) |
165 | { | 169 | { |
166 | close(); | 170 | close(); |
167 | throw SocketException( SocketException::cClosed, "Socket closed."); | 171 | throw TcpSocketException( TcpSocketException::cClosed, "TcpSocket closed."); |
168 | } | 172 | } |
169 | if( nRead < 0 ) | 173 | if( nRead < 0 ) |
170 | { | 174 | { |
@@ -176,14 +180,14 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | |||
176 | if( errno == ENETRESET || errno == ECONNRESET ) | 180 | if( errno == ENETRESET || errno == ECONNRESET ) |
177 | { | 181 | { |
178 | close(); | 182 | close(); |
179 | throw SocketException( SocketException::cClosed, | 183 | throw TcpSocketException( TcpSocketException::cClosed, |
180 | strerror(errno) ); | 184 | strerror(errno) ); |
181 | } | 185 | } |
182 | if( errno == EAGAIN ) | 186 | if( errno == EAGAIN ) |
183 | return 0; | 187 | return 0; |
184 | int iErr = errno; | 188 | int iErr = errno; |
185 | close(); | 189 | close(); |
186 | throw SocketException( SocketException::cRead, strerror(iErr) ); | 190 | throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); |
187 | #endif | 191 | #endif |
188 | } | 192 | } |
189 | return nRead; | 193 | return nRead; |
@@ -191,7 +195,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes ) | |||
191 | return 0; | 195 | return 0; |
192 | } | 196 | } |
193 | 197 | ||
194 | size_t Bu::Socket::read( void *pBuf, size_t nBytes, | 198 | size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes, |
195 | uint32_t nSec, uint32_t nUSec ) | 199 | uint32_t nSec, uint32_t nUSec ) |
196 | { | 200 | { |
197 | struct timeval tv; | 201 | struct timeval tv; |
@@ -199,7 +203,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
199 | 203 | ||
200 | fd_set rfds; | 204 | fd_set rfds; |
201 | FD_ZERO(&rfds); | 205 | FD_ZERO(&rfds); |
202 | FD_SET(nSocket, &rfds); | 206 | FD_SET(nTcpSocket, &rfds); |
203 | 207 | ||
204 | #ifdef WIN32 | 208 | #ifdef WIN32 |
205 | DWORD dwStart = GetTickCount(); | 209 | DWORD dwStart = GetTickCount(); |
@@ -216,7 +220,7 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
216 | { | 220 | { |
217 | tv.tv_sec = nSec; | 221 | tv.tv_sec = nSec; |
218 | tv.tv_usec = nUSec; | 222 | tv.tv_usec = nUSec; |
219 | bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); | 223 | bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); |
220 | nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); | 224 | nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); |
221 | if( nRead >= nBytes ) | 225 | if( nRead >= nBytes ) |
222 | break; | 226 | break; |
@@ -235,13 +239,13 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, | |||
235 | return nRead; | 239 | return nRead; |
236 | } | 240 | } |
237 | 241 | ||
238 | size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) | 242 | size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes ) |
239 | { | 243 | { |
240 | //#ifdef WIN32 | 244 | //#ifdef WIN32 |
241 | int nWrote = TEMP_FAILURE_RETRY( | 245 | int nWrote = TEMP_FAILURE_RETRY( |
242 | bu_send( nSocket, (const char *) pBuf, nBytes, 0 ) ); | 246 | bu_send( nTcpSocket, (const char *) pBuf, nBytes, 0 ) ); |
243 | //#else | 247 | //#else |
244 | // int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); | 248 | // int nWrote = TEMP_FAILURE_RETRY( ::write( nTcpSocket, pBuf, nBytes ) ); |
245 | //#endif | 249 | //#endif |
246 | if( nWrote < 0 ) | 250 | if( nWrote < 0 ) |
247 | { | 251 | { |
@@ -252,19 +256,19 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) | |||
252 | #else | 256 | #else |
253 | if( errno == EAGAIN ) return 0; | 257 | if( errno == EAGAIN ) return 0; |
254 | #endif | 258 | #endif |
255 | throw SocketException( SocketException::cWrite, strerror(errno) ); | 259 | throw TcpSocketException( TcpSocketException::cWrite, strerror(errno) ); |
256 | } | 260 | } |
257 | return nWrote; | 261 | return nWrote; |
258 | } | 262 | } |
259 | 263 | ||
260 | size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) | 264 | size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) |
261 | { | 265 | { |
262 | struct timeval tv; | 266 | struct timeval tv; |
263 | size_t nWrote = 0; | 267 | size_t nWrote = 0; |
264 | 268 | ||
265 | fd_set wfds; | 269 | fd_set wfds; |
266 | FD_ZERO(&wfds); | 270 | FD_ZERO(&wfds); |
267 | FD_SET(nSocket, &wfds); | 271 | FD_SET(nTcpSocket, &wfds); |
268 | 272 | ||
269 | #ifdef WIN32 | 273 | #ifdef WIN32 |
270 | DWORD dwStart = GetTickCount(); | 274 | DWORD dwStart = GetTickCount(); |
@@ -281,7 +285,7 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32 | |||
281 | { | 285 | { |
282 | tv.tv_sec = nSec; | 286 | tv.tv_sec = nSec; |
283 | tv.tv_usec = nUSec; | 287 | tv.tv_usec = nUSec; |
284 | bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); | 288 | bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); |
285 | nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); | 289 | nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); |
286 | if( nWrote >= nBytes ) | 290 | if( nWrote >= nBytes ) |
287 | break; | 291 | break; |
@@ -300,101 +304,101 @@ size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32 | |||
300 | return nWrote; | 304 | return nWrote; |
301 | } | 305 | } |
302 | 306 | ||
303 | long Bu::Socket::tell() | 307 | long Bu::TcpSocket::tell() |
304 | { | 308 | { |
305 | throw UnsupportedException(); | 309 | throw UnsupportedException(); |
306 | } | 310 | } |
307 | 311 | ||
308 | void Bu::Socket::seek( long ) | 312 | void Bu::TcpSocket::seek( long ) |
309 | { | 313 | { |
310 | throw UnsupportedException(); | 314 | throw UnsupportedException(); |
311 | } | 315 | } |
312 | 316 | ||
313 | void Bu::Socket::setPos( long ) | 317 | void Bu::TcpSocket::setPos( long ) |
314 | { | 318 | { |
315 | throw UnsupportedException(); | 319 | throw UnsupportedException(); |
316 | } | 320 | } |
317 | 321 | ||
318 | void Bu::Socket::setPosEnd( long ) | 322 | void Bu::TcpSocket::setPosEnd( long ) |
319 | { | 323 | { |
320 | throw UnsupportedException(); | 324 | throw UnsupportedException(); |
321 | } | 325 | } |
322 | 326 | ||
323 | bool Bu::Socket::isEos() | 327 | bool Bu::TcpSocket::isEos() |
324 | { | 328 | { |
325 | return !bActive; | 329 | return !bActive; |
326 | } | 330 | } |
327 | 331 | ||
328 | bool Bu::Socket::canRead() | 332 | bool Bu::TcpSocket::canRead() |
329 | { | 333 | { |
330 | fd_set rfds; | 334 | fd_set rfds; |
331 | FD_ZERO(&rfds); | 335 | FD_ZERO(&rfds); |
332 | FD_SET(nSocket, &rfds); | 336 | FD_SET(nTcpSocket, &rfds); |
333 | struct timeval tv = { 0, 0 }; | 337 | struct timeval tv = { 0, 0 }; |
334 | int retval = bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); | 338 | int retval = bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); |
335 | if( retval == -1 ) | 339 | if( retval == -1 ) |
336 | throw SocketException( | 340 | throw TcpSocketException( |
337 | SocketException::cBadRead, | 341 | TcpSocketException::cBadRead, |
338 | "Bad Read error" | 342 | "Bad Read error" |
339 | ); | 343 | ); |
340 | 344 | ||
341 | if( !FD_ISSET( nSocket, &rfds ) ) | 345 | if( !FD_ISSET( nTcpSocket, &rfds ) ) |
342 | return false; | 346 | return false; |
343 | return true; | 347 | return true; |
344 | } | 348 | } |
345 | 349 | ||
346 | bool Bu::Socket::canWrite() | 350 | bool Bu::TcpSocket::canWrite() |
347 | { | 351 | { |
348 | fd_set wfds; | 352 | fd_set wfds; |
349 | FD_ZERO(&wfds); | 353 | FD_ZERO(&wfds); |
350 | FD_SET(nSocket, &wfds); | 354 | FD_SET(nTcpSocket, &wfds); |
351 | struct timeval tv = { 0, 0 }; | 355 | struct timeval tv = { 0, 0 }; |
352 | int retval = bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); | 356 | int retval = bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); |
353 | if( retval == -1 ) | 357 | if( retval == -1 ) |
354 | throw SocketException( | 358 | throw TcpSocketException( |
355 | SocketException::cBadRead, | 359 | TcpSocketException::cBadRead, |
356 | "Bad Read error" | 360 | "Bad Read error" |
357 | ); | 361 | ); |
358 | if( !FD_ISSET( nSocket, &wfds ) ) | 362 | if( !FD_ISSET( nTcpSocket, &wfds ) ) |
359 | return false; | 363 | return false; |
360 | return true; | 364 | return true; |
361 | } | 365 | } |
362 | 366 | ||
363 | bool Bu::Socket::isReadable() | 367 | bool Bu::TcpSocket::isReadable() |
364 | { | 368 | { |
365 | return true; | 369 | return true; |
366 | } | 370 | } |
367 | 371 | ||
368 | bool Bu::Socket::isWritable() | 372 | bool Bu::TcpSocket::isWritable() |
369 | { | 373 | { |
370 | return true; | 374 | return true; |
371 | } | 375 | } |
372 | 376 | ||
373 | bool Bu::Socket::isSeekable() | 377 | bool Bu::TcpSocket::isSeekable() |
374 | { | 378 | { |
375 | return false; | 379 | return false; |
376 | } | 380 | } |
377 | 381 | ||
378 | bool Bu::Socket::isBlocking() | 382 | bool Bu::TcpSocket::isBlocking() |
379 | { | 383 | { |
380 | #ifndef WIN32 | 384 | #ifndef WIN32 |
381 | return ((fcntl( nSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); | 385 | return ((fcntl( nTcpSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); |
382 | #else | 386 | #else |
383 | return false; | 387 | return false; |
384 | #endif | 388 | #endif |
385 | } | 389 | } |
386 | 390 | ||
387 | void Bu::Socket::setBlocking( bool bBlocking ) | 391 | void Bu::TcpSocket::setBlocking( bool bBlocking ) |
388 | { | 392 | { |
389 | this->bBlocking = bBlocking; | 393 | this->bBlocking = bBlocking; |
390 | #ifndef WIN32 | 394 | #ifndef WIN32 |
391 | if( bBlocking ) | 395 | if( bBlocking ) |
392 | { | 396 | { |
393 | fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); | 397 | fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); |
394 | } | 398 | } |
395 | else | 399 | else |
396 | { | 400 | { |
397 | fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) | O_NONBLOCK ); | 401 | fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) | O_NONBLOCK ); |
398 | } | 402 | } |
399 | #else | 403 | #else |
400 | u_long iMode; | 404 | u_long iMode; |
@@ -408,39 +412,39 @@ void Bu::Socket::setBlocking( bool bBlocking ) | |||
408 | // socket based on the numerical value of iMode. | 412 | // socket based on the numerical value of iMode. |
409 | // If iMode = 0, blocking is enabled; | 413 | // If iMode = 0, blocking is enabled; |
410 | // If iMode != 0, non-blocking mode is enabled. | 414 | // If iMode != 0, non-blocking mode is enabled. |
411 | bu_ioctlsocket(nSocket, FIONBIO, &iMode); | 415 | bu_ioctlsocket(nTcpSocket, FIONBIO, &iMode); |
412 | #endif | 416 | #endif |
413 | } | 417 | } |
414 | 418 | ||
415 | void Bu::Socket::setSize( long ) | 419 | void Bu::TcpSocket::setSize( long ) |
416 | { | 420 | { |
417 | } | 421 | } |
418 | 422 | ||
419 | void Bu::Socket::flush() | 423 | void Bu::TcpSocket::flush() |
420 | { | 424 | { |
421 | } | 425 | } |
422 | 426 | ||
423 | bool Bu::Socket::isOpen() | 427 | bool Bu::TcpSocket::isOpen() |
424 | { | 428 | { |
425 | return bActive; | 429 | return bActive; |
426 | } | 430 | } |
427 | 431 | ||
428 | void Bu::Socket::setAddress() | 432 | void Bu::TcpSocket::setAddress() |
429 | { | 433 | { |
430 | struct sockaddr_in addr; | 434 | struct sockaddr_in addr; |
431 | socklen_t len = sizeof(addr); | 435 | socklen_t len = sizeof(addr); |
432 | addr.sin_family = AF_INET; | 436 | addr.sin_family = AF_INET; |
433 | bu_getpeername( nSocket, (sockaddr *)(&addr), &len ); | 437 | bu_getpeername( nTcpSocket, (sockaddr *)(&addr), &len ); |
434 | sAddress = bu_inet_ntoa( addr.sin_addr ); | 438 | sAddress = bu_inet_ntoa( addr.sin_addr ); |
435 | } | 439 | } |
436 | 440 | ||
437 | Bu::FString Bu::Socket::getAddress() const | 441 | Bu::FString Bu::TcpSocket::getAddress() const |
438 | { | 442 | { |
439 | return sAddress; | 443 | return sAddress; |
440 | } | 444 | } |
441 | 445 | ||
442 | Bu::Socket::operator int() const | 446 | Bu::TcpSocket::operator int() const |
443 | { | 447 | { |
444 | return nSocket; | 448 | return nTcpSocket; |
445 | } | 449 | } |
446 | 450 | ||
diff --git a/src/socket.h b/src/tcpsocket.h index c8f78f0..3361e84 100644 --- a/src/socket.h +++ b/src/tcpsocket.h | |||
@@ -5,8 +5,8 @@ | |||
5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #ifndef BU_SOCKET_H | 8 | #ifndef BU_TCP_SOCKET_H |
9 | #define BU_SOCKET_H | 9 | #define BU_TCP_SOCKET_H |
10 | 10 | ||
11 | #include <stdint.h> | 11 | #include <stdint.h> |
12 | 12 | ||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | namespace Bu | 17 | namespace Bu |
18 | { | 18 | { |
19 | subExceptionDeclBegin( SocketException ); | 19 | subExceptionDeclBegin( TcpSocketException ); |
20 | enum { | 20 | enum { |
21 | cRead, | 21 | cRead, |
22 | cWrite, | 22 | cWrite, |
@@ -40,28 +40,29 @@ namespace Bu | |||
40 | * Please note that there is a condition that will occur eventually (at | 40 | * Please note that there is a condition that will occur eventually (at |
41 | * least on *nix systems) that will trigger a SIGPIPE condition. This | 41 | * least on *nix systems) that will trigger a SIGPIPE condition. This |
42 | * will terminate your program immediately unless handled properly. Most | 42 | * will terminate your program immediately unless handled properly. Most |
43 | * people doing any connections with Socket will want to put this in their | 43 | * people doing any connections with TcpSocket will want to put this in |
44 | * program somewhere before they use it: | 44 | * their program somewhere before they use it: |
45 | *@code | 45 | *@code |
46 | #include <signal.h> | 46 | #include <signal.h> |
47 | ... | 47 | ... |
48 | ... | 48 | ... |
49 | ... | 49 | ... |
50 | sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::Socket | 50 | sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::TcpSocket |
51 | @endcode | 51 | @endcode |
52 | * When this is done, Bu::Socket will simply throw a broken pipe exception | 52 | * When this is done, Bu::TcpSocket will simply throw a broken pipe |
53 | * just like every other error condition, allowing your program to handle | 53 | * exception just like every other error condition, allowing your program |
54 | * it sanely. | 54 | * to handle it sanely. |
55 | * | 55 | * |
56 | *@ingroup Serving | 56 | *@ingroup Serving |
57 | *@ingroup Streams | 57 | *@ingroup Streams |
58 | */ | 58 | */ |
59 | class Socket : public Stream | 59 | class TcpSocket : public Stream |
60 | { | 60 | { |
61 | public: | 61 | public: |
62 | Socket( int nSocket ); | 62 | TcpSocket( int nTcpSocket ); |
63 | Socket( const FString &sAddr, int nPort, int nTimeout=30 ); | 63 | TcpSocket( const FString &sAddr, int nPort, int nTimeout=30, |
64 | virtual ~Socket(); | 64 | bool bBlocking=true ); |
65 | virtual ~TcpSocket(); | ||
65 | 66 | ||
66 | virtual void close(); | 67 | virtual void close(); |
67 | //virtual void read(); | 68 | //virtual void read(); |
@@ -101,9 +102,9 @@ namespace Bu | |||
101 | void setAddress(); | 102 | void setAddress(); |
102 | 103 | ||
103 | #ifdef WIN32 | 104 | #ifdef WIN32 |
104 | unsigned int nSocket; | 105 | unsigned int nTcpSocket; |
105 | #else | 106 | #else |
106 | int nSocket; | 107 | int nTcpSocket; |
107 | #endif | 108 | #endif |
108 | bool bActive; | 109 | bool bActive; |
109 | bool bBlocking; | 110 | bool bBlocking; |
diff --git a/src/tests/sharedcore.cpp b/src/tests/sharedcore.cpp index 1d0c16e..9b0a0ec 100644 --- a/src/tests/sharedcore.cpp +++ b/src/tests/sharedcore.cpp | |||
@@ -14,7 +14,7 @@ struct ShintCore | |||
14 | { | 14 | { |
15 | int val; | 15 | int val; |
16 | }; | 16 | }; |
17 | class Shint : public Bu::SharedCore<struct ShintCore> | 17 | class Shint : public Bu::SharedCore<Shint, struct ShintCore> |
18 | { | 18 | { |
19 | public: | 19 | public: |
20 | Shint() | 20 | Shint() |
diff --git a/src/tests/socketblock.cpp b/src/tests/socketblock.cpp index a1ea18d..793ef96 100644 --- a/src/tests/socketblock.cpp +++ b/src/tests/socketblock.cpp | |||
@@ -6,8 +6,8 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bu/ito.h" | 8 | #include "bu/ito.h" |
9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
10 | #include "bu/serversocket.h" | 10 | #include "bu/tcpserversocket.h" |
11 | #include <stdio.h> | 11 | #include <stdio.h> |
12 | #include <unistd.h> | 12 | #include <unistd.h> |
13 | 13 | ||
@@ -21,7 +21,7 @@ public: | |||
21 | 21 | ||
22 | virtual void run() | 22 | virtual void run() |
23 | { | 23 | { |
24 | Bu::Socket c = s.accept( 45, 0 ); | 24 | Bu::TcpSocket c = s.accept( 45, 0 ); |
25 | printf("TstServer: Accetped connection.\n"); fflush( stdout ); | 25 | printf("TstServer: Accetped connection.\n"); fflush( stdout ); |
26 | 26 | ||
27 | sleep( 1 ); | 27 | sleep( 1 ); |
@@ -35,7 +35,7 @@ public: | |||
35 | c.close(); | 35 | c.close(); |
36 | } | 36 | } |
37 | 37 | ||
38 | Bu::ServerSocket s; | 38 | Bu::TcpServerSocket s; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | int main() | 41 | int main() |
@@ -45,7 +45,7 @@ int main() | |||
45 | ts.start(); | 45 | ts.start(); |
46 | 46 | ||
47 | printf("main: Connecting to server.\n"); fflush( stdout ); | 47 | printf("main: Connecting to server.\n"); fflush( stdout ); |
48 | Bu::Socket s( "localhost", 55678 ); | 48 | Bu::TcpSocket s( "localhost", 55678 ); |
49 | 49 | ||
50 | printf("main: Sending 4 bytes.\n"); fflush( stdout ); | 50 | printf("main: Sending 4 bytes.\n"); fflush( stdout ); |
51 | s.write( "aoeu", 4 ); | 51 | s.write( "aoeu", 4 ); |
diff --git a/src/tests/socketbreak.cpp b/src/tests/socketbreak.cpp index 8339630..7d3c71a 100644 --- a/src/tests/socketbreak.cpp +++ b/src/tests/socketbreak.cpp | |||
@@ -5,17 +5,17 @@ | |||
5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include "bu/serversocket.h" | 8 | #include "bu/tcpserversocket.h" |
9 | #include "bu/socket.h" | 9 | #include "bu/tcpsocket.h" |
10 | #include <unistd.h> | 10 | #include <unistd.h> |
11 | 11 | ||
12 | int main() | 12 | int main() |
13 | { | 13 | { |
14 | Bu::ServerSocket sSrv( 9987 ); | 14 | Bu::TcpServerSocket sSrv( 9987 ); |
15 | 15 | ||
16 | Bu::Socket sSend("localhost", 9987 ); | 16 | Bu::TcpSocket sSend("localhost", 9987 ); |
17 | 17 | ||
18 | Bu::Socket sRecv( sSrv.accept() ); | 18 | Bu::TcpSocket sRecv( sSrv.accept() ); |
19 | 19 | ||
20 | printf("Connected sockets.\n"); | 20 | printf("Connected sockets.\n"); |
21 | 21 | ||
diff --git a/src/tests/socket.cpp b/src/tests/tcpsocket.cpp index ba4e9b9..30dd22f 100644 --- a/src/tests/socket.cpp +++ b/src/tests/tcpsocket.cpp | |||
@@ -5,7 +5,7 @@ | |||
5 | * terms of the license contained in the file LICENSE. | 5 | * terms of the license contained in the file LICENSE. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <bu/socket.h> | 8 | #include <bu/tcpsocket.h> |
9 | #include <bu/sio.h> | 9 | #include <bu/sio.h> |
10 | 10 | ||
11 | #include <sys/time.h> | 11 | #include <sys/time.h> |
@@ -17,7 +17,7 @@ bool isUp() | |||
17 | { | 17 | { |
18 | try | 18 | try |
19 | { | 19 | { |
20 | Socket s("xagasoft.com", 9898, 1 ); | 20 | TcpSocket s("xagasoft.com", 9898, 1 ); |
21 | 21 | ||
22 | char buf[5]; | 22 | char buf[5]; |
23 | buf[s.read(buf, 2, 1, 0)] = '\0'; | 23 | buf[s.read(buf, 2, 1, 0)] = '\0'; |
diff --git a/src/tools/bnfcompile.cpp b/src/tools/bnfcompile.cpp new file mode 100644 index 0000000..16e75a5 --- /dev/null +++ b/src/tools/bnfcompile.cpp | |||
@@ -0,0 +1,410 @@ | |||
1 | #include <bu/sio.h> | ||
2 | #include <bu/lexer.h> | ||
3 | #include <bu/parser.h> | ||
4 | #include <bu/file.h> | ||
5 | #include <bu/queuebuf.h> | ||
6 | |||
7 | using namespace Bu; | ||
8 | |||
9 | enum TokenType | ||
10 | { | ||
11 | tokIdentifier, | ||
12 | tokColon, | ||
13 | tokOr, | ||
14 | tokSemiColon, | ||
15 | tokTokens, | ||
16 | tokEquals, | ||
17 | tokOpenCurly, | ||
18 | tokCloseCurly, | ||
19 | tokOpenSquare, | ||
20 | tokCloseSquare, | ||
21 | |||
22 | tokEos=-1 | ||
23 | }; | ||
24 | |||
25 | class BnfLexer : public Lexer | ||
26 | { | ||
27 | public: | ||
28 | BnfLexer( Stream &rSrc ) : | ||
29 | rSrc( rSrc ) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | virtual ~BnfLexer() | ||
34 | { | ||
35 | } | ||
36 | |||
37 | virtual Token *nextToken() | ||
38 | { | ||
39 | char cBuf; | ||
40 | |||
41 | for(;;) | ||
42 | { | ||
43 | if( qbIn.getSize() == 0 ) | ||
44 | { | ||
45 | char buf[4096]; | ||
46 | qbIn.write( buf, rSrc.read( buf, 4096 ) ); | ||
47 | |||
48 | if( rSrc.isEos() && qbIn.getSize() == 0 ) | ||
49 | return new Token( tokEos ); | ||
50 | } | ||
51 | qbIn.peek( &cBuf, 1 ); | ||
52 | if( (cBuf >= 'a' && cBuf <= 'z') || | ||
53 | (cBuf >= 'A' && cBuf <= 'Z') || | ||
54 | (cBuf >= '0' && cBuf <= '9') || | ||
55 | cBuf == '_' ) | ||
56 | { | ||
57 | sBuf.append( cBuf ); | ||
58 | qbIn.seek( 1 ); | ||
59 | } | ||
60 | else if( sBuf.isSet() ) | ||
61 | { | ||
62 | if( sBuf == "tokens" ) | ||
63 | { | ||
64 | sBuf.clear(); | ||
65 | return new Token( tokTokens ); | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | Token *pRet = new Token( tokIdentifier, sBuf ); | ||
70 | sBuf.clear(); | ||
71 | return pRet; | ||
72 | } | ||
73 | } | ||
74 | else | ||
75 | { | ||
76 | switch( cBuf ) | ||
77 | { | ||
78 | case ' ': | ||
79 | case '\t': | ||
80 | case '\n': | ||
81 | case '\r': | ||
82 | qbIn.seek( 1 ); | ||
83 | continue; | ||
84 | |||
85 | case ':': | ||
86 | qbIn.seek( 1 ); | ||
87 | return new Token( tokColon ); | ||
88 | |||
89 | case ';': | ||
90 | qbIn.seek( 1 ); | ||
91 | return new Token( tokSemiColon ); | ||
92 | |||
93 | case '|': | ||
94 | qbIn.seek( 1 ); | ||
95 | return new Token( tokOr ); | ||
96 | |||
97 | case '=': | ||
98 | qbIn.seek( 1 ); | ||
99 | return new Token( tokEquals ); | ||
100 | |||
101 | case '[': | ||
102 | qbIn.seek( 1 ); | ||
103 | return new Token( tokOpenSquare ); | ||
104 | |||
105 | case ']': | ||
106 | qbIn.seek( 1 ); | ||
107 | return new Token( tokCloseSquare ); | ||
108 | |||
109 | case '{': | ||
110 | qbIn.seek( 1 ); | ||
111 | return new Token( tokOpenCurly ); | ||
112 | |||
113 | case '}': | ||
114 | qbIn.seek( 1 ); | ||
115 | return new Token( tokCloseCurly ); | ||
116 | |||
117 | default: | ||
118 | throw ExceptionBase("Unexpected character '%c'.", | ||
119 | cBuf ); | ||
120 | break; | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | virtual FString tokenToString( const Token &t ) | ||
127 | { | ||
128 | switch( (TokenType)t.iToken ) | ||
129 | { | ||
130 | case tokIdentifier: return "tokIdentifier"; | ||
131 | case tokColon: return "tokColon"; | ||
132 | case tokOr: return "tokOr"; | ||
133 | case tokSemiColon: return "tokSemiColon"; | ||
134 | case tokTokens: return "tokTokens"; | ||
135 | case tokEquals: return "tokEquals"; | ||
136 | case tokOpenCurly: return "tokOpenCurly"; | ||
137 | case tokCloseCurly: return "tokCloseCurly"; | ||
138 | case tokOpenSquare: return "tokOpenSquare"; | ||
139 | case tokCloseSquare: return "tokCloseSquare"; | ||
140 | case tokEos: return "tokEos"; | ||
141 | } | ||
142 | |||
143 | return "???"; | ||
144 | } | ||
145 | |||
146 | private: | ||
147 | Stream &rSrc; | ||
148 | QueueBuf qbIn; | ||
149 | FString sBuf; | ||
150 | }; | ||
151 | |||
152 | class BnfParser | ||
153 | { | ||
154 | public: | ||
155 | BnfParser( BnfLexer &l ) : | ||
156 | l( l ), | ||
157 | pCur( NULL ), | ||
158 | iLastToken( 0 ) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | virtual ~BnfParser() | ||
163 | { | ||
164 | delete pCur; | ||
165 | pCur = NULL; | ||
166 | } | ||
167 | |||
168 | void parse() | ||
169 | { | ||
170 | for(;;) | ||
171 | { | ||
172 | next(); | ||
173 | switch( pCur->iToken ) | ||
174 | { | ||
175 | case tokTokens: | ||
176 | tokens(); | ||
177 | break; | ||
178 | |||
179 | case tokIdentifier: | ||
180 | nonTerminal(); | ||
181 | break; | ||
182 | |||
183 | case tokEos: | ||
184 | return; | ||
185 | break; | ||
186 | |||
187 | default: | ||
188 | tokenError("tokTokens, tokIdentifier, or tokEos"); | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | private: | ||
194 | void tokens() | ||
195 | { | ||
196 | next(); | ||
197 | if( pCur->iToken != tokEquals ) | ||
198 | tokenError("tokEquals"); | ||
199 | for(;;) | ||
200 | { | ||
201 | next(); | ||
202 | if( pCur->iToken == tokIdentifier ) | ||
203 | { | ||
204 | hTokens.insert( pCur->vExtra.get<Bu::FString>(), ++iLastToken ); | ||
205 | sio << "Added token[" << iLastToken << "]: " | ||
206 | << pCur->vExtra.get<Bu::FString>() << sio.nl; | ||
207 | } | ||
208 | else if( pCur->iToken == tokSemiColon ) | ||
209 | break; | ||
210 | else | ||
211 | tokenError("tokIdentifier or tokSemiColon"); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | void nonTerminal() | ||
216 | { | ||
217 | Bu::FString sNtName = pCur->vExtra.get<Bu::FString>(); | ||
218 | Parser::NonTerminal nt; | ||
219 | p.addNonTerminal( sNtName ); | ||
220 | sio.incIndent(); | ||
221 | sio << "Created non-terminal: " << sNtName << sio.nl; | ||
222 | |||
223 | next(); | ||
224 | if( pCur->iToken != tokColon ) | ||
225 | tokenError("tokColon"); | ||
226 | production( nt ); | ||
227 | for(;;) | ||
228 | { | ||
229 | switch( pCur->iToken ) | ||
230 | { | ||
231 | case tokOr: | ||
232 | production( nt ); | ||
233 | break; | ||
234 | |||
235 | case tokSemiColon: | ||
236 | p.setNonTerminal( sNtName, nt ); | ||
237 | sio.decIndent(); | ||
238 | sio << "Closing non-terminal." << sio.nl; | ||
239 | return; | ||
240 | |||
241 | default: | ||
242 | tokenError("tkOr or tokSemiColon"); | ||
243 | break; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | void production( Parser::NonTerminal &nt ) | ||
249 | { | ||
250 | sio.incIndent(); | ||
251 | sio << "Adding new production:" << sio.nl; | ||
252 | Parser::Production pr; | ||
253 | bool bAnything = false; | ||
254 | for(;;) | ||
255 | { | ||
256 | next(); | ||
257 | switch( pCur->iToken ) | ||
258 | { | ||
259 | case tokIdentifier: | ||
260 | { | ||
261 | const Bu::FString &sName = | ||
262 | pCur->vExtra.get<Bu::FString>(); | ||
263 | if( hTokens.has( sName ) ) | ||
264 | { | ||
265 | pr.append( | ||
266 | Parser::State( | ||
267 | Parser::State::typeTerminal, | ||
268 | hTokens.get( sName ) | ||
269 | ) | ||
270 | ); | ||
271 | sio << "Added terminal " << sName << sio.nl; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | if( !p.hasNonTerminal( sName ) ) | ||
276 | { | ||
277 | p.addNonTerminal( sName ); | ||
278 | } | ||
279 | pr.append( | ||
280 | Parser::State( | ||
281 | Parser::State::typeNonTerminal, | ||
282 | p.getNonTerminalId( sName ) | ||
283 | ) | ||
284 | ); | ||
285 | sio << "Added non-terminal " << sName << sio.nl; | ||
286 | } | ||
287 | } | ||
288 | break; | ||
289 | |||
290 | case tokOpenSquare: | ||
291 | { | ||
292 | next(); | ||
293 | if( pCur->iToken != tokIdentifier ) | ||
294 | tokenError("tokIdentifier"); | ||
295 | Bu::FString sName = | ||
296 | pCur->vExtra.get<Bu::FString>(); | ||
297 | next(); | ||
298 | if( pCur->iToken != tokCloseSquare ) | ||
299 | tokenError("tokCloseSquare"); | ||
300 | |||
301 | if( !hTokens.has( sName ) ) | ||
302 | throw ExceptionBase("Only token names may be " | ||
303 | "enclosed in square brackets."); | ||
304 | |||
305 | pr.append( | ||
306 | Parser::State( | ||
307 | Parser::State::typeTerminalPush, | ||
308 | hTokens.get( sName ) | ||
309 | ) | ||
310 | ); | ||
311 | sio << "Added terminal-push " << sName << sio.nl; | ||
312 | } | ||
313 | break; | ||
314 | |||
315 | case tokOpenCurly: | ||
316 | { | ||
317 | next(); | ||
318 | if( pCur->iToken != tokIdentifier ) | ||
319 | tokenError("tokIdentifier"); | ||
320 | Bu::FString sName = | ||
321 | pCur->vExtra.get<Bu::FString>(); | ||
322 | next(); | ||
323 | if( pCur->iToken != tokCloseCurly ) | ||
324 | tokenError("tokCloseCurly"); | ||
325 | |||
326 | if( !p.hasReduction( sName ) ) | ||
327 | p.addReduction( sName ); | ||
328 | |||
329 | pr.append( | ||
330 | Parser::State( | ||
331 | Parser::State::typeReduction, | ||
332 | p.getReductionId( sName ) | ||
333 | ) | ||
334 | ); | ||
335 | sio << "Added reduction " << sName << sio.nl; | ||
336 | } | ||
337 | break; | ||
338 | |||
339 | case tokOr: | ||
340 | case tokSemiColon: | ||
341 | if( bAnything ) | ||
342 | { | ||
343 | nt.addProduction( pr ); | ||
344 | sio.decIndent(); | ||
345 | sio << "Closing production." << sio.nl; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | nt.setCanSkip(); | ||
350 | sio.decIndent(); | ||
351 | sio << "Closing empty production." << sio.nl; | ||
352 | } | ||
353 | return; | ||
354 | |||
355 | default: | ||
356 | tokenError("tokIdentifier, tokOpenSquare, tokOr, " | ||
357 | "tokOpenCurly, or tokSemiColon"); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | |||
362 | private: | ||
363 | void next() | ||
364 | { | ||
365 | delete pCur; | ||
366 | pCur = l.nextToken(); | ||
367 | } | ||
368 | |||
369 | void tokenError( const FString &s ) | ||
370 | { | ||
371 | throw ExceptionBase( ("Expected " + s + " but found " | ||
372 | + l.tokenToString( *pCur ) + ".").getStr() ); | ||
373 | } | ||
374 | |||
375 | private: | ||
376 | typedef Bu::Hash<Bu::FString, int> TokenHash; | ||
377 | TokenHash hTokens; | ||
378 | BnfLexer &l; | ||
379 | BnfLexer::Token *pCur; | ||
380 | int iLastToken; | ||
381 | Parser p; | ||
382 | }; | ||
383 | |||
384 | int main( int argc, char *argv[] ) | ||
385 | { | ||
386 | File fIn( argv[1], File::Read ); | ||
387 | |||
388 | BnfLexer bl( fIn ); | ||
389 | BnfParser parser( bl ); | ||
390 | |||
391 | parser.parse(); | ||
392 | |||
393 | /* | ||
394 | for(;;) | ||
395 | { | ||
396 | Lexer::Token *pTok = bl.nextToken(); | ||
397 | sio << bl.tokenToString(*pTok); | ||
398 | if( pTok->vExtra.isSet() ) | ||
399 | { | ||
400 | sio << " - " << pTok->vExtra; | ||
401 | } | ||
402 | sio << sio.nl; | ||
403 | if( pTok->iToken == tokEos ) | ||
404 | break; | ||
405 | } | ||
406 | */ | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
diff --git a/src/tools/myriadfs.cpp b/src/tools/myriadfs.cpp new file mode 100644 index 0000000..66955a5 --- /dev/null +++ b/src/tools/myriadfs.cpp | |||
@@ -0,0 +1,38 @@ | |||
1 | #define FUSE_USE_VERSION 26 | ||
2 | |||
3 | #include <fuse.h> | ||
4 | |||
5 | #include <string.h> | ||
6 | |||
7 | extern "C" { | ||
8 | static int myriadfs_getattr( const char *sPath, struct stat *stbuf ) | ||
9 | { | ||
10 | |||
11 | } | ||
12 | |||
13 | static int myriadfs_readdir( const char *sPath, void *buf, | ||
14 | fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi ) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | static int myriadfs_open( const char *sPath, struct fuse_file_info *fi ) | ||
19 | { | ||
20 | } | ||
21 | |||
22 | static int myriadfs_read( const char *sPath, char *buf, size_t iSize, | ||
23 | off_t iOffset, struct fuse_file_info *fi ) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | static struct fuse_operations myriadfs_oper; | ||
28 | |||
29 | int main( int argc, char *argv[] ) | ||
30 | { | ||
31 | memset( &myriadfs_oper, sizeof(myriadfs_oper), 0 ); | ||
32 | myriadfs_oper.getattr = myriadfs_getattr; | ||
33 | myriadfs_oper.readdir = myriadfs_readdir; | ||
34 | myriadfs_oper.open = myriadfs_open; | ||
35 | myriadfs_oper.read = myriadfs_read; | ||
36 | return fuse_main( argc, argv, &myriadfs_oper, NULL ); | ||
37 | } | ||
38 | } | ||
diff --git a/src/tools/parser.cpp b/src/tools/parser.cpp index 76d4a72..7933f31 100644 --- a/src/tools/parser.cpp +++ b/src/tools/parser.cpp | |||
@@ -151,10 +151,43 @@ private: | |||
151 | 151 | ||
152 | void redAdd( Bu::Parser &p ) | 152 | void redAdd( Bu::Parser &p ) |
153 | { | 153 | { |
154 | Lexer::Token *a = p.popToken(); | ||
155 | Lexer::Token *b = p.popToken(); | ||
156 | |||
157 | sio << "Add! " << b->vExtra.get<double>() << " + " | ||
158 | << a->vExtra.get<double>() << sio.nl; | ||
159 | |||
160 | Lexer::Token *c = new Lexer::Token( tokNumber, | ||
161 | b->vExtra.get<double>() + a->vExtra.get<double>() | ||
162 | ); | ||
163 | p.pushToken( c ); | ||
164 | |||
165 | delete a; | ||
166 | delete b; | ||
167 | } | ||
168 | |||
169 | void redSubtract( Bu::Parser &p ) | ||
170 | { | ||
171 | Lexer::Token *a = p.popToken(); | ||
172 | Lexer::Token *b = p.popToken(); | ||
173 | |||
174 | sio << "Subtract! " << b->vExtra.get<double>() << " - " | ||
175 | << a->vExtra.get<double>() << sio.nl; | ||
176 | |||
177 | Lexer::Token *c = new Lexer::Token( tokNumber, | ||
178 | b->vExtra.get<double>() - a->vExtra.get<double>() | ||
179 | ); | ||
180 | p.pushToken( c ); | ||
181 | |||
182 | delete a; | ||
183 | delete b; | ||
154 | } | 184 | } |
155 | 185 | ||
156 | void redPrint( Bu::Parser &p ) | 186 | void redPrint( Bu::Parser &p ) |
157 | { | 187 | { |
188 | Lexer::Token *a = p.popToken(); | ||
189 | sio << "Print! = " << a->vExtra.get<double>() << sio.nl; | ||
190 | delete a; | ||
158 | } | 191 | } |
159 | 192 | ||
160 | /* Basic grammer example: | 193 | /* Basic grammer example: |
@@ -170,14 +203,15 @@ void redPrint( Bu::Parser &p ) | |||
170 | * The problem is, that we can't actually make something left hand recursive, | 203 | * The problem is, that we can't actually make something left hand recursive, |
171 | * so we break it into two exprs: | 204 | * so we break it into two exprs: |
172 | * | 205 | * |
173 | * expr': '(' expr ')' | 206 | * expr-sub1: '(' expr ')' |
174 | * | NUMBER | 207 | * | NUMBER |
175 | * ; | 208 | * ; |
176 | * | 209 | * |
177 | * expr: expr' expr'' | 210 | * expr: expr-sub1 expr-sub2 |
178 | * ; | 211 | * ; |
179 | * | 212 | * |
180 | * expr'': '+' expr | 213 | * expr-sub2: '+' expr |
214 | * | '-' expr | ||
181 | * | | 215 | * | |
182 | * ; | 216 | * ; |
183 | * | 217 | * |
@@ -191,8 +225,8 @@ int main( int argc, char *argv[] ) | |||
191 | Parser p; | 225 | Parser p; |
192 | 226 | ||
193 | p.addNonTerminal("expr"); | 227 | p.addNonTerminal("expr"); |
194 | p.addNonTerminal("expr'"); | 228 | p.addNonTerminal("expr-sub1"); |
195 | p.addNonTerminal("expr''"); | 229 | p.addNonTerminal("expr-sub2"); |
196 | { | 230 | { |
197 | Parser::NonTerminal nt; | 231 | Parser::NonTerminal nt; |
198 | nt.addProduction( | 232 | nt.addProduction( |
@@ -215,10 +249,28 @@ int main( int argc, char *argv[] ) | |||
215 | ); | 249 | ); |
216 | nt.addProduction( | 250 | nt.addProduction( |
217 | Parser::Production( | 251 | Parser::Production( |
252 | Parser::State( | ||
253 | Parser::State::typeTerminal, | ||
254 | tokMinus | ||
255 | ) | ||
256 | ).append( | ||
257 | Parser::State( | ||
258 | Parser::State::typeNonTerminal, | ||
259 | p.getNonTerminalId("expr") | ||
260 | ) | ||
261 | ).append( | ||
262 | Parser::State( | ||
263 | Parser::State::typeReduction, | ||
264 | p.addReduction("subtract") | ||
265 | ) | ||
266 | ) | ||
267 | ); | ||
268 | nt.addProduction( | ||
269 | Parser::Production( | ||
218 | ) | 270 | ) |
219 | ); | 271 | ); |
220 | nt.setCanSkip(); | 272 | nt.setCanSkip(); |
221 | p.setNonTerminal("expr''", nt ); | 273 | p.setNonTerminal("expr-sub2", nt ); |
222 | } | 274 | } |
223 | { | 275 | { |
224 | Parser::NonTerminal nt; | 276 | Parser::NonTerminal nt; |
@@ -230,7 +282,25 @@ int main( int argc, char *argv[] ) | |||
230 | ) | 282 | ) |
231 | ) | 283 | ) |
232 | ); | 284 | ); |
233 | p.setNonTerminal("expr'", nt ); | 285 | nt.addProduction( |
286 | Parser::Production( | ||
287 | Parser::State( | ||
288 | Parser::State::typeTerminal, | ||
289 | tokOpenParen | ||
290 | ) | ||
291 | ).append( | ||
292 | Parser::State( | ||
293 | Parser::State::typeNonTerminal, | ||
294 | p.getNonTerminalId("expr") | ||
295 | ) | ||
296 | ).append( | ||
297 | Parser::State( | ||
298 | Parser::State::typeTerminal, | ||
299 | tokCloseParen | ||
300 | ) | ||
301 | ) | ||
302 | ); | ||
303 | p.setNonTerminal("expr-sub1", nt ); | ||
234 | } | 304 | } |
235 | { | 305 | { |
236 | Parser::NonTerminal nt; | 306 | Parser::NonTerminal nt; |
@@ -238,12 +308,12 @@ int main( int argc, char *argv[] ) | |||
238 | Parser::Production( | 308 | Parser::Production( |
239 | Parser::State( | 309 | Parser::State( |
240 | Parser::State::typeNonTerminal, | 310 | Parser::State::typeNonTerminal, |
241 | p.getNonTerminalId("expr'") | 311 | p.getNonTerminalId("expr-sub1") |
242 | ) | 312 | ) |
243 | ).append( | 313 | ).append( |
244 | Parser::State( | 314 | Parser::State( |
245 | Parser::State::typeNonTerminal, | 315 | Parser::State::typeNonTerminal, |
246 | p.getNonTerminalId("expr''") | 316 | p.getNonTerminalId("expr-sub2") |
247 | ) | 317 | ) |
248 | ) | 318 | ) |
249 | ); | 319 | ); |
@@ -275,6 +345,7 @@ int main( int argc, char *argv[] ) | |||
275 | p.setRootNonTerminal("input"); | 345 | p.setRootNonTerminal("input"); |
276 | 346 | ||
277 | p.setReduction("add", Bu::slot( &redAdd ) ); | 347 | p.setReduction("add", Bu::slot( &redAdd ) ); |
348 | p.setReduction("subtract", Bu::slot( &redSubtract ) ); | ||
278 | p.setReduction("print", Bu::slot( &redPrint ) ); | 349 | p.setReduction("print", Bu::slot( &redPrint ) ); |
279 | 350 | ||
280 | p.pushLexer( new MathLexer( fIn ) ); | 351 | p.pushLexer( new MathLexer( fIn ) ); |
diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit index 00b6eed..c6d7414 100644 --- a/src/unit/fstring.unit +++ b/src/unit/fstring.unit | |||
@@ -339,4 +339,13 @@ suite FString | |||
339 | a = "This is a test."; | 339 | a = "This is a test."; |
340 | unitTest( a.replace("i", "ooo") == "Thooos ooos a test." ); | 340 | unitTest( a.replace("i", "ooo") == "Thooos ooos a test." ); |
341 | } | 341 | } |
342 | |||
343 | test coreDerefBug1 | ||
344 | { | ||
345 | Bu::FString a, b; | ||
346 | a = "bob"; | ||
347 | a.setSize( 0 ); | ||
348 | b = a; | ||
349 | b.getStr(); | ||
350 | } | ||
342 | } | 351 | } |
diff --git a/src/unit/hash.unit b/src/unit/hash.unit index e3d7e42..124b074 100644 --- a/src/unit/hash.unit +++ b/src/unit/hash.unit | |||
@@ -84,4 +84,17 @@ suite Hash | |||
84 | printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); | 84 | printf(" - \"%s\" = %d\n", i.getKey().getStr(), i.getValue() ); |
85 | } */ | 85 | } */ |
86 | } | 86 | } |
87 | |||
88 | test copy | ||
89 | { | ||
90 | StrIntHash h; | ||
91 | h.insert("hello", 55 ); | ||
92 | h.insert("goodbye", -1812 ); | ||
93 | |||
94 | StrIntHash h2 = h; | ||
95 | unitTest( h2.isCoreShared( h ) ); | ||
96 | |||
97 | StrIntHash h3 = h.clone(); | ||
98 | unitTest( !h3.isCoreShared( h ) ); | ||
99 | } | ||
87 | } | 100 | } |
diff --git a/src/utfstring.cpp b/src/utfstring.cpp new file mode 100644 index 0000000..ae5efaf --- /dev/null +++ b/src/utfstring.cpp | |||
@@ -0,0 +1,29 @@ | |||
1 | #include "bu/utfstring.h" | ||
2 | |||
3 | template class Bu::FBasicString<short>; | ||
4 | |||
5 | template<> uint32_t Bu::__calcHashCode<Bu::UtfString>( const Bu::UtfString &k ) | ||
6 | { | ||
7 | long j, sz = k.getSize()*2; | ||
8 | const char *s = (const char *)k.getStr(); | ||
9 | |||
10 | long nPos = 0; | ||
11 | for( j = 0; j < sz; j++, s++ ) | ||
12 | { | ||
13 | nPos = *s + (nPos << 6) + (nPos << 16) - nPos; | ||
14 | } | ||
15 | |||
16 | return nPos; | ||
17 | } | ||
18 | |||
19 | template<> bool Bu::__cmpHashKeys<Bu::UtfString>( | ||
20 | const Bu::UtfString &a, const Bu::UtfString &b ) | ||
21 | { | ||
22 | return a == b; | ||
23 | } | ||
24 | |||
25 | template<> void Bu::__tracer_format<Bu::UtfString>( const Bu::UtfString &v ) | ||
26 | { | ||
27 | printf("(%ld)\"%s\"", v.getSize(), (const char *)v.getStr() ); | ||
28 | } | ||
29 | |||
diff --git a/src/utfstring.h b/src/utfstring.h new file mode 100644 index 0000000..bbacb74 --- /dev/null +++ b/src/utfstring.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #ifndef BU_UTF_STRING_H | ||
2 | #define BU_UTF_STRING_H | ||
3 | |||
4 | #include "bu/fbasicstring.h" | ||
5 | |||
6 | namespace Bu | ||
7 | { | ||
8 | typedef FBasicString<short> UtfString; | ||
9 | |||
10 | template<typename T> | ||
11 | uint32_t __calcHashCode( const T &k ); | ||
12 | |||
13 | template<typename T> | ||
14 | bool __cmpHashKeys( const T &a, const T &b ); | ||
15 | |||
16 | template<> uint32_t __calcHashCode<UtfString>( const UtfString &k ); | ||
17 | template<> bool __cmpHashKeys<UtfString>( | ||
18 | const UtfString &a, const UtfString &b ); | ||
19 | |||
20 | template<typename t> void __tracer_format( const t &v ); | ||
21 | template<> void __tracer_format<UtfString>( const UtfString &v ); | ||
22 | } | ||
23 | |||
24 | #endif | ||
diff --git a/src/variant.h b/src/variant.h index 8e1203c..f659ad2 100644 --- a/src/variant.h +++ b/src/variant.h | |||
@@ -17,6 +17,7 @@ namespace Bu | |||
17 | { | 17 | { |
18 | class Formatter; | 18 | class Formatter; |
19 | class Variant; | 19 | class Variant; |
20 | /** @cond DEVEL */ | ||
20 | template<class t> class VariantType; | 21 | template<class t> class VariantType; |
21 | 22 | ||
22 | class VariantTypeRoot | 23 | class VariantTypeRoot |
@@ -92,7 +93,22 @@ namespace Bu | |||
92 | private: | 93 | private: |
93 | t data; | 94 | t data; |
94 | }; | 95 | }; |
95 | 96 | /** @endcond */ | |
97 | |||
98 | /** | ||
99 | * Store any data type and access it safely. Variant gives you a way to | ||
100 | * pass arbitrary data types around without having to worry about what | ||
101 | * type a variable is. It allows code to be easily extended and to manage | ||
102 | * data without having to know what type it is ahead of time. | ||
103 | * | ||
104 | * Because of the generic method that this class was implemented it may seem | ||
105 | * to have some drawbacks compared to other Variant classes you may have | ||
106 | * seen, however it is fairly easy to get it to do just about anything you | ||
107 | * may need. It is also very low overhead. On most compilers the class | ||
108 | * itself has only 3 words of overhead + the size of the variable you store | ||
109 | * in it. And, since many parts of it are templatized they can often be | ||
110 | * optimized quite a bit. | ||
111 | */ | ||
96 | class Variant | 112 | class Variant |
97 | { | 113 | { |
98 | public: | 114 | public: |