summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/archival.cpp10
-rw-r--r--src/archival.h38
-rw-r--r--src/archive.cpp386
-rw-r--r--src/archive.h212
-rw-r--r--src/arraylist.cpp100
-rw-r--r--src/arraylist.h80
-rw-r--r--src/atom.cpp1
-rw-r--r--src/atom.h107
-rw-r--r--src/bzip2.cpp196
-rw-r--r--src/bzip2.h37
-rw-r--r--src/client.cpp206
-rw-r--r--src/client.h63
-rw-r--r--src/entities/bu-class48
-rw-r--r--src/exceptionbase.cpp16
-rw-r--r--src/exceptionbase.h127
-rw-r--r--src/exceptions.cpp15
-rw-r--r--src/exceptions.h43
-rw-r--r--src/file.cpp158
-rw-r--r--src/file.h78
-rw-r--r--src/filter.cpp97
-rw-r--r--src/filter.h65
-rw-r--r--src/fstring.cpp11
-rw-r--r--src/fstring.h1304
-rw-r--r--src/hash.cpp34
-rw-r--r--src/hash.h1488
-rw-r--r--src/hashable.cpp1
-rw-r--r--src/hashable.h12
-rw-r--r--src/hashfunction.cpp10
-rw-r--r--src/hashfunction.h48
-rw-r--r--src/hashfunctioncasestring.cpp39
-rw-r--r--src/hashfunctioncasestring.h28
-rw-r--r--src/hashfunctionint.cpp20
-rw-r--r--src/hashfunctionint.h26
-rw-r--r--src/hashfunctionstring.cpp51
-rw-r--r--src/hashfunctionstring.h27
-rw-r--r--src/hashtable.cpp424
-rw-r--r--src/hashtable.h308
-rw-r--r--src/inprogress/xmldocument.cpp9
-rw-r--r--src/inprogress/xmldocument.h22
-rw-r--r--src/inprogress/xmlnode.cpp9
-rw-r--r--src/inprogress/xmlnode.h22
-rw-r--r--src/inprogress/xmlreader.cpp267
-rw-r--r--src/inprogress/xmlreader.h121
-rw-r--r--src/inprogress/xmlwriter.cpp9
-rw-r--r--src/inprogress/xmlwriter.h22
-rw-r--r--src/ito.cpp40
-rw-r--r--src/ito.h98
-rw-r--r--src/itoatom.h56
-rw-r--r--src/itocondition.cpp42
-rw-r--r--src/itocondition.h81
-rw-r--r--src/itomutex.cpp27
-rw-r--r--src/itomutex.h61
-rw-r--r--src/itoqueue.h231
-rw-r--r--src/linkmessage.cpp7
-rw-r--r--src/linkmessage.h59
-rw-r--r--src/list.cpp10
-rw-r--r--src/list.h574
-rw-r--r--src/logger.cpp131
-rw-r--r--src/logger.h112
-rw-r--r--src/main.dox14
-rw-r--r--src/membuf.cpp120
-rw-r--r--src/membuf.h53
-rw-r--r--src/old/cgi.cpp (renamed from src/cgi.cpp)0
-rw-r--r--src/old/cgi.h (renamed from src/cgi.h)0
-rw-r--r--src/old/configmanagerbase.cpp (renamed from src/configmanagerbase.cpp)0
-rw-r--r--src/old/configmanagerbase.h (renamed from src/configmanagerbase.h)0
-rw-r--r--src/old/confpair.cpp (renamed from src/confpair.cpp)0
-rw-r--r--src/old/confpair.h (renamed from src/confpair.h)0
-rw-r--r--src/old/confpairbase.cpp (renamed from src/confpairbase.cpp)0
-rw-r--r--src/old/confpairbase.h (renamed from src/confpairbase.h)0
-rw-r--r--src/old/conftree.cpp (renamed from src/conftree.cpp)0
-rw-r--r--src/old/conftree.h (renamed from src/conftree.h)0
-rw-r--r--src/old/connection.cpp (renamed from src/connection.cpp)0
-rw-r--r--src/old/connection.h (renamed from src/connection.h)0
-rw-r--r--src/old/connectionmanager.cpp (renamed from src/connectionmanager.cpp)0
-rw-r--r--src/old/connectionmanager.h (renamed from src/connectionmanager.h)0
-rw-r--r--src/old/connectionmonitor.cpp (renamed from src/connectionmonitor.cpp)0
-rw-r--r--src/old/connectionmonitor.h (renamed from src/connectionmonitor.h)0
-rw-r--r--src/old/flexbuf.cpp (renamed from src/flexbuf.cpp)0
-rw-r--r--src/old/flexbuf.h (renamed from src/flexbuf.h)0
-rw-r--r--src/old/formula.cpp (renamed from src/formula.cpp)0
-rw-r--r--src/old/formula.h (renamed from src/formula.h)0
-rw-r--r--src/old/http.cpp (renamed from src/http.cpp)0
-rw-r--r--src/old/http.h (renamed from src/http.h)0
-rw-r--r--src/old/httpget.cpp (renamed from src/httpget.cpp)0
-rw-r--r--src/old/httpget.h (renamed from src/httpget.h)0
-rw-r--r--src/old/linkedlist.cpp (renamed from src/linkedlist.cpp)0
-rw-r--r--src/old/linkedlist.h (renamed from src/linkedlist.h)0
-rw-r--r--src/old/linkmessenger.cpp (renamed from src/linkmessenger.cpp)0
-rw-r--r--src/old/linkmessenger.h (renamed from src/linkmessenger.h)0
-rw-r--r--src/old/list.cpp10
-rw-r--r--src/old/list.h101
-rw-r--r--src/old/md5.cpp (renamed from src/md5.cpp)0
-rw-r--r--src/old/md5.h (renamed from src/md5.h)0
-rw-r--r--src/old/multilog.cpp (renamed from src/multilog.cpp)0
-rw-r--r--src/old/multilog.h (renamed from src/multilog.h)0
-rw-r--r--src/old/multilogchannel.cpp (renamed from src/multilogchannel.cpp)0
-rw-r--r--src/old/multilogchannel.h (renamed from src/multilogchannel.h)0
-rw-r--r--src/old/multilogtext.cpp (renamed from src/multilogtext.cpp)0
-rw-r--r--src/old/multilogtext.h (renamed from src/multilogtext.h)0
-rw-r--r--src/old/ordhash.cpp (renamed from src/ordhash.cpp)0
-rw-r--r--src/old/ordhash.h (renamed from src/ordhash.h)0
-rw-r--r--src/old/pqueue.cpp (renamed from src/pqueue.cpp)0
-rw-r--r--src/old/pqueue.h (renamed from src/pqueue.h)0
-rw-r--r--src/old/protocol.cpp20
-rw-r--r--src/old/protocol.h62
-rw-r--r--src/old/protocoltelnet.cpp (renamed from src/protocoltelnet.cpp)0
-rw-r--r--src/old/protocoltelnet.h (renamed from src/protocoltelnet.h)0
-rw-r--r--src/old/queue.cpp (renamed from src/queue.cpp)0
-rw-r--r--src/old/queue.h (renamed from src/queue.h)0
-rw-r--r--src/old/ringlist.cpp (renamed from src/ringlist.cpp)0
-rw-r--r--src/old/ringlist.h (renamed from src/ringlist.h)0
-rw-r--r--src/old/sbuffer.cpp (renamed from src/sbuffer.cpp)0
-rw-r--r--src/old/sbuffer.h (renamed from src/sbuffer.h)0
-rw-r--r--src/old/serializerbinary.cpp (renamed from src/serializerbinary.cpp)0
-rw-r--r--src/old/serializerbinary.h (renamed from src/serializerbinary.h)0
-rw-r--r--src/old/serializerbzip2.cpp (renamed from src/serializerbzip2.cpp)0
-rw-r--r--src/old/serializerbzip2.h (renamed from src/serializerbzip2.h)0
-rw-r--r--src/old/serializerconnection.cpp (renamed from src/serializerconnection.cpp)0
-rw-r--r--src/old/serializerconnection.h (renamed from src/serializerconnection.h)0
-rw-r--r--src/old/serializertext.cpp (renamed from src/serializertext.cpp)0
-rw-r--r--src/old/serializertext.h (renamed from src/serializertext.h)0
-rw-r--r--src/old/sha1.cpp (renamed from src/sha1.cpp)0
-rw-r--r--src/old/sha1.h (renamed from src/sha1.h)0
-rw-r--r--src/old/stack.cpp (renamed from src/stack.cpp)0
-rw-r--r--src/old/stack.h (renamed from src/stack.h)0
-rw-r--r--src/old/staticstring.cpp (renamed from src/staticstring.cpp)0
-rw-r--r--src/old/staticstring.h (renamed from src/staticstring.h)0
-rw-r--r--src/old/stringrep.cpp (renamed from src/stringrep.cpp)0
-rw-r--r--src/old/stringrep.h (renamed from src/stringrep.h)0
-rw-r--r--src/old/tests/clistress.cpp (renamed from src/tests/clistress.cpp)0
-rw-r--r--src/old/tests/confpair.cpp (renamed from src/tests/confpair.cpp)0
-rw-r--r--src/old/tests/connect.cpp (renamed from src/tests/connect.cpp)0
-rw-r--r--src/old/tests/exception.cpp (renamed from src/tests/exception.cpp)0
-rw-r--r--src/old/tests/formula.cpp (renamed from src/tests/formula.cpp)0
-rw-r--r--src/old/tests/hash.cpp116
-rw-r--r--src/old/tests/hashtest.cpp (renamed from src/tests/hashtest.cpp)0
-rw-r--r--src/old/tests/hashtest2.cpp (renamed from src/tests/hashtest2.cpp)0
-rw-r--r--src/old/tests/httpsrv/httpconnectionmonitor.cpp (renamed from src/tests/httpsrv/httpconnectionmonitor.cpp)0
-rw-r--r--src/old/tests/httpsrv/httpconnectionmonitor.h (renamed from src/tests/httpsrv/httpconnectionmonitor.h)0
-rw-r--r--src/old/tests/httpsrv/main.cpp (renamed from src/tests/httpsrv/main.cpp)0
-rw-r--r--src/old/tests/log.cpp (renamed from src/tests/log.cpp)0
-rw-r--r--src/old/tests/md5test.cpp (renamed from src/tests/md5test.cpp)0
-rw-r--r--src/old/tests/ordhash.cpp (renamed from src/tests/ordhash.cpp)0
-rw-r--r--src/old/tests/param.cpp (renamed from src/tests/param.cpp)0
-rw-r--r--src/old/tests/param.h (renamed from src/tests/param.h)0
-rw-r--r--src/old/tests/plugin/main.cpp (renamed from src/tests/plugin/main.cpp)0
-rw-r--r--src/old/tests/plugin/plugin.cpp (renamed from src/tests/plugin/plugin.cpp)0
-rw-r--r--src/old/tests/plugin/plugin.h (renamed from src/tests/plugin/plugin.h)0
-rw-r--r--src/old/tests/qsort.cpp (renamed from src/tests/qsort.cpp)0
-rw-r--r--src/old/tests/sbuffer.cpp (renamed from src/tests/sbuffer.cpp)0
-rw-r--r--src/old/tests/serialize.cpp (renamed from src/tests/serialize.cpp)0
-rw-r--r--src/old/tests/serializetext.cpp (renamed from src/tests/serializetext.cpp)0
-rw-r--r--src/old/tests/sha1.cpp (renamed from src/tests/sha1.cpp)0
-rw-r--r--src/old/tests/sptr.cpp (renamed from src/tests/sptr.cpp)30
-rw-r--r--src/old/tests/srvstress.cpp (renamed from src/tests/srvstress.cpp)0
-rw-r--r--src/old/tests/strhash.cpp (renamed from src/tests/strhash.cpp)0
-rw-r--r--src/old/tests/teltest/main.cpp (renamed from src/tests/teltest/main.cpp)0
-rw-r--r--src/old/tests/teltest/telnetmonitor.cpp (renamed from src/tests/teltest/telnetmonitor.cpp)0
-rw-r--r--src/old/tests/teltest/telnetmonitor.h (renamed from src/tests/teltest/telnetmonitor.h)0
-rw-r--r--src/old/tests/xmlreadtest.cpp (renamed from src/tests/xmlreadtest.cpp)0
-rw-r--r--src/old/tests/xmlrepltest.cpp (renamed from src/tests/xmlrepltest.cpp)0
-rw-r--r--src/old/tests/xmlwritetest.cpp (renamed from src/tests/xmlwritetest.cpp)0
-rw-r--r--src/old/tokenstring.cpp (renamed from src/tokenstring.cpp)0
-rw-r--r--src/old/tokenstring.h (renamed from src/tokenstring.h)0
-rw-r--r--src/old/tqsort.h (renamed from src/tqsort.h)0
-rw-r--r--src/old/unit/hashtable/hashtable.cpp (renamed from src/unit/hashtable/hashtable.cpp)0
-rw-r--r--src/old/unit/xml/xml.cpp (renamed from src/unit/xml/xml.cpp)0
-rw-r--r--src/old/xmldocument.cpp (renamed from src/xmldocument.cpp)20
-rw-r--r--src/old/xmldocument.h (renamed from src/xmldocument.h)8
-rw-r--r--src/old/xmlfilereader.cpp (renamed from src/xmlfilereader.cpp)0
-rw-r--r--src/old/xmlfilereader.h (renamed from src/xmlfilereader.h)0
-rw-r--r--src/old/xmlfilewriter.cpp (renamed from src/xmlfilewriter.cpp)0
-rw-r--r--src/old/xmlfilewriter.h (renamed from src/xmlfilewriter.h)0
-rw-r--r--src/old/xmlnode.cpp (renamed from src/xmlnode.cpp)106
-rw-r--r--src/old/xmlnode.h (renamed from src/xmlnode.h)101
-rw-r--r--src/old/xmlreader.cpp (renamed from src/xmlreader.cpp)170
-rw-r--r--src/old/xmlreader.h (renamed from src/xmlreader.h)31
-rw-r--r--src/old/xmlstringreader.cpp (renamed from src/xmlstringreader.cpp)0
-rw-r--r--src/old/xmlstringreader.h (renamed from src/xmlstringreader.h)0
-rw-r--r--src/old/xmlstringwriter.cpp (renamed from src/xmlstringwriter.cpp)0
-rw-r--r--src/old/xmlstringwriter.h (renamed from src/xmlstringwriter.h)0
-rw-r--r--src/old/xmlwriter.cpp (renamed from src/xmlwriter.cpp)62
-rw-r--r--src/old/xmlwriter.h (renamed from src/xmlwriter.h)16
-rw-r--r--src/paramproc.cpp98
-rw-r--r--src/paramproc.h265
-rw-r--r--src/plugger.h316
-rw-r--r--src/programchain.cpp49
-rw-r--r--src/programchain.h163
-rw-r--r--src/programlink.cpp14
-rw-r--r--src/programlink.h165
-rw-r--r--src/protocol.cpp16
-rw-r--r--src/protocol.h67
-rw-r--r--src/ringbuffer.cpp2
-rw-r--r--src/ringbuffer.h97
-rw-r--r--src/serializable.cpp8
-rw-r--r--src/serializable.h34
-rw-r--r--src/serializer.cpp338
-rw-r--r--src/serializer.h80
-rw-r--r--src/server.cpp96
-rw-r--r--src/server.h61
-rw-r--r--src/serversocket.cpp158
-rw-r--r--src/serversocket.h39
-rw-r--r--src/sfile.cpp74
-rw-r--r--src/sfile.h29
-rw-r--r--src/singleton.h101
-rw-r--r--src/socket.cpp294
-rw-r--r--src/socket.h55
-rw-r--r--src/sptr.cpp2
-rw-r--r--src/sptr.h272
-rw-r--r--src/stream.cpp4
-rw-r--r--src/stream.h148
-rw-r--r--src/tafnode.cpp165
-rw-r--r--src/tafnode.h94
-rw-r--r--src/tafreader.cpp155
-rw-r--r--src/tafreader.h35
-rw-r--r--src/tafwriter.cpp70
-rw-r--r--src/tafwriter.h30
-rw-r--r--src/tests/archive.cpp16
-rw-r--r--src/tests/atom.cpp25
-rw-r--r--src/tests/bzip2.cpp23
-rw-r--r--src/tests/constsptr.cpp94
-rw-r--r--src/tests/constsptr2.cpp30
-rw-r--r--src/tests/fstring.cpp108
-rw-r--r--src/tests/hash.cpp120
-rw-r--r--src/tests/itoqueue1.cpp110
-rw-r--r--src/tests/itoqueue2.cpp83
-rw-r--r--src/tests/list.cpp53
-rw-r--r--src/tests/logger.cpp28
-rw-r--r--src/tests/ringbuffer.cpp29
-rw-r--r--src/tests/taf.cpp24
-rw-r--r--src/unit/entities/unit30
-rw-r--r--src/unit/file.cpp111
-rw-r--r--src/unit/fstring.cpp28
-rw-r--r--src/unit/hash.cpp40
-rw-r--r--src/unit/membuf.cpp37
-rw-r--r--src/unit/taf.cpp48
-rw-r--r--src/unitsuite.cpp67
-rw-r--r--src/unitsuite.h96
239 files changed, 9329 insertions, 4429 deletions
diff --git a/src/archival.cpp b/src/archival.cpp
new file mode 100644
index 0000000..79c28f1
--- /dev/null
+++ b/src/archival.cpp
@@ -0,0 +1,10 @@
1#include "archival.h"
2
3Bu::Archival::Archival()
4{
5}
6
7Bu::Archival::~Archival()
8{
9}
10
diff --git a/src/archival.h b/src/archival.h
new file mode 100644
index 0000000..8be3308
--- /dev/null
+++ b/src/archival.h
@@ -0,0 +1,38 @@
1#ifndef BU_ARCHIVAL_H
2#define BU_ARCHIVAL_H
3
4namespace Bu
5{
6 /**
7 * The base class for any class you want to archive. Simply include this as
8 * a base class, implement the purely virtual archive function and you've
9 * got an easily archiveable class.
10 *
11 * Archival: "of or pertaining to archives or valuable records; contained
12 * in or comprising such archives or records."
13 */
14 class Archival
15 {
16 public:
17 /**
18 * Does nothing, here for completeness.
19 */
20 Archival();
21
22 /**
23 * Here to ensure the deconstructor is virtual.
24 */
25 virtual ~Archival();
26
27 /**
28 * This is the main workhorse of the archive system, just override and
29 * you've got a archiveable class. A reference to the Archive
30 * used is passed in as your only parameter, query it to discover if
31 * you are loading or saving.
32 * @param ar A reference to the Archive object to use.
33 */
34 virtual void archive( class Archive &ar )=0;
35 };
36}
37
38#endif
diff --git a/src/archive.cpp b/src/archive.cpp
new file mode 100644
index 0000000..7208bae
--- /dev/null
+++ b/src/archive.cpp
@@ -0,0 +1,386 @@
1#include "archive.h"
2
3Bu::Archive::Archive( Stream &rStream, bool bLoading ) :
4 bLoading( bLoading ),
5 rStream( rStream ),
6 nNextID( 1 )
7{
8}
9
10Bu::Archive::~Archive()
11{
12}
13
14void Bu::Archive::write( const void *pData, int32_t nSize )
15{
16 if( nSize == 0 || pData == NULL )
17 return;
18
19 rStream.write( (const char *)pData, nSize );
20}
21
22void Bu::Archive::read( void *pData, int32_t nSize )
23{
24 if( nSize == 0 || pData == NULL )
25 return;
26
27 rStream.read( (char *)pData, nSize );
28}
29
30void Bu::Archive::close()
31{
32 rStream.close();
33}
34
35bool Bu::Archive::isLoading()
36{
37 return bLoading;
38}
39Bu::Archive &Bu::Archive::operator<<(bool p)
40{
41 write( &p, sizeof(p) );
42 return *this;
43}
44Bu::Archive &Bu::Archive::operator<<(int8_t p)
45{
46 write( &p, sizeof(p) );
47 return *this;
48}
49Bu::Archive &Bu::Archive::operator<<(int16_t p)
50{
51 write( &p, sizeof(p) );
52 return *this;
53}
54Bu::Archive &Bu::Archive::operator<<(int32_t p)
55{
56 write( &p, sizeof(p) );
57 return *this;
58}
59Bu::Archive &Bu::Archive::operator<<(int64_t p)
60{
61 write( &p, sizeof(p) );
62 return *this;
63}
64Bu::Archive &Bu::Archive::operator<<(uint8_t p)
65{
66 write( &p, sizeof(p) );
67 return *this;
68}
69Bu::Archive &Bu::Archive::operator<<(uint16_t p)
70{
71 write( &p, sizeof(p) );
72 return *this;
73}
74Bu::Archive &Bu::Archive::operator<<(uint32_t p)
75{
76 write( &p, sizeof(p) );
77 return *this;
78}
79Bu::Archive &Bu::Archive::operator<<(uint64_t p)
80{
81 write( &p, sizeof(p) );
82 return *this;
83}
84Bu::Archive &Bu::Archive::operator<<(long p)
85{
86 write( &p, sizeof(p) );
87 return *this;
88}
89Bu::Archive &Bu::Archive::operator<<(float p)
90{
91 write( &p, sizeof(p) );
92 return *this;
93}
94Bu::Archive &Bu::Archive::operator<<(double p)
95{
96 write( &p, sizeof(p) );
97 return *this;
98}
99Bu::Archive &Bu::Archive::operator<<(long double p)
100{
101 write( &p, sizeof(p) );
102 return *this;
103}
104
105Bu::Archive &Bu::Archive::operator>>(bool &p)
106{
107 read( &p, sizeof(p) );
108 return *this;
109}
110Bu::Archive &Bu::Archive::operator>>(int8_t &p)
111{
112 read( &p, sizeof(p) );
113 return *this;
114}
115Bu::Archive &Bu::Archive::operator>>(int16_t &p)
116{
117 read( &p, sizeof(p) );
118 return *this;
119}
120Bu::Archive &Bu::Archive::operator>>(int32_t &p)
121{
122 read( &p, sizeof(p) );
123 return *this;
124}
125Bu::Archive &Bu::Archive::operator>>(int64_t &p)
126{
127 read( &p, sizeof(p) );
128 return *this;
129}
130Bu::Archive &Bu::Archive::operator>>(uint8_t &p)
131{
132 read( &p, sizeof(p) );
133 return *this;
134}
135Bu::Archive &Bu::Archive::operator>>(uint16_t &p)
136{
137 read( &p, sizeof(p) );
138 return *this;
139}
140Bu::Archive &Bu::Archive::operator>>(uint32_t &p)
141{
142 read( &p, sizeof(p) );
143 return *this;
144}
145Bu::Archive &Bu::Archive::operator>>(uint64_t &p)
146{
147 read( &p, sizeof(p) );
148 return *this;
149}
150Bu::Archive &Bu::Archive::operator>>(long &p)
151{
152 read( &p, sizeof(p) );
153 return *this;
154}
155Bu::Archive &Bu::Archive::operator>>(float &p)
156{
157 read( &p, sizeof(p) );
158 return *this;
159}
160Bu::Archive &Bu::Archive::operator>>(double &p)
161{
162 read( &p, sizeof(p) );
163 return *this;
164}
165Bu::Archive &Bu::Archive::operator>>(long double &p)
166{
167 read( &p, sizeof(p) );
168 return *this;
169}
170
171Bu::Archive &Bu::Archive::operator&&(bool &p)
172{
173 if (bLoading)
174 {
175 return *this >> p;
176 }
177 else
178 {
179 return *this << p;
180 }
181}
182
183Bu::Archive &Bu::Archive::operator&&(int8_t &p)
184{
185 if (bLoading)
186 {
187 return *this >> p;
188 }
189 else
190 {
191 return *this << p;
192 }
193}
194
195Bu::Archive &Bu::Archive::operator&&(int16_t &p)
196{
197 if (bLoading)
198 {
199 return *this >> p;
200 }
201 else
202 {
203 return *this << p;
204 }
205}
206
207Bu::Archive &Bu::Archive::operator&&(int32_t &p)
208{
209 if (bLoading)
210 {
211 return *this >> p;
212 }
213 else
214 {
215 return *this << p;
216 }
217}
218
219Bu::Archive &Bu::Archive::operator&&(int64_t &p)
220{
221 if (bLoading)
222 {
223 return *this >> p;
224 }
225 else
226 {
227 return *this << p;
228 }
229}
230
231Bu::Archive &Bu::Archive::operator&&(uint8_t &p)
232{
233 if (bLoading)
234 {
235 return *this >> p;
236 }
237 else
238 {
239 return *this << p;
240 }
241}
242
243Bu::Archive &Bu::Archive::operator&&(uint16_t &p)
244{
245 if (bLoading)
246 {
247 return *this >> p;
248 }
249 else
250 {
251 return *this << p;
252 }
253}
254
255Bu::Archive &Bu::Archive::operator&&(uint32_t &p)
256{
257 if (bLoading)
258 {
259 return *this >> p;
260 }
261 else
262 {
263 return *this << p;
264 }
265}
266
267Bu::Archive &Bu::Archive::operator&&(uint64_t &p)
268{
269 if (bLoading)
270 {
271 return *this >> p;
272 }
273 else
274 {
275 return *this << p;
276 }
277}
278
279Bu::Archive &Bu::Archive::operator&&(float &p)
280{
281 if (bLoading)
282 {
283 return *this >> p;
284 }
285 else
286 {
287 return *this << p;
288 }
289}
290
291Bu::Archive &Bu::Archive::operator&&(double &p)
292{
293 if (bLoading)
294 {
295 return *this >> p;
296 }
297 else
298 {
299 return *this << p;
300 }
301}
302
303Bu::Archive &Bu::Archive::operator&&(long double &p)
304{
305 if (bLoading)
306 {
307 return *this >> p;
308 }
309 else
310 {
311 return *this << p;
312 }
313}
314
315
316Bu::Archive &Bu::operator<<(Bu::Archive &s, Bu::Archival &p)
317{
318 p.archive( s );
319 return s;
320}
321
322Bu::Archive &Bu::operator>>(Bu::Archive &s, Bu::Archival &p)
323{
324 p.archive( s );
325 return s;
326}
327
328Bu::Archive &Bu::operator<<( Bu::Archive &ar, std::string &s )
329{
330 ar << (uint32_t)s.length();
331 ar.write( s.c_str(), s.length() );
332
333 return ar;
334}
335
336Bu::Archive &Bu::operator>>( Bu::Archive &ar, std::string &s )
337{
338 uint32_t l;
339 ar >> l;
340 char *tmp = new char[l+1];
341 tmp[l] = '\0';
342 ar.read( tmp, l );
343 s = tmp;
344 delete[] tmp;
345
346 return ar;
347}
348
349uint32_t Bu::Archive::getID( const void *ptr )
350{
351 if( hPtrID.has( (int)ptr ) )
352 return hPtrID.get( (int)ptr );
353 hPtrID.insert( (int)ptr, nNextID );
354 return nNextID++;
355}
356
357void Bu::Archive::assocPtrID( void **ptr, uint32_t id )
358{
359 if( hPtrID.has( id ) )
360 {
361 *ptr = (void *)hPtrID.get( id );
362 return;
363 }
364
365 if( !hPtrDest.has( id ) )
366 hPtrDest.insert( id, List<void **>() );
367
368 hPtrDest[id].value().append( ptr );
369}
370
371void Bu::Archive::readID( const void *ptr, uint32_t id )
372{
373 hPtrID.insert( id, (int)ptr );
374
375 if( hPtrDest.has( id ) )
376 {
377 Bu::List<void **> &l = hPtrDest.get( id );
378 for( Bu::List<void **>::iterator i = l.begin(); i != l.end(); i++ )
379 {
380 *(*i) = (void *)ptr;
381 }
382
383 hPtrDest.erase( id );
384 }
385}
386
diff --git a/src/archive.h b/src/archive.h
new file mode 100644
index 0000000..a2d4c8f
--- /dev/null
+++ b/src/archive.h
@@ -0,0 +1,212 @@
1#ifndef BU_ARCHIVE_H
2#define BU_ARCHIVE_H
3
4#include <stdint.h>
5#include <string>
6#include "bu/archival.h"
7#include "bu/stream.h"
8#include <list>
9#include "bu/hash.h"
10#include "bu/list.h"
11
12namespace Bu
13{
14 /**
15 * Provides a framework for serialization of objects and primitives. The
16 * archive will handle any basic primitive, a few special types, like char *
17 * strings, as well as STL classes and anything that inherits from the
18 * Archival class. Each Archive operates on a Stream, so you can send the
19 * data using an Archive almost anywhere.
20 *
21 * In order to use an Archive to store something to a file, try something
22 * like:
23 *@code
24 * File sOut("output", "wb"); // This is a stream subclass
25 * Archive ar( sOut, Archive::save );
26 * ar << myClass;
27 @endcode
28 * In this example myClass is any class that inherits from Archival. When
29 * the storage operator is called, the Archival::archive() function in the
30 * myClass object is called with a reference to the Archive. This can be
31 * handled in one of two ways:
32 *@code
33 * void MyClass::archive( Archive &ar )
34 * {
35 * ar && sName && nAge && sJob;
36 * }
37 @endcode
38 * Here we don't worry about weather we're loading or saving by using the
39 * smart && operator. This allows us to write very consistent, very simple
40 * archive functions that really do a lot of work. If we wanted to do
41 * something different in the case of loading or saving we would do:
42 *@code
43 * void MyClass::archive( Archive &ar )
44 * {
45 * if( ar.isLoading() )
46 * {
47 * ar >> sName >> nAge >> sJob;
48 * } else
49 * {
50 * ar << sName << nAge << sJob;
51 * }
52 * }
53 @endcode
54 * Archive currently does not provide facility to make fully portable
55 * archives. For example, it will not convert between endianness for you,
56 * nor will it take into account differences between primitive sizes on
57 * different platforms. This, at the moment, is up to the user to ensure.
58 * One way of dealing with the latter problem is to make sure and use
59 * explicit primitive types from the stdint.h header, i.e. int32_t.
60 */
61 class Archive
62 {
63 private:
64 bool bLoading;
65 public:
66 bool isLoading();
67
68 enum
69 {
70 load = true,
71 save = false
72 };
73
74 Archive( Stream &rStream, bool bLoading );
75 virtual ~Archive();
76 virtual void close();
77
78 virtual void write(const void *, int32_t);
79 virtual void read(void *, int32_t);
80
81 virtual Archive &operator<<(bool);
82 virtual Archive &operator<<(int8_t);
83 virtual Archive &operator<<(int16_t);
84 virtual Archive &operator<<(int32_t);
85 virtual Archive &operator<<(int64_t);
86 virtual Archive &operator<<(uint8_t);
87 virtual Archive &operator<<(uint16_t);
88 virtual Archive &operator<<(uint32_t);
89 virtual Archive &operator<<(uint64_t);
90 virtual Archive &operator<<(long);
91 virtual Archive &operator<<(float);
92 virtual Archive &operator<<(double);
93 virtual Archive &operator<<(long double);
94
95 virtual Archive &operator>>(bool &);
96 virtual Archive &operator>>(int8_t &);
97 virtual Archive &operator>>(int16_t &);
98 virtual Archive &operator>>(int32_t &);
99 virtual Archive &operator>>(int64_t &);
100 virtual Archive &operator>>(uint8_t &);
101 virtual Archive &operator>>(uint16_t &);
102 virtual Archive &operator>>(uint32_t &);
103 virtual Archive &operator>>(uint64_t &);
104 virtual Archive &operator>>(long &);
105 virtual Archive &operator>>(float &);
106 virtual Archive &operator>>(double &);
107 virtual Archive &operator>>(long double &);
108
109 virtual Archive &operator&&(bool &);
110 virtual Archive &operator&&(int8_t &);
111 virtual Archive &operator&&(int16_t &);
112 virtual Archive &operator&&(int32_t &);
113 virtual Archive &operator&&(int64_t &);
114 virtual Archive &operator&&(uint8_t &);
115 virtual Archive &operator&&(uint16_t &);
116 virtual Archive &operator&&(uint32_t &);
117 virtual Archive &operator&&(uint64_t &);
118 virtual Archive &operator&&(float &);
119 virtual Archive &operator&&(double &);
120 virtual Archive &operator&&(long double &);
121
122 uint32_t getID( const void *ptr );
123 void assocPtrID( void **ptr, uint32_t id );
124 void readID( const void *ptr, uint32_t id );
125
126 private:
127 Stream &rStream;
128 uint32_t nNextID;
129 Hash<uint32_t,uint32_t> hPtrID;
130 Hash<uint32_t,List<void **> > hPtrDest;
131 };
132
133 Archive &operator<<(Archive &, class Bu::Archival &);
134 Archive &operator>>(Archive &, class Bu::Archival &);
135 //Archive &operator&&(Archive &s, class Bu::Archival &p);
136
137 Archive &operator<<(Archive &, std::string &);
138 Archive &operator>>(Archive &, std::string &);
139 //Archive &operator&&(Archive &, std::string &);
140
141 template<typename T> Archive &operator&&( Archive &ar, T &dat )
142 {
143 if( ar.isLoading() )
144 {
145 return ar >> dat;
146 }
147 else
148 {
149 return ar << dat;
150 }
151 }
152
153 template<typename T> Archive &operator<<( Archive &ar, std::list<T> &l )
154 {
155 typename std::list<T>::size_type num = l.size();
156 ar << num;
157 for( typename std::list<T>::const_iterator i = l.begin(); i != l.end();
158 i++ )
159 {
160 ar << *i;
161 }
162
163 return ar;
164 }
165
166 template<typename T> Archive &operator>>( Archive &ar, std::list<T> &l )
167 {
168 typename std::list<T>::size_type num;
169 ar >> num;
170
171 l.resize( num );
172 for( typename std::list<T>::const_iterator i = l.begin();
173 i != l.end(); i++ )
174 {
175 ar >> *i;
176 }
177
178 return ar;
179 }
180
181 template<typename key, typename value>
182 Archive &operator<<( Archive &ar, Hash<key,value> &h )
183 {
184 ar << h.size();
185 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
186 {
187 //std::pair<key,value> p = *i;
188 ar << (i.getKey()) << (i.getValue());
189 }
190
191 return ar;
192 }
193
194 template<typename key, typename value>
195 Archive &operator>>( Archive &ar, Hash<key,value> &h )
196 {
197 h.clear();
198 uint32_t nSize;
199 ar >> nSize;
200
201 for( uint32_t j = 0; j < nSize; j++ )
202 {
203 key k; value v;
204 ar >> k >> v;
205 h.insert( k, v );
206 }
207
208 return ar;
209 }
210}
211
212#endif
diff --git a/src/arraylist.cpp b/src/arraylist.cpp
deleted file mode 100644
index ef21426..0000000
--- a/src/arraylist.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
1#include "arraylist.h"
2#include <stdlib.h>
3#include <string.h>
4
5ArrayList::ArrayList( int initSize, int growByFactor )
6{
7 apData = new void *[initSize];
8 nSize = 0;
9 nCapacity = initSize;
10 nGrowByFactor = growByFactor;
11}
12
13ArrayList::~ArrayList( )
14{
15 delete[] apData;
16}
17
18void *ArrayList::getAt( int index )
19{
20 if( index < 0 || index > nSize )
21 return NULL;
22
23 return apData[index];
24}
25
26void ArrayList::append( void *data )
27{
28 insertBefore( data, nSize );
29}
30
31void ArrayList::insertBefore( void *data, int pos )
32{
33 if( pos < 0 || pos > nSize )
34 return;
35
36 checkResize();
37 memmove( &apData[pos+1], &apData[pos], (nSize-pos)*sizeof(void*) );
38 apData[pos] = data;
39 nSize++;
40}
41
42int ArrayList::getSize( )
43{
44 return nSize;
45}
46
47bool ArrayList::isEmpty( )
48{
49 return nSize==0;
50}
51
52void ArrayList::deleteAt( int index )
53{
54 if( index < 0 || index >= nSize )
55 return;
56
57 memmove( &apData[index], &apData[index+1], (nSize-index-1)*sizeof(void *) );
58 nSize--;
59}
60
61void ArrayList::empty()
62{
63 // Probably the easiest as far as things go.
64 nSize = 0;
65}
66
67void ArrayList::resizeTo( int newSize )
68{
69 void **apNew = new void *[newSize];
70 memmove( apNew, apData, nSize*sizeof(void *) );
71 nCapacity = newSize;
72 delete[] apData;
73 apData = apNew;
74}
75
76void ArrayList::checkResize()
77{
78 if( nSize >= nCapacity )
79 {
80 resizeTo( nCapacity + nGrowByFactor );
81 }
82}
83
84void ArrayList::setSize( int newSize )
85{
86 if( newSize < 0 )
87 return;
88
89 nSize = newSize;
90 checkResize();
91}
92
93void ArrayList::setAt( int index, void *data )
94{
95 if( index < 0 || index >= nSize )
96 return;
97
98 apData[index] = data;
99}
100
diff --git a/src/arraylist.h b/src/arraylist.h
deleted file mode 100644
index 0fda34a..0000000
--- a/src/arraylist.h
+++ /dev/null
@@ -1,80 +0,0 @@
1/** \file arraylist.h
2 * Describes the ArrayList class.
3 *@author Mike Buland
4 */
5#ifndef ARRAY_LIST_H
6#define ARRAY_LIST_H
7
8#include "list.h"
9
10/** A simple list which uses an array. This is a great choice if you won't do
11 * a lot of adding and deleting and need a fast random access list. Otherwise
12 * use the LinkedList.
13 *@author Mike Buland
14 */
15class ArrayList : public List
16{
17public:
18 /** Creates an arraylist with some pre-defined specs spelled out.
19 *@param initSize the inital number of elements to allocate.
20 *@param growByFactor How much to increase the size of the array by
21 * each time we run out of room.
22 */
23 ArrayList( int initSize=100, int growByFactor=10 );
24 /**
25 * Destroy the ArrayList
26 */
27 virtual ~ArrayList();
28
29 void *getAt( int nIndex );
30 void append( void *pData );
31 void insertBefore( void *pData, int nPos = 0 );
32 int getSize( );
33 bool isEmpty( );
34 void deleteAt( int nIndex );
35 void empty();
36 void setSize( int nNewSize );
37 void setAt( int nIndex, void *pData );
38
39private:
40 /**
41 * Checks to see if the system needs to be resized, if it does, this will
42 * automatically resize based on your parameters.
43 */
44 void checkResize();
45
46 /**
47 * Resize the system to a specified size. If it is larger, then all data
48 * will be retained, if smaller the elements at the end will be cut off.
49 *@param newSize The number of elements to include after resizing.
50 */
51 void resizeTo( int newSize );
52
53 /**
54 * Actual master array of pointers. This is done to follow the List specs.
55 * All data transactions are performed with pointers or compatable
56 * primitive data-types.
57 */
58 void **apData;
59
60 /**
61 * The number of filled in elements in the array. This is the practical
62 * real size of the ArrayList for all userspace applications.
63 */
64 int nSize;
65
66 /**
67 * The number of elements allocated in memory. Not all of these have to be
68 * filled in, and it is usually larger than nSize so that adding and
69 * deleting elements is fast and easy.
70 */
71 int nCapacity;
72
73 /**
74 * The amount to grow by whenever the array needs resizing.
75 */
76 int nGrowByFactor;
77};
78
79#endif
80
diff --git a/src/atom.cpp b/src/atom.cpp
new file mode 100644
index 0000000..f966bfc
--- /dev/null
+++ b/src/atom.cpp
@@ -0,0 +1 @@
#include "bu/atom.h"
diff --git a/src/atom.h b/src/atom.h
new file mode 100644
index 0000000..fad47eb
--- /dev/null
+++ b/src/atom.h
@@ -0,0 +1,107 @@
1#ifndef BU_ATOM_H
2#define BU_ATOM_H
3
4#include <stdint.h>
5#include <memory>
6#include "bu/exceptions.h"
7
8namespace Bu
9{
10 /**
11 *
12 */
13 template <typename t, typename talloc=std::allocator<t> >
14 class Atom
15 {
16 private:
17 typedef struct Atom<t, talloc> MyType;
18
19 public:
20 Atom() :
21 pData( NULL )
22 {
23 }
24
25 virtual ~Atom()
26 {
27 clear();
28 }
29
30 bool has() const
31 {
32 return (pData != NULL);
33 }
34
35 void set( const t &val )
36 {
37 clear();
38 pData = ta.allocate( 1 );
39 ta.construct( pData, val );
40 }
41
42 t &get()
43 {
44 if( !pData )
45 throw Bu::ExceptionBase("Not set");
46 return *pData;
47 }
48
49 const t &get() const
50 {
51 if( !pData )
52 throw Bu::ExceptionBase("Not set");
53 return *pData;
54 }
55
56 void clear()
57 {
58 if( pData )
59 {
60 ta.destroy( pData );
61 ta.deallocate( pData, 1 );
62 pData = NULL;
63 }
64 }
65
66 operator const t &() const
67 {
68 if( !pData )
69 throw Bu::ExceptionBase("Not set");
70 return *pData;
71 }
72
73 operator t &()
74 {
75 if( !pData )
76 throw Bu::ExceptionBase("Not set");
77 return *pData;
78 }
79
80 MyType &operator =( const t &oth )
81 {
82 set( oth );
83
84 return *this;
85 }
86
87 t *operator ->()
88 {
89 if( !pData )
90 throw Bu::ExceptionBase("Not set");
91 return pData;
92 }
93
94 t &operator *()
95 {
96 if( !pData )
97 throw Bu::ExceptionBase("Not set");
98 return *pData;
99 }
100
101 private:
102 t *pData;
103 talloc ta;
104 };
105}
106
107#endif
diff --git a/src/bzip2.cpp b/src/bzip2.cpp
new file mode 100644
index 0000000..fbe5712
--- /dev/null
+++ b/src/bzip2.cpp
@@ -0,0 +1,196 @@
1#include "bu/bzip2.h"
2#include "bu/exceptions.h"
3
4using namespace Bu;
5
6Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) :
7 Bu::Filter( rNext ),
8 nCompression( nCompression )
9{
10 start();
11}
12
13Bu::BZip2::~BZip2()
14{
15 stop();
16}
17
18void Bu::BZip2::start()
19{
20 bzState.state = NULL;
21 bzState.bzalloc = NULL;
22 bzState.bzfree = NULL;
23 bzState.opaque = NULL;
24
25 nBufSize = 50000;
26 pBuf = new char[nBufSize];
27}
28
29size_t Bu::BZip2::stop()
30{
31 if( bzState.state )
32 {
33 if( bReading )
34 {
35 BZ2_bzDecompressEnd( &bzState );
36 delete[] pBuf;
37 pBuf = NULL;
38 return 0;
39 }
40 else
41 {
42 size_t sTotal = 0;
43 for(;;)
44 {
45 bzState.next_in = NULL;
46 bzState.avail_in = 0;
47 bzState.avail_out = nBufSize;
48 bzState.next_out = pBuf;
49 int res = BZ2_bzCompress( &bzState, BZ_FINISH );
50 if( bzState.avail_out < nBufSize )
51 {
52 sTotal += rNext.write( pBuf, nBufSize-bzState.avail_out );
53 }
54 if( res == BZ_STREAM_END )
55 break;
56 }
57 BZ2_bzCompressEnd( &bzState );
58 delete[] pBuf;
59 pBuf = NULL;
60 return sTotal;
61 }
62 }
63 return 0;
64}
65
66void Bu::BZip2::bzError( int code )
67{
68 switch( code )
69 {
70 case BZ_OK:
71 case BZ_RUN_OK:
72 case BZ_FLUSH_OK:
73 case BZ_FINISH_OK:
74 return;
75
76 case BZ_CONFIG_ERROR:
77 throw ExceptionBase("BZip2: Library configured improperly, reinstall.");
78
79 case BZ_SEQUENCE_ERROR:
80 throw ExceptionBase("BZip2: Functions were called in an invalid sequence.");
81
82 case BZ_PARAM_ERROR:
83 throw ExceptionBase("BZip2: Invalid parameter was passed into a function.");
84
85 case BZ_MEM_ERROR:
86 throw ExceptionBase("BZip2: Couldn't allocate sufficient memory.");
87
88 case BZ_DATA_ERROR:
89 throw ExceptionBase("BZip2: Data was corrupted before decompression.");
90
91 case BZ_DATA_ERROR_MAGIC:
92 throw ExceptionBase("BZip2: Stream does not appear to be bzip2 data.");
93
94 case BZ_IO_ERROR:
95 throw ExceptionBase("BZip2: File couldn't be read from / written to.");
96
97 case BZ_UNEXPECTED_EOF:
98 throw ExceptionBase("BZip2: End of file encountered before end of stream.");
99
100 case BZ_OUTBUFF_FULL:
101 throw ExceptionBase("BZip2: Buffer not large enough to accomidate data.");
102
103 default:
104 throw ExceptionBase("BZip2: Unknown error encountered.");
105
106 }
107}
108
109size_t Bu::BZip2::read( void *pData, size_t nBytes )
110{
111 if( !bzState.state )
112 {
113 bReading = true;
114 BZ2_bzDecompressInit( &bzState, 0, 0 );
115 bzState.next_in = pBuf;
116 bzState.avail_in = 0;
117 }
118 if( bReading == false )
119 throw ExceptionBase("This bzip2 filter is in writing mode, you can't read.");
120
121 int nRead = 0;
122 int nReadTotal = bzState.total_out_lo32;
123 bzState.next_out = (char *)pData;
124 bzState.avail_out = nBytes;
125 for(;;)
126 {
127 int ret = BZ2_bzDecompress( &bzState );
128
129 nReadTotal += nRead-bzState.avail_out;
130
131 if( ret == BZ_STREAM_END )
132 {
133 if( bzState.avail_in > 0 )
134 {
135 if( rNext.isSeekable() )
136 {
137 rNext.seek( -bzState.avail_in );
138 }
139 }
140 return nBytes-bzState.avail_out;
141 }
142 bzError( ret );
143
144 if( bzState.avail_out )
145 {
146 if( bzState.avail_in == 0 )
147 {
148 nRead = rNext.read( pBuf, nBufSize );
149 bzState.next_in = pBuf;
150 bzState.avail_in = nRead;
151 }
152 }
153 else
154 {
155 return nBytes-bzState.avail_out;
156 }
157 }
158 return 0;
159}
160
161size_t Bu::BZip2::write( const void *pData, size_t nBytes )
162{
163 if( !bzState.state )
164 {
165 bReading = false;
166 BZ2_bzCompressInit( &bzState, nCompression, 0, 30 );
167 }
168 if( bReading == true )
169 throw ExceptionBase("This bzip2 filter is in reading mode, you can't write.");
170
171 size_t sTotalOut = 0;
172 bzState.next_in = (char *)pData;
173 bzState.avail_in = nBytes;
174 for(;;)
175 {
176 bzState.avail_out = nBufSize;
177 bzState.next_out = pBuf;
178
179 bzError( BZ2_bzCompress( &bzState, BZ_RUN ) );
180
181 if( bzState.avail_out < nBufSize )
182 {
183 sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out );
184 }
185 if( bzState.avail_in == 0 )
186 break;
187 }
188
189 return sTotalOut;
190}
191
192bool Bu::BZip2::isOpen()
193{
194 return (bzState.state != NULL);
195}
196
diff --git a/src/bzip2.h b/src/bzip2.h
new file mode 100644
index 0000000..0a111e8
--- /dev/null
+++ b/src/bzip2.h
@@ -0,0 +1,37 @@
1#ifndef BU_BZIP2_H
2#define BU_BZIP2_H
3
4#include <stdint.h>
5#include <bzlib.h>
6
7#include "bu/filter.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class BZip2 : public Bu::Filter
15 {
16 public:
17 BZip2( Bu::Stream &rNext, int nCompression=9 );
18 virtual ~BZip2();
19
20 virtual void start();
21 virtual size_t stop();
22 virtual size_t read( void *pBuf, size_t nBytes );
23 virtual size_t write( const void *pBuf, size_t nBytes );
24
25 virtual bool isOpen();
26
27 private:
28 void bzError( int code );
29 bz_stream bzState;
30 bool bReading;
31 int nCompression;
32 char *pBuf;
33 uint32_t nBufSize;
34 };
35}
36
37#endif
diff --git a/src/client.cpp b/src/client.cpp
new file mode 100644
index 0000000..8077b3d
--- /dev/null
+++ b/src/client.cpp
@@ -0,0 +1,206 @@
1#include "bu/client.h"
2#include "bu/socket.h"
3#include <stdlib.h>
4#include <errno.h>
5#include "bu/exceptions.h"
6#include "bu/protocol.h"
7
8/** Read buffer size. */
9#define RBS (1024*2)
10
11Bu::Client::Client( Bu::Socket *pSocket ) :
12 pSocket( pSocket ),
13 pProto( NULL ),
14 nRBOffset( 0 )
15{
16}
17
18Bu::Client::~Client()
19{
20}
21
22void Bu::Client::processInput()
23{
24 char buf[RBS];
25 size_t nRead, nTotal=0;
26
27 for(;;)
28 {
29 nRead = pSocket->read( buf, nRead );
30 if( nRead < 0 )
31 {
32 throw Bu::ConnectionException(
33 excodeReadError,
34 "Read error: %s",
35 strerror( errno )
36 );
37 }
38 else if( nRead == 0 )
39 {
40 break;
41 }
42 else
43 {
44 nTotal += nRead;
45 sReadBuf.append( buf, nRead );
46 if( !pSocket->canRead() )
47 break;
48 }
49 }
50
51 if( nTotal == 0 )
52 {
53 pSocket->close();
54 }
55
56 if( pProto && nTotal )
57 {
58 pProto->onNewData( this );
59 }
60}
61
62void Bu::Client::processOutput()
63{
64 if( sWriteBuf.getSize() > 0 )
65 {
66 pSocket->write( sWriteBuf.getStr(), sWriteBuf.getSize() );
67 sWriteBuf.clear();
68 }
69}
70
71void Bu::Client::setProtocol( Protocol *pProto )
72{
73 this->pProto = pProto;
74}
75
76Bu::Protocol *Bu::Client::getProtocol()
77{
78 return pProto;
79}
80
81void Bu::Client::clearProtocol()
82{
83 pProto = NULL;
84}
85
86Bu::FString &Bu::Client::getInput()
87{
88 return sReadBuf;
89}
90
91Bu::FString &Bu::Client::getOutput()
92{
93 return sWriteBuf;
94}
95
96bool Bu::Client::isOpen()
97{
98 if( !pSocket ) return false;
99 return pSocket->isOpen();
100}
101
102void Bu::Client::write( const void *pData, int nBytes )
103{
104 sWriteBuf.append( (const char *)pData, nBytes );
105}
106
107void Bu::Client::write( int8_t nData )
108{
109 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
110}
111
112void Bu::Client::write( int16_t nData )
113{
114 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
115}
116
117void Bu::Client::write( int32_t nData )
118{
119 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
120}
121
122void Bu::Client::write( int64_t nData )
123{
124 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
125}
126
127void Bu::Client::write( uint8_t nData )
128{
129 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
130}
131
132void Bu::Client::write( uint16_t nData )
133{
134 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
135}
136
137void Bu::Client::write( uint32_t nData )
138{
139 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
140}
141
142void Bu::Client::write( uint64_t nData )
143{
144 sWriteBuf.append( (const char *)&nData, sizeof(nData) );
145}
146
147void Bu::Client::read( void *pData, int nBytes )
148{
149 memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes );
150 nRBOffset += nBytes;
151 if( sReadBuf.getSize()-nRBOffset == 0 )
152 {
153 sReadBuf.clear();
154 nRBOffset = 0;
155 }
156 // This is an experimental threshold, maybe I'll make this configurable
157 // later on.
158 else if(
159 (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) ||
160 (nRBOffset >= sReadBuf.getSize()/4)
161 )
162 {
163 sReadBuf.trimFront( nRBOffset );
164 nRBOffset = 0;
165 }
166}
167
168void Bu::Client::peek( void *pData, int nBytes )
169{
170 memcpy( pData, sReadBuf.getStr()+nRBOffset, nBytes );
171}
172
173void Bu::Client::seek( int nBytes )
174{
175 nRBOffset += nBytes;
176 if( sReadBuf.getSize()-nRBOffset == 0 )
177 {
178 sReadBuf.clear();
179 nRBOffset = 0;
180 }
181 // This is an experimental threshold, maybe I'll make this configurable
182 // later on.
183 else if(
184 (sReadBuf.getSize() >= 1024 && nRBOffset >= sReadBuf.getSize()/2) ||
185 (nRBOffset >= sReadBuf.getSize()/4)
186 )
187 {
188 sReadBuf.trimFront( nRBOffset );
189 nRBOffset = 0;
190 }
191}
192
193long Bu::Client::getInputSize()
194{
195 return sReadBuf.getSize()-nRBOffset;
196}
197
198const Bu::Socket *Bu::Client::getSocket() const
199{
200 return pSocket;
201}
202
203void Bu::Client::disconnect()
204{
205}
206
diff --git a/src/client.h b/src/client.h
new file mode 100644
index 0000000..5947521
--- /dev/null
+++ b/src/client.h
@@ -0,0 +1,63 @@
1#ifndef BU_CLIENT_H
2#define BU_CLIENT_H
3
4#include <stdint.h>
5
6#include "bu/fstring.h"
7
8namespace Bu
9{
10 class Protocol;
11 class Socket;
12
13 /**
14 *
15 */
16 class Client
17 {
18 public:
19 Client( Bu::Socket *pSocket );
20 virtual ~Client();
21
22 void processInput();
23 void processOutput();
24
25 Bu::FString &getInput();
26 Bu::FString &getOutput();
27 void write( const void *pData, int nBytes );
28 void write( int8_t nData );
29 void write( int16_t nData );
30 void write( int32_t nData );
31 void write( int64_t nData );
32 void write( uint8_t nData );
33 void write( uint16_t nData );
34 void write( uint32_t nData );
35 void write( uint64_t nData );
36 void read( void *pData, int nBytes );
37 void peek( void *pData, int nBytes );
38 void seek( int nBytes );
39 long getInputSize();
40
41 void setProtocol( Protocol *pProto );
42 Bu::Protocol *getProtocol();
43 void clearProtocol();
44
45 bool isOpen();
46
47 const Bu::Socket *getSocket() const;
48
49 /**
50 *@todo Make this not suck.
51 */
52 void disconnect();
53
54 private:
55 Bu::Socket *pSocket;
56 Bu::Protocol *pProto;
57 Bu::FString sReadBuf;
58 int nRBOffset;
59 Bu::FString sWriteBuf;
60 };
61}
62
63#endif
diff --git a/src/entities/bu-class b/src/entities/bu-class
new file mode 100644
index 0000000..7b25291
--- /dev/null
+++ b/src/entities/bu-class
@@ -0,0 +1,48 @@
1<?xml version="1.1" ?>
2<entity desc="Basic cpp class, with optional parent class. (.cpp+.h)">
3 <param name="name" required="yes" desc="Name of the class"/>
4 <param name="parent" required="no" desc="Name of the parent class"/>
5 <file
6 name="header"
7 filename="{=name:%tolower}.h"
8>#ifndef {=name:%uccsplit:%toupper}_H
9#define {=name:%uccsplit:%toupper}_H
10
11#include &lt;stdint.h&gt;
12
13{?parent:"#include \"bu/{=parent:%tolower}.h\"
14
15"}namespace Bu
16{
17 /**
18 *
19 */
20 class {=name}{?parent:" : public {=parent}"}
21 {
22 public:
23 {=name}();
24 virtual ~{=name}();
25
26 private:
27
28 };
29}
30
31#endif
32</file>
33 <file
34 name="source"
35 filename="{=name:%tolower}.cpp"
36>#include "bu/{=name:%tolower}.h"
37
38using namespace Bu;
39
40Bu::{=name}::{=name}()
41{
42}
43
44Bu::{=name}::~{=name}()
45{
46}
47</file>
48</entity>
diff --git a/src/exceptionbase.cpp b/src/exceptionbase.cpp
index f3d22da..f6ec625 100644
--- a/src/exceptionbase.cpp
+++ b/src/exceptionbase.cpp
@@ -1,7 +1,7 @@
1#include "exceptionbase.h" 1#include "exceptionbase.h"
2#include <stdarg.h> 2#include <stdarg.h>
3 3
4ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() : 4Bu::ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() :
5 nErrorCode( 0 ), 5 nErrorCode( 0 ),
6 sWhat( NULL ) 6 sWhat( NULL )
7{ 7{
@@ -12,7 +12,7 @@ ExceptionBase::ExceptionBase( const char *lpFormat, ... ) throw() :
12 va_end(ap); 12 va_end(ap);
13} 13}
14 14
15ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() : 15Bu::ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() :
16 nErrorCode( nCode ), 16 nErrorCode( nCode ),
17 sWhat( NULL ) 17 sWhat( NULL )
18{ 18{
@@ -23,13 +23,13 @@ ExceptionBase::ExceptionBase( int nCode, const char *lpFormat, ... ) throw() :
23 va_end(ap); 23 va_end(ap);
24} 24}
25 25
26ExceptionBase::ExceptionBase( int nCode ) throw() : 26Bu::ExceptionBase::ExceptionBase( int nCode ) throw() :
27 nErrorCode( nCode ), 27 nErrorCode( nCode ),
28 sWhat( NULL ) 28 sWhat( NULL )
29{ 29{
30} 30}
31 31
32ExceptionBase::~ExceptionBase() throw() 32Bu::ExceptionBase::~ExceptionBase() throw()
33{ 33{
34 if( sWhat ) 34 if( sWhat )
35 { 35 {
@@ -38,7 +38,7 @@ ExceptionBase::~ExceptionBase() throw()
38 } 38 }
39} 39}
40 40
41void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs ) 41void Bu::ExceptionBase::setWhat( const char *lpFormat, va_list &vargs )
42{ 42{
43 if( sWhat ) delete[] sWhat; 43 if( sWhat ) delete[] sWhat;
44 int nSize; 44 int nSize;
@@ -48,7 +48,7 @@ void ExceptionBase::setWhat( const char *lpFormat, va_list &vargs )
48 vsnprintf( sWhat, nSize+1, lpFormat, vargs ); 48 vsnprintf( sWhat, nSize+1, lpFormat, vargs );
49} 49}
50 50
51void ExceptionBase::setWhat( const char *lpText ) 51void Bu::ExceptionBase::setWhat( const char *lpText )
52{ 52{
53 if( sWhat ) delete[] sWhat; 53 if( sWhat ) delete[] sWhat;
54 int nSize; 54 int nSize;
@@ -58,12 +58,12 @@ void ExceptionBase::setWhat( const char *lpText )
58 strcpy( sWhat, lpText ); 58 strcpy( sWhat, lpText );
59} 59}
60 60
61const char *ExceptionBase::what() const throw() 61const char *Bu::ExceptionBase::what() const throw()
62{ 62{
63 return sWhat; 63 return sWhat;
64} 64}
65 65
66int ExceptionBase::getErrorCode() 66int Bu::ExceptionBase::getErrorCode()
67{ 67{
68 return nErrorCode; 68 return nErrorCode;
69} 69}
diff --git a/src/exceptionbase.h b/src/exceptionbase.h
index 6f1eca7..24e4bbf 100644
--- a/src/exceptionbase.h
+++ b/src/exceptionbase.h
@@ -1,75 +1,84 @@
1#ifndef EXCEPTION_BASE_H 1#ifndef BU_EXCEPTION_BASE_H
2#define EXCEPTION_BASE_H 2#define BU_EXCEPTION_BASE_H
3 3
4#include <string> 4#include <string>
5#include <exception> 5#include <exception>
6#include <stdarg.h> 6#include <stdarg.h>
7 7
8/** 8namespace Bu
9 * A generalized Exception base class. This is nice for making general and
10 * flexible child classes that can create new error code classes.
11 */
12class ExceptionBase : public std::exception
13{ 9{
14public:
15 /**
16 * Construct an exception with an error code of zero, but with a
17 * description. The use of this is not reccomended most of the time, it's
18 * generally best to include an error code with the exception so your
19 * program can handle the exception in a better way.
20 * @param sFormat The format of the text. See printf for more info.
21 */
22 ExceptionBase( const char *sFormat, ... ) throw();
23
24 /** 10 /**
11 * A generalized Exception base class. This is nice for making general and
12 * flexible child classes that can create new error code classes.
13 *
14 * In order to create your own exception class use these two lines.
25 * 15 *
26 * @param nCode 16 * in your header: subExceptionDecl( NewClassName );
27 * @param sFormat
28 */
29 ExceptionBase( int nCode, const char *sFormat, ... ) throw();
30
31 /**
32 * 17 *
33 * @param nCode 18 * in your source: subExcpetienDef( NewClassName );
34 * @return
35 */ 19 */
36 ExceptionBase( int nCode=0 ) throw(); 20 class ExceptionBase : public std::exception
37 21 {
38 /** 22 public:
39 * 23 /**
40 * @return 24 * Construct an exception with an error code of zero, but with a
41 */ 25 * description. The use of this is not reccomended most of the time,
42 virtual ~ExceptionBase() throw(); 26 * it's generally best to include an error code with the exception so
27 * your program can handle the exception in a better way.
28 * @param sFormat The format of the text. See printf for more info.
29 */
30 ExceptionBase( const char *sFormat, ... ) throw();
31
32 /**
33 *
34 * @param nCode
35 * @param sFormat
36 */
37 ExceptionBase( int nCode, const char *sFormat, ... ) throw();
38
39 /**
40 *
41 * @param nCode
42 * @return
43 */
44 ExceptionBase( int nCode=0 ) throw();
45
46 /**
47 *
48 * @return
49 */
50 virtual ~ExceptionBase() throw();
43 51
44 /** 52 /**
45 * 53 *
46 * @return 54 * @return
47 */ 55 */
48 virtual const char *what() const throw(); 56 virtual const char *what() const throw();
49 57
50 /** 58 /**
51 * 59 *
52 * @return 60 * @return
53 */ 61 */
54 int getErrorCode(); 62 int getErrorCode();
55 63
56 /** 64 /**
57 * 65 *
58 * @param lpFormat 66 * @param lpFormat
59 * @param vargs 67 * @param vargs
60 */ 68 */
61 void setWhat( const char *lpFormat, va_list &vargs ); 69 void setWhat( const char *lpFormat, va_list &vargs );
62 70
63 /** 71 /**
64 * 72 *
65 * @param lpText 73 * @param lpText
66 */ 74 */
67 void setWhat( const char *lpText ); 75 void setWhat( const char *lpText );
68 76
69private: 77 private:
70 int nErrorCode; /**< The code for the error that occured. */ 78 int nErrorCode; /**< The code for the error that occured. */
71 char *sWhat; /**< The text string telling people what went wrong. */ 79 char *sWhat; /**< The text string telling people what went wrong. */
72}; 80 };
81}
73 82
74#define subExceptionDecl( name ) \ 83#define subExceptionDecl( name ) \
75class name : public ExceptionBase \ 84class name : public ExceptionBase \
diff --git a/src/exceptions.cpp b/src/exceptions.cpp
index ce79a5e..50b95c3 100644
--- a/src/exceptions.cpp
+++ b/src/exceptions.cpp
@@ -1,8 +1,13 @@
1#include "exceptions.h" 1#include "exceptions.h"
2#include <stdarg.h> 2#include <stdarg.h>
3 3
4subExceptionDef( XmlException ) 4namespace Bu
5subExceptionDef( FileException ) 5{
6subExceptionDef( ConnectionException ) 6 subExceptionDef( XmlException )
7subExceptionDef( PluginException ) 7 subExceptionDef( TafException )
8 8 subExceptionDef( FileException )
9 subExceptionDef( SocketException )
10 subExceptionDef( ConnectionException )
11 subExceptionDef( PluginException )
12 subExceptionDef( UnsupportedException )
13}
diff --git a/src/exceptions.h b/src/exceptions.h
index 0ab2b15..b824b91 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -1,25 +1,32 @@
1#ifndef EXCEPTIONS_H 1#ifndef BU_EXCEPTIONS_H
2#define EXCEPTIONS_H 2#define BU_EXCEPTIONS_H
3 3
4#include "exceptionbase.h" 4#include "exceptionbase.h"
5#include <stdarg.h> 5#include <stdarg.h>
6 6
7subExceptionDecl( XmlException ) 7namespace Bu
8subExceptionDecl( FileException )
9subExceptionDecl( ConnectionException )
10subExceptionDecl( PluginException )
11
12enum eFileException
13{
14 excodeEOF
15};
16
17enum eConnectionException
18{ 8{
19 excodeReadError, 9 subExceptionDecl( XmlException )
20 excodeBadReadError, 10 subExceptionDecl( TafException )
21 excodeConnectionClosed, 11 subExceptionDecl( FileException )
22 excodeSocketTimeout 12 subExceptionDecl( SocketException )
23}; 13 subExceptionDecl( ConnectionException )
14 subExceptionDecl( PluginException )
15 subExceptionDecl( UnsupportedException )
16
17 enum eFileException
18 {
19 excodeEOF
20 };
21
22 enum eConnectionException
23 {
24 excodeReadError,
25 excodeWriteError,
26 excodeBadReadError,
27 excodeConnectionClosed,
28 excodeSocketTimeout
29 };
30}
24 31
25#endif 32#endif
diff --git a/src/file.cpp b/src/file.cpp
new file mode 100644
index 0000000..1a8bd08
--- /dev/null
+++ b/src/file.cpp
@@ -0,0 +1,158 @@
1#include "file.h"
2#include "exceptions.h"
3#include <errno.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6
7Bu::File::File( const char *sName, const char *sFlags )
8{
9 fh = fopen( sName, sFlags );
10 if( fh == NULL )
11 {
12 throw Bu::FileException( errno, strerror(errno) );
13 }
14}
15
16Bu::File::File( const Bu::FString &sName, const char *sFlags )
17{
18 fh = fopen( sName.getStr(), sFlags );
19 if( fh == NULL )
20 {
21 throw Bu::FileException( errno, strerror(errno) );
22 }
23}
24
25Bu::File::File( int fd, const char *sFlags )
26{
27 fh = fdopen( fd, sFlags );
28}
29
30Bu::File::~File()
31{
32 close();
33}
34
35void Bu::File::close()
36{
37 if( fh )
38 {
39 fclose( fh );
40 fh = NULL;
41 }
42}
43
44size_t Bu::File::read( void *pBuf, size_t nBytes )
45{
46 if( !fh )
47 throw FileException("File not open.");
48
49 int nAmnt = fread( pBuf, 1, nBytes, fh );
50
51 //if( nAmnt == 0 )
52 // throw FileException("End of file.");
53
54 return nAmnt;
55}
56
57size_t Bu::File::write( const void *pBuf, size_t nBytes )
58{
59 if( !fh )
60 throw FileException("File not open.");
61
62 return fwrite( pBuf, 1, nBytes, fh );
63}
64
65long Bu::File::tell()
66{
67 if( !fh )
68 throw FileException("File not open.");
69
70 return ftell( fh );
71}
72
73void Bu::File::seek( long offset )
74{
75 if( !fh )
76 throw FileException("File not open.");
77
78 fseek( fh, offset, SEEK_CUR );
79}
80
81void Bu::File::setPos( long pos )
82{
83 if( !fh )
84 throw FileException("File not open.");
85
86 fseek( fh, pos, SEEK_SET );
87}
88
89void Bu::File::setPosEnd( long pos )
90{
91 if( !fh )
92 throw FileException("File not open.");
93
94 fseek( fh, pos, SEEK_END );
95}
96
97bool Bu::File::isEOS()
98{
99 return feof( fh );
100}
101
102bool Bu::File::canRead()
103{
104 return true;
105}
106
107bool Bu::File::canWrite()
108{
109 return true;
110}
111
112bool Bu::File::isReadable()
113{
114 return true;
115}
116
117bool Bu::File::isWritable()
118{
119 return true;
120}
121
122bool Bu::File::isSeekable()
123{
124 return true;
125}
126
127bool Bu::File::isBlocking()
128{
129 return true;
130}
131
132void Bu::File::setBlocking( bool bBlocking )
133{
134 return;
135}
136
137#ifndef WIN32
138void Bu::File::truncate( long nSize )
139{
140 ftruncate( fileno( fh ), nSize );
141}
142
143void Bu::File::chmod( mode_t t )
144{
145 fchmod( fileno( fh ), t );
146}
147#endif
148
149void Bu::File::flush()
150{
151 fflush( fh );
152}
153
154bool Bu::File::isOpen()
155{
156 return (fh != NULL);
157}
158
diff --git a/src/file.h b/src/file.h
new file mode 100644
index 0000000..d4e43eb
--- /dev/null
+++ b/src/file.h
@@ -0,0 +1,78 @@
1#ifndef BU_FILE_H
2#define BU_FILE_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 class File : public Bu::Stream
12 {
13 public:
14 File( const char *sName, const char *sFlags );
15 File( const Bu::FString &sName, const char *sFlags );
16 File( int fd, const char *sFlags );
17 virtual ~File();
18
19 virtual void close();
20 virtual size_t read( void *pBuf, size_t nBytes );
21 virtual size_t write( const void *pBuf, size_t nBytes );
22
23 virtual long tell();
24 virtual void seek( long offset );
25 virtual void setPos( long pos );
26 virtual void setPosEnd( long pos );
27 virtual bool isEOS();
28 virtual bool isOpen();
29
30 virtual void flush();
31
32 virtual bool canRead();
33 virtual bool canWrite();
34
35 virtual bool isReadable();
36 virtual bool isWritable();
37 virtual bool isSeekable();
38
39 virtual bool isBlocking();
40 virtual void setBlocking( bool bBlocking=true );
41
42 /**
43 * Create a temp file and return its handle
44 *@param sName (Bu::FString) Give in the form: "/tmp/tmpfileXXXXXXXX"
45 * It will alter your (sName) setting the 'X's to random
46 * characters.
47 *@param sFlags (const char *) Standard file flags 'rb'... etc..
48 *@returns (Bu::File) A file object representing your temp file.
49 */
50#ifndef WIN32
51 inline static Bu::File tempFile( Bu::FString &sName, const char *sFlags )
52 {
53 int afh_d = mkstemp( sName.getStr() );
54
55 return Bu::File( afh_d, sFlags );
56 }
57
58 /**
59 * Set the size of the file to (nSize). You can either grow or shrink
60 * the file.
61 *@param nSize (long) The new size of the file.
62 */
63 void truncate( long nSize );
64
65 /**
66 * Change the file access permissions.
67 *@param t (mode_t) The new file access permissions.
68 */
69 void chmod( mode_t t );
70#endif
71
72 private:
73 FILE *fh;
74
75 };
76}
77
78#endif
diff --git a/src/filter.cpp b/src/filter.cpp
new file mode 100644
index 0000000..96a8694
--- /dev/null
+++ b/src/filter.cpp
@@ -0,0 +1,97 @@
1#include "bu/filter.h"
2
3Bu::Filter::Filter( Bu::Stream &rNext ) :
4 rNext( rNext )
5{
6}
7
8Bu::Filter::~Filter()
9{
10 //printf("-> Bu::Filter::~Filter()\n");
11}
12/*
13void Bu::Filter::start()
14{
15 printf("-> Bu::Filter::start()\n");
16}
17
18void Bu::Filter::stop()
19{
20}*/
21
22void Bu::Filter::close()
23{
24 stop();
25 rNext.close();
26}
27
28long Bu::Filter::tell()
29{
30 return rNext.tell();
31}
32
33void Bu::Filter::seek( long offset )
34{
35 rNext.seek( offset );
36}
37
38void Bu::Filter::setPos( long pos )
39{
40 rNext.setPos( pos );
41}
42
43void Bu::Filter::setPosEnd( long pos )
44{
45 rNext.setPosEnd( pos );
46}
47
48bool Bu::Filter::isEOS()
49{
50 return rNext.isEOS();
51}
52
53bool Bu::Filter::isOpen()
54{
55 return rNext.isOpen();
56}
57
58bool Bu::Filter::canRead()
59{
60 return rNext.canRead();
61}
62
63bool Bu::Filter::canWrite()
64{
65 return rNext.canWrite();
66}
67
68bool Bu::Filter::isReadable()
69{
70 return rNext.isReadable();
71}
72
73bool Bu::Filter::isWritable()
74{
75 return rNext.isWritable();
76}
77
78bool Bu::Filter::isSeekable()
79{
80 return rNext.isSeekable();
81}
82
83bool Bu::Filter::isBlocking()
84{
85 return rNext.isBlocking();
86}
87
88void Bu::Filter::setBlocking( bool bBlocking )
89{
90 rNext.setBlocking( bBlocking );
91}
92
93void Bu::Filter::flush()
94{
95 rNext.flush();
96}
97
diff --git a/src/filter.h b/src/filter.h
new file mode 100644
index 0000000..bd557b2
--- /dev/null
+++ b/src/filter.h
@@ -0,0 +1,65 @@
1#ifndef BU_FILTER_H
2#define BU_FILTER_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7
8namespace Bu
9{
10 /**
11 * Data filter base class. Each data filter should contain a read and write
12 * section. Effectively, the write applies the filter, the read un-applies
13 * the filter, if possible. For example, BZip2 is a filter that compresses
14 * on write and decompresses on read. All bi-directional filters should
15 * follow: x == read( write( x ) ) (byte-for-byte comparison)
16 *
17 * Also, all returned buffers should be owned by the filter, and deleted
18 * when the filter is deleted. This means that the output of a read or
19 * write operation must be used before the next call to read or write or the
20 * data will be destroyed. Also, the internal buffer may be changed or
21 * recreated between calls, so always get a new pointer from a call to
22 * read or write.
23 *
24 * The close function can also return data, so make sure to check for it,
25 * many filters such as compression filters will buffer data until they have
26 * enough to create a compression block, in these cases the leftover data
27 * will be returned by close.
28 */
29 class Filter : public Bu::Stream
30 {
31 public:
32 Filter( Bu::Stream &rNext );
33 virtual ~Filter();
34
35 virtual void start()=0;
36 virtual size_t stop()=0;
37 virtual void close();
38 virtual long tell();
39 virtual void seek( long offset );
40 virtual void setPos( long pos );
41 virtual void setPosEnd( long pos );
42 virtual bool isEOS();
43 virtual bool isOpen();
44
45 virtual void flush();
46
47 virtual bool canRead();
48 virtual bool canWrite();
49
50 virtual bool isReadable();
51 virtual bool isWritable();
52 virtual bool isSeekable();
53
54 virtual bool isBlocking();
55 virtual void setBlocking( bool bBlocking=true );
56
57 protected:
58 Bu::Stream &rNext;
59
60 private:
61
62 };
63}
64
65#endif
diff --git a/src/fstring.cpp b/src/fstring.cpp
index 82d024d..f71d6c1 100644
--- a/src/fstring.cpp
+++ b/src/fstring.cpp
@@ -1,13 +1,20 @@
1#include "fstring.h" 1#include "fstring.h"
2#include "hash.h" 2#include "hash.h"
3 3
4template<> uint32_t __calcHashCode<FString>( const FString &k ) 4template<> uint32_t Bu::__calcHashCode<Bu::FString>( const Bu::FString &k )
5{ 5{
6 return __calcHashCode( k.c_str() ); 6 return __calcHashCode( k.c_str() );
7} 7}
8 8
9template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ) 9template<> bool Bu::__cmpHashKeys<Bu::FString>(
10 const Bu::FString &a, const Bu::FString &b )
10{ 11{
11 return a == b; 12 return a == b;
12} 13}
13 14
15std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val )
16{
17 os.write( val.getStr(), val.getSize() );
18 return os;
19}
20
diff --git a/src/fstring.h b/src/fstring.h
index c5397cc..1e1fc02 100644
--- a/src/fstring.h
+++ b/src/fstring.h
@@ -1,651 +1,903 @@
1#ifndef F_STRING_H 1#ifndef BU_F_STRING_H
2#define F_STRING_H 2#define BU_F_STRING_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <memory> 5#include <memory>
6#include "serializable.h" 6#include "bu/archival.h"
7#include "serializer.h" 7#include "bu/archive.h"
8#include "bu/hash.h"
8 9
9template< typename chr > 10#define min( a, b ) ((a<b)?(a):(b))
10struct FStringChunk 11
11{ 12namespace Bu
12 long nLength;
13 chr *pData;
14 FStringChunk *pNext;
15};
16
17/**
18 * Flexible String class. This class was designed with string passing and
19 * generation in mind. Like the standard string class you can specify what
20 * datatype to use for each character. Unlike the standard string class,
21 * collection of appended and prepended terms is done lazily, making long
22 * operations that involve many appends very inexpensive. In addition internal
23 * ref-counting means that if you pass strings around between functions there's
24 * almost no overhead in time or memory since a reference is created and no
25 * data is actually copied. This also means that you never need to put any
26 * FBasicString into a ref-counting container class.
27 */
28template< typename chr, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
29class FBasicString : public Serializable
30{ 13{
14 template< typename chr >
15 struct FStringChunk
16 {
17 long nLength;
18 chr *pData;
19 FStringChunk *pNext;
20 };
21
22 /**
23 * Flexible String class. This class was designed with string passing and
24 * generation in mind. Like the standard string class you can specify what
25 * datatype to use for each character. Unlike the standard string class,
26 * collection of appended and prepended terms is done lazily, making long
27 * operations that involve many appends very inexpensive. In addition internal
28 * ref-counting means that if you pass strings around between functions there's
29 * almost no overhead in time or memory since a reference is created and no
30 * data is actually copied. This also means that you never need to put any
31 * FBasicString into a ref-counting container class.
32 *
33 *@param chr (typename) Type of character (i.e. char)
34 *@param nMinSize (int) Chunk size (default: 256)
35 *@param chralloc (typename) Memory Allocator for chr
36 *@param chunkalloc (typename) Memory Allocator for chr chunks
37 */
38 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
39 class FBasicString : public Archival
40 {
31#ifndef VALTEST 41#ifndef VALTEST
32#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) ) 42#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
33#endif 43#endif
34private: 44 private:
35 typedef struct FStringChunk<chr> Chunk; 45 typedef struct FStringChunk<chr> Chunk;
36 typedef struct FBasicString<chr, chralloc, chunkalloc> MyType; 46 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
37 47
38public: 48 public:
39 FBasicString() : 49 FBasicString() :
40 nLength( 0 ), 50 nLength( 0 ),
41 pnRefs( NULL ), 51 pnRefs( NULL ),
42 pFirst( NULL ), 52 pFirst( NULL ),
43 pLast( NULL ) 53 pLast( NULL )
44 { 54 {
45 } 55 }
46 56
47 FBasicString( const chr *pData ) : 57 FBasicString( const chr *pData ) :
48 nLength( 0 ), 58 nLength( 0 ),
49 pnRefs( NULL ), 59 pnRefs( NULL ),
50 pFirst( NULL ), 60 pFirst( NULL ),
51 pLast( NULL ) 61 pLast( NULL )
52 { 62 {
53 append( pData ); 63 append( pData );
54 } 64 }
55
56 FBasicString( const chr *pData, long nLength ) :
57 nLength( 0 ),
58 pnRefs( NULL ),
59 pFirst( NULL ),
60 pLast( NULL )
61 {
62 append( pData, nLength );
63 }
64
65 FBasicString( const MyType &rSrc ) :
66 nLength( 0 ),
67 pnRefs( NULL ),
68 pFirst( NULL ),
69 pLast( NULL )
70 {
71 // Here we have no choice but to copy, since the other guy is a const.
72 // In the case that the source were flat, we could get a reference, it
73 // would make some things faster, but not matter in many other cases.
74
75 joinShare( rSrc );
76 //copyFrom( rSrc );
77 }
78
79 FBasicString( const MyType &rSrc, long nLength ) :
80 nLength( 0 ),
81 pnRefs( NULL ),
82 pFirst( NULL ),
83 pLast( NULL )
84 {
85 append( rSrc.pFirst->pData, nLength );
86 }
87
88 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
89 nLength( 0 ),
90 pnRefs( NULL ),
91 pFirst( NULL ),
92 pLast( NULL )
93 {
94 append( rSrc.pFirst->pData+nStart, nLength );
95 }
96
97 FBasicString( long nSize ) :
98 nLength( nSize ),
99 pnRefs( NULL ),
100 pFirst( NULL ),
101 pLast( NULL )
102 {
103 pFirst = pLast = newChunk( nSize );
104 }
105 65
106 virtual ~FBasicString() 66 FBasicString( const chr *pData, long nLength ) :
107 { 67 nLength( 0 ),
108 clear(); 68 pnRefs( NULL ),
109 } 69 pFirst( NULL ),
70 pLast( NULL )
71 {
72 append( pData, nLength );
73 }
110 74
111 void append( const chr *pData ) 75 FBasicString( const MyType &rSrc ) :
112 { 76 nLength( 0 ),
113 long nLen; 77 pnRefs( NULL ),
114 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 78 pFirst( NULL ),
115 79 pLast( NULL )
116 Chunk *pNew = newChunk( nLen ); 80 {
117 cpy( pNew->pData, pData, nLen ); 81 // Here we have no choice but to copy, since the other guy is a const.
82 // In the case that the source were flat, we could get a reference, it
83 // would make some things faster, but not matter in many other cases.
118 84
119 appendChunk( pNew ); 85 joinShare( rSrc );
120 } 86 //copyFrom( rSrc );
87 }
121 88
122 void append( const chr *pData, long nLen ) 89 FBasicString( const MyType &rSrc, long nLength ) :
123 { 90 nLength( 0 ),
124 Chunk *pNew = newChunk( nLen ); 91 pnRefs( NULL ),
92 pFirst( NULL ),
93 pLast( NULL )
94 {
95 append( rSrc.pFirst->pData, nLength );
96 }
125 97
126 cpy( pNew->pData, pData, nLen ); 98 FBasicString( const MyType &rSrc, long nStart, long nLength ) :
99 nLength( 0 ),
100 pnRefs( NULL ),
101 pFirst( NULL ),
102 pLast( NULL )
103 {
104 append( rSrc.pFirst->pData+nStart, nLength );
105 }
127 106
128 appendChunk( pNew ); 107 FBasicString( long nSize ) :
129 } 108 nLength( nSize ),
109 pnRefs( NULL ),
110 pFirst( NULL ),
111 pLast( NULL )
112 {
113 pFirst = pLast = newChunk( nSize );
114 }
130 115
131 void prepend( const chr *pData ) 116 virtual ~FBasicString()
132 { 117 {
133 long nLen; 118 clear();
134 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ); 119 }
135
136 Chunk *pNew = newChunk( nLen );
137 cpy( pNew->pData, pData, nLen );
138 120
139 prependChunk( pNew ); 121 /**
140 } 122 *@todo void append( const MyType & sData )
123 */
141 124
142 void prepend( const chr *pData, long nLen ) 125 /**
143 { 126 * Append data to your string.
144 Chunk *pNew = newChunk( nLen ); 127 *@param pData (const chr *) The data to append.
145 128 */
146 cpy( pNew->pData, pData, nLen ); 129 void append( const chr *pData )
130 {
131 if( !pData ) return;
132 long nLen;
133 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
134 if( nLen == 0 )
135 return;
136
137 Chunk *pNew = newChunk( nLen );
138 cpy( pNew->pData, pData, nLen );
147 139
148 prependChunk( pNew ); 140 appendChunk( pNew );
149 } 141 }
150 142
151 void clear() 143 /**
152 { 144 * Append data to your string.
153 realClear(); 145 *@param pData (const chr *) The data to append.
154 } 146 *@param nLen (long) The length of the data to append.
147 */
148 void append( const chr *pData, long nLen )
149 {
150 if( nLen == 0 )
151 return;
155 152
156 void resize( long nNewSize ) 153 Chunk *pNew = newChunk( nLen );
157 { 154
158 if( nLength == nNewSize ) 155 cpy( pNew->pData, pData, nLen );
159 return;
160
161 flatten();
162
163 Chunk *pNew = newChunk( nNewSize );
164 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
165 cpy( pNew->pData, pFirst->pData, nNewLen );
166 pNew->pData[nNewLen] = (chr)0;
167 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
168 aChunk.deallocate( pFirst, 1 );
169 pFirst = pLast = pNew;
170 nLength = nNewSize;
171 }
172
173 long getSize() const
174 {
175 return nLength;
176 }
177
178 chr *getStr()
179 {
180 if( pFirst == NULL )
181 return NULL;
182
183 flatten();
184 return pFirst->pData;
185 }
186
187 const chr *getStr() const
188 {
189 if( pFirst == NULL )
190 return NULL;
191 156
192 flatten(); 157 appendChunk( pNew );
193 return pFirst->pData; 158 }
194 }
195 159
196 chr *c_str() 160 /**
197 { 161 * Append a single chr to your string.
198 if( pFirst == NULL ) 162 *@param cData (const chr &) The character to append.
199 return NULL; 163 */
200 164 void append( const chr &cData )
201 flatten(); 165 {
202 return pFirst->pData; 166 append( &cData, 1 );
203 } 167 }
204
205 const chr *c_str() const
206 {
207 if( pFirst == NULL )
208 return NULL;
209 168
210 flatten(); 169 /**
211 return pFirst->pData; 170 * Prepend another FString to this one.
212 } 171 *@param sData (MyType &) The FString to prepend.
172 */
173 void prepend( const MyType & sData )
174 {
175 prepend( sData.getStr(), sData.getSize() );
176 }
213 177
214 MyType &operator +=( const chr *pData ) 178 /**
215 { 179 * Prepend data to your string.
216 append( pData ); 180 *@param pData (const chr *) The data to prepend.
181 */
182 void prepend( const chr *pData )
183 {
184 long nLen;
185 for( nLen = 0; pData[nLen] != (chr)0; nLen++ );
186
187 Chunk *pNew = newChunk( nLen );
188 cpy( pNew->pData, pData, nLen );
217 189
218 return (*this); 190 prependChunk( pNew );
219 } 191 }
220
221 MyType &operator +=( const MyType &rSrc )
222 {
223 rSrc.flatten();
224 append( rSrc.pFirst->pData, rSrc.nLength );
225 192
226 return (*this); 193 /**
227 } 194 * Prepend data to your string.
195 *@param pData (const chr *) The data to prepend.
196 *@param nLen (long) The length of the data to prepend.
197 */
198 void prepend( const chr *pData, long nLen )
199 {
200 Chunk *pNew = newChunk( nLen );
201
202 cpy( pNew->pData, pData, nLen );
228 203
229 MyType &operator +=( const chr pData ) 204 prependChunk( pNew );
230 { 205 }
231 chr tmp[2] = { pData, (chr)0 };
232 append( tmp );
233 206
234 return (*this); 207 /**
235 } 208 *@todo void prepend( const chr &cData )
209 */
236 210
237 MyType &operator =( const chr *pData ) 211 /**
238 { 212 * Clear all data from the string.
239 clear(); 213 */
240 append( pData ); 214 void clear()
215 {
216 realClear();
217 }
241 218
242 return (*this); 219 /**
243 } 220 * Force the string to resize
221 *@param nNewSize (long) The new size of the string.
222 */
223 void resize( long nNewSize )
224 {
225 if( nLength == nNewSize )
226 return;
244 227
245 MyType &operator =( const MyType &rSrc ) 228 flatten();
246 { 229
247 //if( rSrc.isFlat() ) 230 Chunk *pNew = newChunk( nNewSize );
248 //{ 231 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength);
249 joinShare( rSrc ); 232 cpy( pNew->pData, pFirst->pData, nNewLen );
250 //} 233 pNew->pData[nNewLen] = (chr)0;
251 //else 234 aChr.deallocate( pFirst->pData, pFirst->nLength+1 );
252 //{ 235 aChunk.deallocate( pFirst, 1 );
253 // copyFrom( rSrc ); 236 pFirst = pLast = pNew;
254 //} 237 nLength = nNewSize;
255 //
256
257 return (*this);
258 }
259
260 bool operator ==( const chr *pData ) const
261 {
262 if( pFirst == NULL ) {
263 if( pData == NULL )
264 return true;
265 return false;
266 } 238 }
267 239
268 flatten(); 240 /**
269 const chr *a = pData; 241 * Get the current size of the string.
270 chr *b = pFirst->pData; 242 *@returns (long) The current size of the string.
271 for( ; *a!=(chr)0; a++, b++ ) 243 */
244 long getSize() const
272 { 245 {
273 if( *a != *b ) 246 return nLength;
274 return false;
275 } 247 }
248
249 /**
250 * Get a pointer to the string array.
251 *@returns (chr *) The string data.
252 */
253 chr *getStr()
254 {
255 if( pFirst == NULL )
256 return NULL;
276 257
277 return true; 258 flatten();
278 } 259 return pFirst->pData;
279 260 }
280 bool operator ==( const MyType &pData ) const 261
281 { 262 /**
282 if( pFirst == pData.pFirst ) 263 * Get a const pointer to the string array.
283 return true; 264 *@returns (const chr *) The string data.
284 if( pFirst == NULL ) 265 */
285 return false; 266 const chr *getStr() const
267 {
268 if( pFirst == NULL )
269 return NULL;
270
271 flatten();
272 return pFirst->pData;
273 }
286 274
287 flatten(); 275 /**
288 pData.flatten(); 276 * (std::string compatability) Get a pointer to the string array.
289 const chr *a = pData.pFirst->pData; 277 *@returns (chr *) The string data.
290 chr *b = pFirst->pData; 278 */
291 for( ; *a!=(chr)0; a++, b++ ) 279 chr *c_str()
292 { 280 {
293 if( *a != *b ) 281 if( pFirst == NULL )
294 return false; 282 return NULL;
283
284 flatten();
285 return pFirst->pData;
295 } 286 }
287
288 /**
289 * (std::string compatability) Get a const pointer to the string array.
290 *@returns (const chr *) The string data.
291 */
292 const chr *c_str() const
293 {
294 if( pFirst == NULL )
295 return NULL;
296 296
297 return true; 297 flatten();
298 } 298 return pFirst->pData;
299 }
299 300
300 bool operator !=(const chr *pData ) const 301 /**
301 { 302 * Plus equals operator for FString.
302 return !(*this == pData); 303 *@param pData (const chr *) The data to append to your FString.
303 } 304 */
304 305 MyType &operator +=( const chr *pData )
305 bool operator !=(const MyType &pData ) const 306 {
306 { 307 append( pData );
307 return !(*this == pData);
308 }
309 308
310 chr &operator[]( long nIndex ) 309 return (*this);
311 { 310 }
312 flatten(); 311
312 /**
313 * Plus equals operator for FString.
314 *@param pData (const MyType &) The FString to append to your FString.
315 */
316 MyType &operator +=( const MyType &rSrc )
317 {
318 if( rSrc.nLength == 0 )
319 return (*this);
320 rSrc.flatten();
321 append( rSrc.pFirst->pData, rSrc.nLength );
313 322
314 return pFirst->pData[nIndex]; 323 return (*this);
315 } 324 }
316
317 const chr &operator[]( long nIndex ) const
318 {
319 flatten();
320 325
321 return pFirst->pData[nIndex]; 326 /**
322 } 327 * Plus equals operator for FString.
328 *@param pData (const chr) The character to append to your FString.
329 */
330 MyType &operator +=( const chr pData )
331 {
332 append( &pData, 1 );
323 333
324 bool isWS( long nIndex ) const 334 return (*this);
325 { 335 }
326 flatten();
327 336
328 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t' 337 /**
329 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n'; 338 * Assignment operator.
330 } 339 *@param pData (const chr *) The character array to append to your
340 * FString.
341 */
342 MyType &operator =( const chr *pData )
343 {
344 clear();
345 append( pData );
331 346
332 bool isAlpha( long nIndex ) const 347 return (*this);
333 { 348 }
334 flatten();
335 349
336 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z') 350 /**
337 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z'); 351 * Reset your FString to this character array.
338 } 352 *@param pData (const chr *) The character array to set your FString to.
353 */
354 void set( const chr *pData )
355 {
356 clear();
357 append( pData );
358 }
339 359
340 void toLower() 360 /**
341 { 361 * Reset your FString to this character array.
342 flatten(); 362 *@param pData (const chr *) The character array to set your FString to.
343 unShare(); 363 *@param nSize (long) The length of the inputted character array.
364 */
365 void set( const chr *pData, long nSize )
366 {
367 clear();
368 append( pData, nSize );
369 }
344 370
345 for( long j = 0; j < nLength; j++ ) 371 /**
372 * Assignment operator.
373 *@param rSrc (const MyType &) The FString to set your FString to.
374 */
375 MyType &operator =( const MyType &rSrc )
346 { 376 {
347 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' ) 377 //if( rSrc.isFlat() )
348 pFirst->pData[j] -= 'A'-'a'; 378 //{
379 joinShare( rSrc );
380 //}
381 //else
382 //{
383 // copyFrom( rSrc );
384 //}
385 //
386
387 return (*this);
349 } 388 }
350 } 389
390 /**
391 * Equals comparison operator.
392 *@param pData (const chr *) The character array to compare your FString
393 * to.
394 */
395 bool operator ==( const chr *pData ) const
396 {
397 if( pFirst == NULL ) {
398 if( pData == NULL )
399 return true;
400 return false;
401 }
351 402
352 void toUpper() 403 flatten();
353 { 404 const chr *a = pData;
354 flatten(); 405 chr *b = pFirst->pData;
355 unShare(); 406 for( ; *a!=(chr)0; a++, b++ )
407 {
408 if( *a != *b )
409 return false;
410 }
356 411
357 for( long j = 0; j < nLength; j++ ) 412 return true;
413 }
414
415 /**
416 * Equals comparison operator.
417 *@param pData (const MyType &) The FString to compare your FString to.
418 */
419 bool operator ==( const MyType &pData ) const
358 { 420 {
359 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' ) 421 if( pFirst == pData.pFirst )
360 pFirst->pData[j] += 'A'-'a'; 422 return true;
423 if( pFirst == NULL )
424 return false;
425
426 flatten();
427 pData.flatten();
428 const chr *a = pData.pFirst->pData;
429 chr *b = pFirst->pData;
430 for( ; *a!=(chr)0; a++, b++ )
431 {
432 if( *a != *b )
433 return false;
434 }
435
436 return true;
361 } 437 }
362 }
363 438
364 void serialize( class Serializer &ar ) 439 /**
365 { 440 * Not equals comparison operator.
366 if( ar.isLoading() ) 441 *@param pData (const chr *) The character array to compare your FString
442 * to.
443 */
444 bool operator !=(const chr *pData ) const
367 { 445 {
368 clear(); 446 return !(*this == pData);
369 long nLen; 447 }
370 ar >> nLen;
371 448
372 Chunk *pNew = newChunk( nLen ); 449 /**
373 ar.read( pNew->pData, nLen*sizeof(chr) ); 450 * Not equals comparison operator.
374 appendChunk( pNew ); 451 *@param pData (const MyType &) The FString to compare your FString to.
452 */
453 bool operator !=(const MyType &pData ) const
454 {
455 return !(*this == pData);
375 } 456 }
376 else 457
458 /**
459 * Indexing operator
460 *@param nIndex (long) The index of the character you want.
461 *@returns (chr &) The character at position (nIndex).
462 */
463 chr &operator[]( long nIndex )
377 { 464 {
378 flatten(); 465 flatten();
379 466
380 ar << nLength; 467 return pFirst->pData[nIndex];
381 ar.write( pFirst->pData, nLength*sizeof(chr) );
382 } 468 }
383 } 469
470 /**
471 * Const indexing operator
472 *@param nIndex (long) The index of the character you want.
473 *@returns (const chr &) The character at position (nIndex).
474 */
475 const chr &operator[]( long nIndex ) const
476 {
477 flatten();
384 478
385private: 479 return pFirst->pData[nIndex];
386 void flatten() const 480 }
387 { 481/*
388 if( isFlat() ) 482 operator const chr *() const
389 return; 483 {
484 if( !pFirst ) return NULL;
485 flatten();
486 return pFirst->pData;
487 }
488 */
390 489
391 if( pFirst == NULL ) 490 operator bool() const
392 return; 491 {
492 return (pFirst != NULL);
493 }
393 494
394 unShare(); 495 bool isSet() const
496 {
497 return (pFirst != NULL);
498 }
395 499
396 Chunk *pNew = newChunk( nLength ); 500 /**
397 chr *pos = pNew->pData; 501 * Is the character at index (nIndex) white space?
398 Chunk *i = pFirst; 502 *@param nIndex (long) The index of the character you want to check.
399 for(;;) 503 *@returns (bool) Is it white space?
504 */
505 bool isWS( long nIndex ) const
400 { 506 {
401 cpy( pos, i->pData, i->nLength ); 507 flatten();
402 pos += i->nLength; 508
403 i = i->pNext; 509 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t'
404 if( i == NULL ) 510 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n';
405 break;
406 } 511 }
407 realClear();
408 512
409 pLast = pFirst = pNew; 513 /**
410 nLength = pNew->nLength; 514 * Is the character at index (nIndex) a letter?
411 } 515 *@param nIndex (long) The index of the character you want to check.
412 516 *@returns (bool) Is it a letter?
413 void realClear() const 517 */
414 { 518 bool isAlpha( long nIndex ) const
415 if( pFirst == NULL ) 519 {
416 return; 520 flatten();
417 521
418 if( isShared() ) 522 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z')
523 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z');
524 }
525
526 /**
527 * Convert your alpha characters to lower case.
528 */
529 void toLower()
419 { 530 {
420 decRefs(); 531 flatten();
532 unShare();
533
534 for( long j = 0; j < nLength; j++ )
535 {
536 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' )
537 pFirst->pData[j] -= 'A'-'a';
538 }
539 }
540
541 /**
542 * Convert your alpha characters to upper case.
543 */
544 void toUpper()
545 {
546 flatten();
547 unShare();
548
549 for( long j = 0; j < nLength; j++ )
550 {
551 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' )
552 pFirst->pData[j] += 'A'-'a';
553 }
554 }
555
556 /**
557 * Find the index of the first occurrance of (sText)
558 *@param sText (const char *) The string to search for.
559 *@returns (long) The index of the first occurrance. -1 for not found.
560 */
561 long find( const char *sText )
562 {
563 long nTLen = strlen( sText );
564 flatten();
565 for( long j = 0; j < pFirst->nLength-nTLen; j++ )
566 {
567 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
568 return j;
569 }
570 return -1;
571 }
572
573 /**
574 * Do a reverse search for (sText)
575 *@param sText (const char *) The string to search for.
576 *@returns (long) The index of the last occurrance. -1 for not found.
577 */
578 long rfind( const char *sText )
579 {
580 long nTLen = strlen( sText );
581 flatten();
582 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- )
583 {
584 if( !strncmp( sText, pFirst->pData+j, nTLen ) )
585 return j;
586 }
587 return -1;
588 }
589
590 /**
591 * Remove nAmnt bytes from the front of the string. This function
592 * operates in O(n) time and should be used sparingly.
593 */
594 void trimFront( long nAmnt )
595 {
596 long nNewLen = nLength - nAmnt;
597 flatten();
598 Chunk *pNew = newChunk( nNewLen );
599 cpy( pNew->pData, pFirst->pData, nNewLen );
600 clear();
601 appendChunk( pNew );
602 }
603
604 /**
605 * Function the archiver calls to archive your FString.
606 *@param ar (Archive) The archive which is archiving your FString.
607 */
608 void archive( class Archive &ar )
609 {
610 if( ar.isLoading() )
611 {
612 clear();
613 long nLen;
614 ar >> nLen;
615
616 if( nLen > 0 )
617 {
618 Chunk *pNew = newChunk( nLen );
619 ar.read( pNew->pData, nLen*sizeof(chr) );
620 appendChunk( pNew );
621 }
622 }
623 else
624 {
625 flatten();
626
627 ar << nLength;
628 if( nLength )
629 ar.write( pFirst->pData, nLength*sizeof(chr) );
630 }
421 } 631 }
422 else 632
633 private:
634 void flatten() const
423 { 635 {
636 if( isFlat() )
637 return;
638
639 if( pFirst == NULL )
640 return;
641
642 unShare();
643
644 Chunk *pNew = newChunk( nLength );
645 chr *pos = pNew->pData;
424 Chunk *i = pFirst; 646 Chunk *i = pFirst;
425 for(;;) 647 for(;;)
426 { 648 {
427 Chunk *n = i->pNext; 649 cpy( pos, i->pData, i->nLength );
428 aChr.deallocate( i->pData, i->nLength+1 ); 650 pos += i->nLength;
429 aChunk.deallocate( i, 1 ); 651 i = i->pNext;
430 if( n == NULL ) 652 if( i == NULL )
431 break; 653 break;
432 i = n;
433 } 654 }
434 pFirst = pLast = NULL; 655 realClear();
435 nLength = 0; 656
657 pLast = pFirst = pNew;
658 nLength = pNew->nLength;
436 } 659 }
437 }
438
439 void copyFrom( const FBasicString<chr, chralloc, chunkalloc> &rSrc )
440 {
441 if( rSrc.pFirst == NULL )
442 return;
443 660
444 decRefs(); 661 void realClear() const
445
446 Chunk *pNew = newChunk( rSrc.nLength );
447 chr *pos = pNew->pData;
448 Chunk *i = rSrc.pFirst;
449 for(;;)
450 { 662 {
451 cpy( pos, i->pData, i->nLength ); 663 if( pFirst == NULL )
452 pos += i->nLength; 664 return;
453 i = i->pNext;
454 if( i == NULL )
455 break;
456 }
457 clear();
458 665
459 appendChunk( pNew ); 666 if( isShared() )
460 } 667 {
461 668 decRefs();
462 bool isFlat() const 669 }
463 { 670 else
464 return (pFirst == pLast); 671 {
465 } 672 Chunk *i = pFirst;
466 673 for(;;)
467 bool isShared() const 674 {
468 { 675 Chunk *n = i->pNext;
469 return (pnRefs != NULL); 676 aChr.deallocate( i->pData, i->nLength+1 );
470 } 677 aChunk.deallocate( i, 1 );
678 if( n == NULL )
679 break;
680 i = n;
681 }
682 pFirst = pLast = NULL;
683 nLength = 0;
684 }
685 }
686
687 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
688 {
689 if( rSrc.pFirst == NULL )
690 return;
691
692 decRefs();
471 693
472 Chunk *newChunk() const 694 Chunk *pNew = newChunk( rSrc.nLength );
473 { 695 chr *pos = pNew->pData;
474 Chunk *pNew = aChunk.allocate( 1 ); 696 Chunk *i = rSrc.pFirst;
475 pNew->pNext = NULL; 697 for(;;)
476 return pNew; 698 {
477 } 699 cpy( pos, i->pData, i->nLength );
478 700 pos += i->nLength;
479 Chunk *newChunk( long nLen ) const 701 i = i->pNext;
480 { 702 if( i == NULL )
481 Chunk *pNew = aChunk.allocate( 1 ); 703 break;
482 pNew->pNext = NULL; 704 }
483 pNew->nLength = nLen; 705 clear();
484 pNew->pData = aChr.allocate( nLen+1 );
485 pNew->pData[nLen] = (chr)0;
486 return pNew;
487 }
488
489 void appendChunk( Chunk *pNewChunk )
490 {
491 unShare();
492 706
493 if( pFirst == NULL ) 707 appendChunk( pNew );
494 pLast = pFirst = pNewChunk; 708 }
495 else 709
710 bool isFlat() const
496 { 711 {
497 pLast->pNext = pNewChunk; 712 return (pFirst == pLast);
498 pLast = pNewChunk;
499 } 713 }
500 714
501 nLength += pNewChunk->nLength; 715 bool isShared() const
502 } 716 {
503 717 return (pnRefs != NULL);
504 void prependChunk( Chunk *pNewChunk ) 718 }
505 {
506 unShare();
507 719
508 if( pFirst == NULL ) 720 Chunk *newChunk() const
509 pLast = pFirst = pNewChunk; 721 {
510 else 722 Chunk *pNew = aChunk.allocate( 1 );
723 pNew->pNext = NULL;
724 return pNew;
725 }
726
727 Chunk *newChunk( long nLen ) const
511 { 728 {
512 pNewChunk->pNext = pFirst; 729 Chunk *pNew = aChunk.allocate( 1 );
513 pFirst = pNewChunk; 730 pNew->pNext = NULL;
731 pNew->nLength = nLen;
732 pNew->pData = aChr.allocate( nLen+1 );
733 pNew->pData[nLen] = (chr)0;
734 return pNew;
514 } 735 }
515 736
516 nLength += pNewChunk->nLength; 737 void appendChunk( Chunk *pNewChunk )
517 } 738 {
739 unShare();
518 740
519 void joinShare( MyType &rSrc ) 741 if( pFirst == NULL )
520 { 742 pLast = pFirst = pNewChunk;
521 clear(); 743 else
744 {
745 pLast->pNext = pNewChunk;
746 pLast = pNewChunk;
747 }
522 748
523 if( !rSrc.isFlat() ) 749 nLength += pNewChunk->nLength;
524 rSrc.flatten(); 750 }
751
752 void prependChunk( Chunk *pNewChunk )
753 {
754 unShare();
525 755
526 rSrc.initCount(); 756 if( pFirst == NULL )
527 pnRefs = rSrc.pnRefs; 757 pLast = pFirst = pNewChunk;
528 (*pnRefs)++; 758 else
529 nLength = rSrc.nLength; 759 {
530 pFirst = rSrc.pFirst; 760 pNewChunk->pNext = pFirst;
531 pLast = rSrc.pLast; 761 pFirst = pNewChunk;
532 } 762 }
533
534 void joinShare( const MyType &rSrc )
535 {
536 clear();
537 763
538 rSrc.flatten(); 764 nLength += pNewChunk->nLength;
765 }
539 766
540 if( !rSrc.isShared() ) 767 void joinShare( MyType &rSrc )
541 { 768 {
542 rSrc.pnRefs = new uint32_t; 769 clear();
543 (*rSrc.pnRefs) = 1; 770
771 if( !rSrc.isFlat() )
772 rSrc.flatten();
773
774 rSrc.initCount();
775 pnRefs = rSrc.pnRefs;
776 (*pnRefs)++;
777 nLength = rSrc.nLength;
778 pFirst = rSrc.pFirst;
779 pLast = rSrc.pLast;
544 } 780 }
545 pnRefs = rSrc.pnRefs; 781
546 (*pnRefs)++; 782 void joinShare( const MyType &rSrc )
547 nLength = rSrc.nLength; 783 {
548 pFirst = rSrc.pFirst; 784 clear();
549 pLast = rSrc.pLast;
550 }
551 785
552 /** 786 rSrc.flatten();
553 * This takes an object that was shared and makes a copy of the base data
554 * that was being shared so that this copy can be changed. This should be
555 * added before any call that will change this object;
556 */
557 void unShare() const
558 {
559 if( isShared() == false )
560 return;
561 787
562 Chunk *pNew = newChunk( nLength ); 788 if( !rSrc.isShared() )
563 chr *pos = pNew->pData; 789 {
564 Chunk *i = pFirst; 790 rSrc.pnRefs = new uint32_t;
565 for(;;) 791 (*rSrc.pnRefs) = 1;
792 }
793 pnRefs = rSrc.pnRefs;
794 (*pnRefs)++;
795 nLength = rSrc.nLength;
796 pFirst = rSrc.pFirst;
797 pLast = rSrc.pLast;
798 }
799
800 /**
801 * This takes an object that was shared and makes a copy of the base data
802 * that was being shared so that this copy can be changed. This should be
803 * added before any call that will change this object;
804 */
805 void unShare() const
566 { 806 {
567 cpy( pos, i->pData, i->nLength ); 807 if( isShared() == false )
568 pos += i->nLength; 808 return;
569 i = i->pNext; 809 if( pFirst == NULL )
570 if( i == NULL ) 810 return;
571 break; 811
812 Chunk *pNew = newChunk( nLength );
813 chr *pos = pNew->pData;
814 Chunk *i = pFirst;
815 for(;;)
816 {
817 cpy( pos, i->pData, i->nLength );
818 pos += i->nLength;
819 i = i->pNext;
820 if( i == NULL )
821 break;
822 }
823 decRefs();
824 pLast = pFirst = pNew;
825 nLength = pNew->nLength;
572 } 826 }
573 decRefs();
574 pLast = pFirst = pNew;
575 nLength = pNew->nLength;
576 }
577 827
578 /** 828 /**
579 * This decrements our ref count and pulls us out of the share. If the ref 829 * This decrements our ref count and pulls us out of the share. If the ref
580 * count hits zero because of this, it destroys the share. This is not 830 * count hits zero because of this, it destroys the share. This is not
581 * safe to call on it's own, it's much better to call unShare. 831 * safe to call on it's own, it's much better to call unShare.
582 */ 832 */
583 void decRefs() const 833 void decRefs() const
584 {
585 if( isShared() )
586 { 834 {
587 (*pnRefs)--; 835 if( isShared() )
588 if( (*pnRefs) == 0 )
589 destroyShare();
590 else
591 { 836 {
592 pnRefs = NULL; 837 (*pnRefs)--;
593 pFirst = NULL; 838 if( (*pnRefs) == 0 )
594 pLast = NULL; 839 destroyShare();
595 nLength = 0; 840 else
841 {
842 pnRefs = NULL;
843 pFirst = NULL;
844 pLast = NULL;
845 nLength = 0;
846 }
596 } 847 }
597 } 848 }
598 }
599 849
600 /** 850 /**
601 * While the unShare function removes an instance from a share, this 851 * While the unShare function removes an instance from a share, this
602 * function destroys the data that was in the share, removing the share 852 * function destroys the data that was in the share, removing the share
603 * itself. This should only be called when the refcount for the share has 853 * itself. This should only be called when the refcount for the share has
604 * or is about to reach zero. 854 * or is about to reach zero.
605 */ 855 */
606 void destroyShare() const 856 void destroyShare() const
607 { 857 {
608 delete pnRefs; 858 delete pnRefs;
609 pnRefs = NULL; 859 pnRefs = NULL;
610 realClear(); 860 realClear();
611 } 861 }
612 862
613#ifdef VALTEST 863#ifdef VALTEST
614 void cpy( chr *dest, const chr *src, long count ) const 864 void cpy( chr *dest, const chr *src, long count ) const
615 {
616 for( int j = 0; j < count; j++ )
617 { 865 {
618 *dest = *src; 866 for( int j = 0; j < count; j++ )
619 dest++; 867 {
620 src++; 868 *dest = *src;
869 dest++;
870 src++;
871 }
621 } 872 }
622 }
623#endif 873#endif
624 874
625 void initCount() const 875 void initCount() const
626 {
627 if( !isShared() )
628 { 876 {
629 pnRefs = new uint32_t; 877 if( !isShared() )
630 (*pnRefs) = 1; 878 {
879 pnRefs = new uint32_t;
880 (*pnRefs) = 1;
881 }
631 } 882 }
632 }
633 883
634private: 884 private:
635 mutable long nLength; 885 mutable long nLength;
636 mutable uint32_t *pnRefs; 886 mutable uint32_t *pnRefs;
637 mutable Chunk *pFirst; 887 mutable Chunk *pFirst;
638 mutable Chunk *pLast; 888 mutable Chunk *pLast;
639 889
640 mutable chralloc aChr; 890 mutable chralloc aChr;
641 mutable chunkalloc aChunk; 891 mutable chunkalloc aChunk;
642}; 892 };
643 893
644typedef FBasicString<char> FString; 894 typedef FBasicString<char> FString;
645 895
646#include "hash.h" 896 template<> uint32_t __calcHashCode<FString>( const FString &k );
647template<> uint32_t __calcHashCode<FString>( const FString &k ); 897 template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b );
648template<> bool __cmpHashKeys<FString>( const FString &a, const FString &b ); 898}
649 899
900#include <ostream>
901std::basic_ostream<char>& operator<< (std::basic_ostream<char> &os, const Bu::FString &val );
650 902
651#endif 903#endif
diff --git a/src/hash.cpp b/src/hash.cpp
index c52e6b1..a207c29 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -1,29 +1,29 @@
1#include "hash.h" 1#include "hash.h"
2 2
3subExceptionDef( HashException ) 3namespace Bu { subExceptionDef( HashException ) }
4 4
5template<> uint32_t __calcHashCode<int>( const int &k ) 5template<> uint32_t Bu::__calcHashCode<int>( const int &k )
6{ 6{
7 return k; 7 return k;
8} 8}
9 9
10template<> bool __cmpHashKeys<int>( const int &a, const int &b ) 10template<> bool Bu::__cmpHashKeys<int>( const int &a, const int &b )
11{ 11{
12 return a == b; 12 return a == b;
13} 13}
14 14
15template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k ) 15template<> uint32_t Bu::__calcHashCode<unsigned int>( const unsigned int &k )
16{ 16{
17 return k; 17 return k;
18} 18}
19 19
20template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b ) 20template<> bool Bu::__cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b )
21{ 21{
22 return a == b; 22 return a == b;
23} 23}
24 24
25template<> 25template<>
26uint32_t __calcHashCode<const char *>( const char * const &k ) 26uint32_t Bu::__calcHashCode<const char *>( const char * const &k )
27{ 27{
28 if (k == NULL) 28 if (k == NULL)
29 { 29 {
@@ -39,7 +39,7 @@ uint32_t __calcHashCode<const char *>( const char * const &k )
39 return nPos; 39 return nPos;
40} 40}
41 41
42template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b ) 42template<> bool Bu::__cmpHashKeys<const char *>( const char * const &a, const char * const &b )
43{ 43{
44 if( a == b ) 44 if( a == b )
45 return true; 45 return true;
@@ -52,7 +52,7 @@ template<> bool __cmpHashKeys<const char *>( const char * const &a, const char *
52} 52}
53 53
54template<> 54template<>
55uint32_t __calcHashCode<char *>( char * const &k ) 55uint32_t Bu::__calcHashCode<char *>( char * const &k )
56{ 56{
57 if (k == NULL) 57 if (k == NULL)
58 { 58 {
@@ -68,7 +68,7 @@ uint32_t __calcHashCode<char *>( char * const &k )
68 return nPos; 68 return nPos;
69} 69}
70 70
71template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b ) 71template<> bool Bu::__cmpHashKeys<char *>( char * const &a, char * const &b )
72{ 72{
73 if( a == b ) 73 if( a == b )
74 return true; 74 return true;
@@ -80,7 +80,7 @@ template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b )
80 return false; 80 return false;
81} 81}
82 82
83template<> uint32_t __calcHashCode<std::string>( const std::string &k ) 83template<> uint32_t Bu::__calcHashCode<std::string>( const std::string &k )
84{ 84{
85 std::string::size_type j, sz = k.size(); 85 std::string::size_type j, sz = k.size();
86 const char *s = k.c_str(); 86 const char *s = k.c_str();
@@ -94,20 +94,8 @@ template<> uint32_t __calcHashCode<std::string>( const std::string &k )
94 return nPos; 94 return nPos;
95} 95}
96 96
97template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b ) 97template<> bool Bu::__cmpHashKeys<std::string>( const std::string &a, const std::string &b )
98{ 98{
99 return a == b; 99 return a == b;
100} 100}
101 101
102template<> uint32_t __calcHashCode<Hashable>( const Hashable &k )
103{
104 return 0;
105 //return k.getHashCode();
106}
107
108template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b )
109{
110 return false;
111 //return a.compareForHash( b );
112}
113
diff --git a/src/hash.h b/src/hash.h
index a21d651..f183823 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -1,745 +1,1071 @@
1#ifndef HASH_H 1#ifndef BU_HASH_H
2#define HASH_H 2#define BU_HASH_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <string.h> 5#include <string.h>
6#include <memory> 6#include <memory>
7#include <iostream> 7#include <iostream>
8#include <list> 8#include <list>
9#include "exceptionbase.h" 9#include <utility>
10#include "hashable.h" 10#include "bu/exceptionbase.h"
11#include "serializable.h" 11#include "bu/list.h"
12#include "serializer.h" 12///#include "archival.h"
13///#include "archive.h"
13 14
14#define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0)) 15#define bitsToBytes( n ) (n/32+(n%32>0 ? 1 : 0))
15 16
16subExceptionDecl( HashException ) 17namespace Bu
17
18enum eHashException
19{ 18{
20 excodeNotFilled 19 subExceptionDecl( HashException )
21};
22
23template<typename T>
24uint32_t __calcHashCode( const T &k );
25
26template<typename T>
27bool __cmpHashKeys( const T &a, const T &b );
28 20
29struct __calcNextTSize_fast 21 enum eHashException
30{
31 uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const
32 { 22 {
33 if( nDeleted >= nCapacity/2 ) 23 excodeNotFilled
34 return nCapacity; 24 };
35 return nCapacity*2+1;
36 }
37};
38 25
39template<typename key, typename value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<value>, typename challoc = std::allocator<uint32_t> > 26 template<typename T>
40class Hash; 27 uint32_t __calcHashCode( const T &k );
41 28
42template< typename key, typename _value, typename sizecalc = __calcNextTSize_fast, typename keyalloc = std::allocator<key>, typename valuealloc = std::allocator<_value>, typename challoc = std::allocator<uint32_t> > 29 template<typename T>
43struct HashProxy 30 bool __cmpHashKeys( const T &a, const T &b );
44{
45 friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>;
46private:
47 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) :
48 hsh( h ),
49 pKey( k ),
50 nPos( nPos ),
51 hash( hash ),
52 bFilled( false )
53 {
54 }
55 31
56 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) : 32 struct __calcNextTSize_fast
57 hsh( h ),
58 nPos( nPos ),
59 pValue( pValue ),
60 bFilled( true )
61 { 33 {
62 } 34 uint32_t operator()( uint32_t nCapacity, uint32_t nFill, uint32_t nDeleted ) const
35 {
36 if( nDeleted >= nCapacity/2 )
37 return nCapacity;
38 return nCapacity*2+1;
39 }
40 };
63 41
64 Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh; 42 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> >
65 key *pKey; 43 class Hash;
66 uint32_t nPos;
67 _value *pValue;
68 uint32_t hash;
69 bool bFilled;
70 44
71public: 45 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> >
72 operator _value &() 46 struct HashProxy
73 { 47 {
74 if( bFilled == false ) 48 friend class Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc>;
75 throw HashException( 49 private:
76 excodeNotFilled, 50 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, key *k, uint32_t nPos, uint32_t hash ) :
77 "No data assosiated with that key." 51 hsh( h ),
78 ); 52 pKey( k ),
79 return *pValue; 53 nPos( nPos ),
80 } 54 hash( hash ),
55 bFilled( false )
56 {
57 }
81 58
82 _value &value() 59 HashProxy( Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &h, uint32_t nPos, _value *pValue ) :
83 { 60 hsh( h ),
84 if( bFilled == false ) 61 nPos( nPos ),
85 throw HashException( 62 pValue( pValue ),
86 excodeNotFilled, 63 bFilled( true )
87 "No data assosiated with that key." 64 {
88 ); 65 }
89 return *pValue;
90 }
91 66
92 bool isFilled() 67 Hash<key, _value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
93 { 68 key *pKey;
94 return bFilled; 69 uint32_t nPos;
95 } 70 _value *pValue;
71 uint32_t hash;
72 bool bFilled;
96 73
97 void erase() 74 public:
98 { 75 /**
99 if( bFilled ) 76 * Cast operator for HashProxy.
77 *@returns (value_type &) The value the HashProxy is pointing to.
78 */
79 operator _value &()
100 { 80 {
101 hsh._erase( nPos ); 81 if( bFilled == false )
102 hsh.onDelete(); 82 throw HashException(
83 excodeNotFilled,
84 "No data assosiated with that key."
85 );
86 return *pValue;
103 } 87 }
104 }
105 88
106 _value operator=( _value nval ) 89 /**
107 { 90 * Direct function for retrieving a value out of the HashProxy.
108 if( bFilled ) 91 *@returns (value_type &) The value pointed to by this HashProxy.
92 */
93 _value &value()
109 { 94 {
110 hsh.va.destroy( pValue ); 95 if( bFilled == false )
111 hsh.va.construct( pValue, nval ); 96 throw HashException(
112 hsh.onUpdate(); 97 excodeNotFilled,
98 "No data assosiated with that key."
99 );
100 return *pValue;
113 } 101 }
114 else 102
103 /**
104 * Whether this HashProxy points to something real or not.
105 */
106 bool isFilled()
115 { 107 {
116 hsh.fill( nPos, *pKey, nval, hash ); 108 return bFilled;
117 hsh.onInsert();
118 } 109 }
119 110
120 return nval; 111 /**
121 } 112 * Erase the data pointed to by this HashProxy.
113 */
114 void erase()
115 {
116 if( bFilled )
117 {
118 hsh._erase( nPos );
119 hsh.onDelete();
120 }
121 }
122 122
123 _value *operator->() 123 /**
124 { 124 * Assign data to this point in the hash table.
125 if( bFilled == false ) 125 *@param nval (value_type) the data to assign.
126 throw HashException( 126 */
127 excodeNotFilled, 127 _value operator=( _value nval )
128 "No data assosiated with that key." 128 {
129 ); 129 if( bFilled )
130 return pValue; 130 {
131 } 131 hsh.va.destroy( pValue );
132}; 132 hsh.va.construct( pValue, nval );
133 hsh.onUpdate();
134 }
135 else
136 {
137 hsh.fill( nPos, *pKey, nval, hash );
138 hsh.onInsert();
139 }
133 140
134template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc > 141 return nval;
135class Hash 142 }
136{
137 friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>;
138public:
139 Hash() :
140 nCapacity( 11 ),
141 nFilled( 0 ),
142 nDeleted( 0 ),
143 bFilled( NULL ),
144 bDeleted( NULL ),
145 aKeys( NULL ),
146 aValues( NULL ),
147 aHashCodes( NULL )
148 {
149 nKeysSize = bitsToBytes( nCapacity );
150 bFilled = ca.allocate( nKeysSize );
151 bDeleted = ca.allocate( nKeysSize );
152 clearBits();
153
154 aHashCodes = ca.allocate( nCapacity );
155 aKeys = ka.allocate( nCapacity );
156 aValues = va.allocate( nCapacity );
157 }
158 143
159 Hash( const Hash &src ) : 144 /**
160 nCapacity( src.nCapacity ), 145 * Pointer extraction operator. Access to members of data pointed to
161 nFilled( 0 ), 146 * by HashProxy.
162 nDeleted( 0 ), 147 *@returns (value_type *)
163 bFilled( NULL ), 148 */
164 bDeleted( NULL ), 149 _value *operator->()
165 aKeys( NULL ), 150 {
166 aValues( NULL ), 151 if( bFilled == false )
167 aHashCodes( NULL ) 152 throw HashException(
168 { 153 excodeNotFilled,
169 nKeysSize = bitsToBytes( nCapacity ); 154 "No data assosiated with that key."
170 bFilled = ca.allocate( nKeysSize ); 155 );
171 bDeleted = ca.allocate( nKeysSize ); 156 return pValue;
172 clearBits(); 157 }
158 };
173 159
174 aHashCodes = ca.allocate( nCapacity ); 160 /**
175 aKeys = ka.allocate( nCapacity ); 161 * Libbu Template Hash Table
176 aValues = va.allocate( nCapacity ); 162 *@param key (typename) The datatype of the hashtable keys
163 *@param value (typename) The datatype of the hashtable data
164 *@param sizecalc (typename) Functor to compute new table size on rehash
165 *@param keyalloc (typename) Memory allocator for hashtable keys
166 *@param valuealloc (typename) Memory allocator for hashtable values
167 *@param challoc (typename) Byte allocator for bitflags
168 */
169 template<typename key, typename value, typename sizecalc, typename keyalloc, typename valuealloc, typename challoc >
170 class Hash
171 {
172 friend struct HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>;
173 public:
174 Hash() :
175 nCapacity( 11 ),
176 nFilled( 0 ),
177 nDeleted( 0 ),
178 bFilled( NULL ),
179 bDeleted( NULL ),
180 aKeys( NULL ),
181 aValues( NULL ),
182 aHashCodes( NULL )
183 {
184 nKeysSize = bitsToBytes( nCapacity );
185 bFilled = ca.allocate( nKeysSize );
186 bDeleted = ca.allocate( nKeysSize );
187 clearBits();
188
189 aHashCodes = ca.allocate( nCapacity );
190 aKeys = ka.allocate( nCapacity );
191 aValues = va.allocate( nCapacity );
192 }
177 193
178 for( uint32_t j = 0; j < src.nCapacity; j++ ) 194 Hash( const Hash &src ) :
195 nCapacity( src.nCapacity ),
196 nFilled( 0 ),
197 nDeleted( 0 ),
198 bFilled( NULL ),
199 bDeleted( NULL ),
200 aKeys( NULL ),
201 aValues( NULL ),
202 aHashCodes( NULL )
179 { 203 {
180 if( src.isFilled( j ) ) 204 nKeysSize = bitsToBytes( nCapacity );
205 bFilled = ca.allocate( nKeysSize );
206 bDeleted = ca.allocate( nKeysSize );
207 clearBits();
208
209 aHashCodes = ca.allocate( nCapacity );
210 aKeys = ka.allocate( nCapacity );
211 aValues = va.allocate( nCapacity );
212
213 for( uint32_t j = 0; j < src.nCapacity; j++ )
181 { 214 {
182 insert( src.aKeys[j], src.aValues[j] ); 215 if( src.isFilled( j ) )
216 {
217 insert( src.aKeys[j], src.aValues[j] );
218 }
183 } 219 }
184 } 220 }
185 }
186 221
187 Hash &operator=( const Hash &src ) 222 /**
188 { 223 * Hashtable assignment operator. Clears this hashtable and
189 for( uint32_t j = 0; j < nCapacity; j++ ) 224 * copies RH into it.
225 */
226 Hash &operator=( const Hash &src )
190 { 227 {
191 if( isFilled( j ) ) 228 for( uint32_t j = 0; j < nCapacity; j++ )
192 if( !isDeleted( j ) ) 229 {
230 if( isFilled( j ) )
231 if( !isDeleted( j ) )
232 {
233 va.destroy( &aValues[j] );
234 ka.destroy( &aKeys[j] );
235 }
236 }
237 va.deallocate( aValues, nCapacity );
238 ka.deallocate( aKeys, nCapacity );
239 ca.deallocate( bFilled, nKeysSize );
240 ca.deallocate( bDeleted, nKeysSize );
241 ca.deallocate( aHashCodes, nCapacity );
242
243 nFilled = 0;
244 nDeleted = 0;
245 nCapacity = src.nCapacity;
246 nKeysSize = bitsToBytes( nCapacity );
247 bFilled = ca.allocate( nKeysSize );
248 bDeleted = ca.allocate( nKeysSize );
249 clearBits();
250
251 aHashCodes = ca.allocate( nCapacity );
252 aKeys = ka.allocate( nCapacity );
253 aValues = va.allocate( nCapacity );
254
255 for( uint32_t j = 0; j < src.nCapacity; j++ )
256 {
257 if( src.isFilled( j ) )
193 { 258 {
194 va.destroy( &aValues[j] ); 259 insert( src.aKeys[j], src.aValues[j] );
195 ka.destroy( &aKeys[j] );
196 } 260 }
197 } 261 }
198 va.deallocate( aValues, nCapacity );
199 ka.deallocate( aKeys, nCapacity );
200 ca.deallocate( bFilled, nKeysSize );
201 ca.deallocate( bDeleted, nKeysSize );
202 ca.deallocate( aHashCodes, nCapacity );
203
204 nFilled = 0;
205 nDeleted = 0;
206 nCapacity = src.nCapacity;
207 nKeysSize = bitsToBytes( nCapacity );
208 bFilled = ca.allocate( nKeysSize );
209 bDeleted = ca.allocate( nKeysSize );
210 clearBits();
211 262
212 aHashCodes = ca.allocate( nCapacity ); 263 return *this;
213 aKeys = ka.allocate( nCapacity ); 264 }
214 aValues = va.allocate( nCapacity );
215 265
216 for( uint32_t j = 0; j < src.nCapacity; j++ ) 266 virtual ~Hash()
217 { 267 {
218 if( src.isFilled( j ) ) 268 for( uint32_t j = 0; j < nCapacity; j++ )
219 { 269 {
220 insert( src.aKeys[j], src.aValues[j] ); 270 if( isFilled( j ) )
271 if( !isDeleted( j ) )
272 {
273 va.destroy( &aValues[j] );
274 ka.destroy( &aKeys[j] );
275 }
221 } 276 }
277 va.deallocate( aValues, nCapacity );
278 ka.deallocate( aKeys, nCapacity );
279 ca.deallocate( bFilled, nKeysSize );
280 ca.deallocate( bDeleted, nKeysSize );
281 ca.deallocate( aHashCodes, nCapacity );
222 } 282 }
223 283
224 return *this; 284 /**
225 } 285 * Get the current hash table capacity. (Changes at re-hash)
226 286 *@returns (uint32_t) The current capacity.
227 virtual ~Hash() 287 */
228 { 288 uint32_t getCapacity()
229 for( uint32_t j = 0; j < nCapacity; j++ )
230 { 289 {
231 if( isFilled( j ) ) 290 return nCapacity;
232 if( !isDeleted( j ) )
233 {
234 va.destroy( &aValues[j] );
235 ka.destroy( &aKeys[j] );
236 }
237 } 291 }
238 va.deallocate( aValues, nCapacity );
239 ka.deallocate( aKeys, nCapacity );
240 ca.deallocate( bFilled, nKeysSize );
241 ca.deallocate( bDeleted, nKeysSize );
242 ca.deallocate( aHashCodes, nCapacity );
243 }
244 292
245 uint32_t getCapacity() 293 /**
246 { 294 * Get the number of hash locations spoken for. (Including
247 return nCapacity; 295 * not-yet-cleaned-up deleted items.)
248 } 296 *@returns (uint32_t) The current fill state.
297 */
298 uint32_t getFill()
299 {
300 return nFilled;
301 }
249 302
250 uint32_t getFill() 303 /**
251 { 304 * Get the number of items stored in the hash table.
252 return nFilled; 305 *@returns (uint32_t) The number of items stored in the hash table.
253 } 306 */
307 uint32_t size()
308 {
309 return nFilled-nDeleted;
310 }
254 311
255 uint32_t size() 312 /**
256 { 313 * Get the number of items which have been deleted, but not yet
257 return nFilled-nDeleted; 314 * cleaned up.
258 } 315 *@returns (uint32_t) The number of deleted items.
316 */
317 uint32_t getDeleted()
318 {
319 return nDeleted;
320 }
259 321
260 uint32_t getDeleted() 322 /**
261 { 323 * Hash table index operator
262 return nDeleted; 324 *@param k (key_type) Key of data to be retrieved.
263 } 325 *@returns (HashProxy) Proxy pointing to the data.
326 */
327 virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k )
328 {
329 uint32_t hash = __calcHashCode( k );
330 bool bFill;
331 uint32_t nPos = probe( hash, k, bFill );
264 332
265 virtual HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc> operator[]( key k ) 333 if( bFill )
266 { 334 {
267 uint32_t hash = __calcHashCode( k ); 335 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] );
268 bool bFill; 336 }
269 uint32_t nPos = probe( hash, k, bFill ); 337 else
338 {
339 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash );
340 }
341 }
270 342
271 if( bFill ) 343 /**
344 * Insert a value (v) under key (k) into the hash table
345 *@param k (key_type) Key to list the value under.
346 *@param v (value_type) Value to store in the hash table.
347 */
348 virtual void insert( key k, value v )
272 { 349 {
273 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, nPos, &aValues[nPos] ); 350 uint32_t hash = __calcHashCode( k );
351 bool bFill;
352 uint32_t nPos = probe( hash, k, bFill );
353
354 if( bFill )
355 {
356 va.destroy( &aValues[nPos] );
357 va.construct( &aValues[nPos], v );
358 onUpdate();
359 }
360 else
361 {
362 fill( nPos, k, v, hash );
363 onInsert();
364 }
274 } 365 }
275 else 366
367 /**
368 * Remove a value from the hash table.
369 *@param k (key_type) The data under this key will be erased.
370 */
371 virtual void erase( key k )
276 { 372 {
277 return HashProxy<key, value, sizecalc, keyalloc, valuealloc, challoc>( *this, &k, nPos, hash ); 373 uint32_t hash = __calcHashCode( k );
374 bool bFill;
375 uint32_t nPos = probe( hash, k, bFill );
376
377 if( bFill )
378 {
379 _erase( nPos );
380 onDelete();
381 }
278 } 382 }
279 }
280 383
281 virtual void insert( key k, value v ) 384 struct iterator;
282 {
283 uint32_t hash = __calcHashCode( k );
284 bool bFill;
285 uint32_t nPos = probe( hash, k, bFill );
286 385
287 if( bFill ) 386 /**
387 * Remove a value from the hash pointed to from an iterator.
388 *@param i (iterator &) The data to be erased.
389 */
390 virtual void erase( struct iterator &i )
288 { 391 {
289 va.destroy( &aValues[nPos] ); 392 if( this != &i.hsh )
290 va.construct( &aValues[nPos], v ); 393 throw HashException("This iterator didn't come from this Hash.");
291 onUpdate(); 394 if( isFilled( i.nPos ) && !isDeleted( i.nPos ) )
395 {
396 _erase( i.nPos );
397 onDelete();
398 }
292 } 399 }
293 else 400
401 /**
402 * Remove all data from the hash table.
403 */
404 virtual void clear()
294 { 405 {
295 fill( nPos, k, v, hash ); 406 for( uint32_t j = 0; j < nCapacity; j++ )
296 onInsert(); 407 {
408 if( isFilled( j ) )
409 if( !isDeleted( j ) )
410 {
411 va.destroy( &aValues[j] );
412 ka.destroy( &aKeys[j] );
413 onDelete();
414 }
415 }
416
417 clearBits();
297 } 418 }
298 }
299 419
300 virtual void erase( key k ) 420 /**
301 { 421 * Get an item of data from the hash table.
302 uint32_t hash = __calcHashCode( k ); 422 *@param k (key_type) Key pointing to the data to be retrieved.
303 bool bFill; 423 *@returns (value_type &) The data pointed to by (k).
304 uint32_t nPos = probe( hash, k, bFill ); 424 */
425 virtual value &get( key k )
426 {
427 uint32_t hash = __calcHashCode( k );
428 bool bFill;
429 uint32_t nPos = probe( hash, k, bFill );
305 430
306 if( bFill ) 431 if( bFill )
432 {
433 return aValues[nPos];
434 }
435 else
436 {
437 throw HashException(
438 excodeNotFilled,
439 "No data assosiated with that key."
440 );
441 }
442 }
443
444 /**
445 * Get a const item of data from the hash table.
446 *@param k (key_type) Key pointing to the data to be retrieved.
447 *@returns (const value_type &) A const version of the data pointed
448 * to by (k).
449 */
450 virtual const value &get( key k ) const
307 { 451 {
308 _erase( nPos ); 452 uint32_t hash = __calcHashCode( k );
309 onDelete(); 453 bool bFill;
454 uint32_t nPos = probe( hash, k, bFill );
455
456 if( bFill )
457 {
458 return aValues[nPos];
459 }
460 else
461 {
462 throw HashException(
463 excodeNotFilled,
464 "No data assosiated with that key."
465 );
466 }
310 } 467 }
311 }
312 468
313 struct iterator; 469 /**
314 virtual void erase( struct iterator &i ) 470 * Does the hash table contain an item under key (k).
315 { 471 *@param k (key_type) The key to check.
316 if( this != &i.hsh ) 472 *@returns (bool) Whether there was an item in the hash under key (k).
317 throw HashException("This iterator didn't come from this Hash."); 473 */
318 if( isFilled( i.nPos ) && !isDeleted( i.nPos ) ) 474 virtual bool has( key k )
319 { 475 {
320 _erase( i.nPos ); 476 bool bFill;
321 onDelete(); 477 probe( __calcHashCode( k ), k, bFill, false );
478
479 return bFill;
322 } 480 }
323 }
324 481
325 virtual void clear() 482 /**
326 { 483 * Iteration structure for iterating through the hash.
327 for( uint32_t j = 0; j < nCapacity; j++ ) 484 */
485 typedef struct iterator
328 { 486 {
329 if( isFilled( j ) ) 487 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
330 if( !isDeleted( j ) ) 488 private:
489 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) :
490 hsh( hsh ),
491 nPos( 0 ),
492 bFinished( false )
493 {
494 nPos = hsh.getFirstPos( bFinished );
495 }
496
497 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) :
498 hsh( hsh ),
499 nPos( 0 ),
500 bFinished( bDone )
501 {
502 }
503
504 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
505 uint32_t nPos;
506 bool bFinished;
507
508 public:
509 /**
510 * Iterator incrementation operator. Move the iterator forward.
511 */
512 iterator operator++( int )
513 {
514 if( bFinished == false )
515 nPos = hsh.getNextPos( nPos, bFinished );
516
517 return *this;
518 }
519
520 /**
521 * Iterator incrementation operator. Move the iterator forward.
522 */
523 iterator operator++()
524 {
525 if( bFinished == false )
526 nPos = hsh.getNextPos( nPos, bFinished );
527
528 return *this;
529 }
530
531 /**
532 * Iterator equality comparison operator. Iterators the same?
533 */
534 bool operator==( const iterator &oth )
535 {
536 if( bFinished != oth.bFinished )
537 return false;
538 if( bFinished == true )
331 { 539 {
332 va.destroy( &aValues[j] ); 540 return true;
333 ka.destroy( &aKeys[j] );
334 onDelete();
335 } 541 }
336 } 542 else
337 543 {
338 clearBits(); 544 if( oth.nPos == nPos )
339 } 545 return true;
546 return false;
547 }
548 }
549
550 /**
551 * Iterator not equality comparison operator. Not the same?
552 */
553 bool operator!=( const iterator &oth )
554 {
555 return !(*this == oth );
556 }
340 557
341 virtual value &get( key k ) 558 /**
342 { 559 * Iterator assignment operator.
343 uint32_t hash = __calcHashCode( k ); 560 */
344 bool bFill; 561 iterator operator=( const iterator &oth )
345 uint32_t nPos = probe( hash, k, bFill ); 562 {
563 if( &hsh != &oth.hsh )
564 throw HashException(
565 "Cannot mix iterators from different hash objects.");
566 nPos = oth.nPos;
567 bFinished = oth.bFinished;
568 }
346 569
347 if( bFill ) 570 /**
348 { 571 * Iterator dereference operator... err.. get the value
349 return aValues[nPos]; 572 *@returns (value_type &) The value behind this iterator.
350 } 573 */
351 else 574 value &operator *()
575 {
576 return hsh.getValueAtPos( nPos );
577 }
578
579 /**
580 * Get the key behind this iterator.
581 *@returns (key_type &) The key behind this iterator.
582 */
583 key &getKey()
584 {
585 return hsh.getKeyAtPos( nPos );
586 }
587
588 /**
589 * Get the value behind this iterator.
590 *@returs (value_type &) The value behind this iterator.
591 */
592 value &getValue()
593 {
594 return hsh.getValueAtPos( nPos );
595 }
596 };
597
598 /**
599 * Iteration structure for iterating through the hash (const).
600 */
601 typedef struct const_iterator
352 { 602 {
353 throw HashException( 603 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>;
354 excodeNotFilled, 604 private:
355 "No data assosiated with that key." 605 const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) :
356 ); 606 hsh( hsh ),
357 } 607 nPos( 0 ),
358 } 608 bFinished( false )
609 {
610 nPos = hsh.getFirstPos( bFinished );
611 }
612
613 const_iterator( const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) :
614 hsh( hsh ),
615 nPos( 0 ),
616 bFinished( bDone )
617 {
618 }
359 619
360 virtual bool has( key k ) 620 const Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh;
361 { 621 uint32_t nPos;
362 bool bFill; 622 bool bFinished;
363 probe( __calcHashCode( k ), k, bFill, false );
364 623
365 return bFill; 624 public:
366 } 625 /**
626 * Iterator incrementation operator. Move the iterator forward.
627 */
628 const_iterator operator++( int )
629 {
630 if( bFinished == false )
631 nPos = hsh.getNextPos( nPos, bFinished );
367 632
368 typedef struct iterator 633 return *this;
369 { 634 }
370 friend class Hash<key, value, sizecalc, keyalloc, valuealloc, challoc>; 635
371 private: 636 /**
372 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh ) : 637 * Iterator incrementation operator. Move the iterator forward.
373 hsh( hsh ), 638 */
374 nPos( 0 ), 639 const_iterator operator++()
375 bFinished( false ) 640 {
641 if( bFinished == false )
642 nPos = hsh.getNextPos( nPos, bFinished );
643
644 return *this;
645 }
646
647 /**
648 * Iterator equality comparison operator. Iterators the same?
649 */
650 bool operator==( const const_iterator &oth )
651 {
652 if( bFinished != oth.bFinished )
653 return false;
654 if( bFinished == true )
655 {
656 return true;
657 }
658 else
659 {
660 if( oth.nPos == nPos )
661 return true;
662 return false;
663 }
664 }
665
666 /**
667 * Iterator not equality comparison operator. Not the same?
668 */
669 bool operator!=( const const_iterator &oth )
670 {
671 return !(*this == oth );
672 }
673
674 /**
675 * Iterator assignment operator.
676 */
677 const_iterator operator=( const const_iterator &oth )
678 {
679 if( &hsh != &oth.hsh )
680 throw HashException(
681 "Cannot mix iterators from different hash objects.");
682 nPos = oth.nPos;
683 bFinished = oth.bFinished;
684 }
685
686 /**
687 * Iterator dereference operator... err.. get the value
688 *@returns (value_type &) The value behind this iterator.
689 */
690 const value &operator *() const
691 {
692 return hsh.getValueAtPos( nPos );
693 }
694
695 /**
696 * Get the key behind this iterator.
697 *@returns (key_type &) The key behind this iterator.
698 */
699 const key &getKey() const
700 {
701 return hsh.getKeyAtPos( nPos );
702 }
703
704 /**
705 * Get the value behind this iterator.
706 *@returs (value_type &) The value behind this iterator.
707 */
708 const value &getValue() const
709 {
710 return hsh.getValueAtPos( nPos );
711 }
712 };
713
714 /**
715 * Get an iterator pointing to the first item in the hash table.
716 *@returns (iterator) An iterator pointing to the first item in the
717 * hash table.
718 */
719 iterator begin()
376 { 720 {
377 nPos = hsh.getFirstPos( bFinished ); 721 return iterator( *this );
378 } 722 }
379 723
380 iterator( Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh, bool bDone ) : 724 const_iterator begin() const
381 hsh( hsh ),
382 nPos( 0 ),
383 bFinished( bDone )
384 { 725 {
726 return const_iterator( *this );
385 } 727 }
386 728
387 Hash<key, value, sizecalc, keyalloc, valuealloc, challoc> &hsh; 729 /**
388 uint32_t nPos; 730 * Get an iterator pointing to a point just past the last item in the
389 bool bFinished; 731 * hash table.
390 732 *@returns (iterator) An iterator pointing to a point just past the
391 public: 733 * last item in the hash table.
392 iterator operator++( int ) 734 */
735 iterator end()
393 { 736 {
394 if( bFinished == false ) 737 return iterator( *this, true );
395 nPos = hsh.getNextPos( nPos, bFinished );
396
397 return *this;
398 } 738 }
399 739
400 iterator operator++() 740 const_iterator end() const
401 { 741 {
402 if( bFinished == false ) 742 return const_iterator( *this, true );
403 nPos = hsh.getNextPos( nPos, bFinished );
404
405 return *this;
406 } 743 }
407 744
408 bool operator==( const iterator &oth ) 745 /**
746 * Get a list of all the keys in the hash table.
747 *@returns (std::list<key_type>) The list of keys in the hash table.
748 */
749 Bu::List<key> getKeys() const
409 { 750 {
410 if( bFinished != oth.bFinished ) 751 Bu::List<key> lKeys;
411 return false; 752
412 if( bFinished == true ) 753 for( uint32_t j = 0; j < nCapacity; j++ )
413 { 754 {
414 return true; 755 if( isFilled( j ) )
756 {
757 if( !isDeleted( j ) )
758 {
759 lKeys.append( aKeys[j] );
760 }
761 }
415 } 762 }
416 else 763
764 return lKeys;
765 }
766
767 protected:
768 virtual void onInsert() {}
769 virtual void onUpdate() {}
770 virtual void onDelete() {}
771 virtual void onReHash() {}
772
773 virtual void clearBits()
774 {
775 for( uint32_t j = 0; j < nKeysSize; j++ )
417 { 776 {
418 if( oth.nPos == nPos ) 777 bFilled[j] = bDeleted[j] = 0;
419 return true;
420 return false;
421 } 778 }
422 } 779 }
423 780
424 bool operator!=( const iterator &oth ) 781 virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash )
425 { 782 {
426 return !(*this == oth ); 783 bFilled[loc/32] |= (1<<(loc%32));
784 va.construct( &aValues[loc], v );
785 ka.construct( &aKeys[loc], k );
786 aHashCodes[loc] = hash;
787 nFilled++;
788 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
789 // nFilled, nDeleted, nCapacity );
427 } 790 }
428 791
429 iterator operator=( const iterator &oth ) 792 virtual void _erase( uint32_t loc )
430 { 793 {
431 if( &hsh != &oth.hsh ) 794 bDeleted[loc/32] |= (1<<(loc%32));
432 throw HashException( 795 va.destroy( &aValues[loc] );
433 "Cannot mix iterators from different hash objects."); 796 ka.destroy( &aKeys[loc] );
434 nPos = oth.nPos; 797 nDeleted++;
435 bFinished = oth.bFinished; 798 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
799 // nFilled, nDeleted, nCapacity );
436 } 800 }
437 801
438 std::pair<key,value> operator *() 802 virtual std::pair<key,value> getAtPos( uint32_t nPos )
803 {
804 return std::pair<key,value>(aKeys[nPos],aValues[nPos]);
805 }
806
807 virtual key &getKeyAtPos( uint32_t nPos )
439 { 808 {
440 return hsh.getAtPos( nPos ); 809 return aKeys[nPos];
441 } 810 }
442 811
443 key &getKey() 812 virtual const key &getKeyAtPos( uint32_t nPos ) const
444 { 813 {
445 return hsh.getKeyAtPos( nPos ); 814 return aKeys[nPos];
815 }
816
817 virtual value &getValueAtPos( uint32_t nPos )
818 {
819 return aValues[nPos];
820 }
821
822 virtual const value &getValueAtPos( uint32_t nPos ) const
823 {
824 return aValues[nPos];
446 } 825 }
447 826
448 value &getValue() 827 virtual uint32_t getFirstPos( bool &bFinished ) const
449 { 828 {
450 return hsh.getValueAtPos( nPos ); 829 for( uint32_t j = 0; j < nCapacity; j++ )
830 {
831 if( isFilled( j ) )
832 if( !isDeleted( j ) )
833 return j;
834 }
835
836 bFinished = true;
837 return 0;
451 } 838 }
452 };
453 839
454 iterator begin() 840 virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) const
455 { 841 {
456 return iterator( *this ); 842 for( uint32_t j = nPos+1; j < nCapacity; j++ )
457 } 843 {
458 844 if( isFilled( j ) )
459 iterator end() 845 if( !isDeleted( j ) )
460 { 846 return j;
461 return iterator( *this, true ); 847 }
462 }
463 848
464 std::list<key> getKeys() 849 bFinished = true;
465 { 850 return 0;
466 std::list<key> lKeys; 851 }
467 852
468 for( uint32_t j = 0; j < nCapacity; j++ ) 853 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true )
469 { 854 {
470 if( isFilled( j ) ) 855 uint32_t nCur = hash%nCapacity;
856
857 // First we scan to see if the key is already there, abort if we
858 // run out of probing room, or we find a non-filled entry
859 for( int8_t j = 0;
860 isFilled( nCur ) && j < 32;
861 nCur = (nCur + (1<<j))%nCapacity, j++
862 )
471 { 863 {
472 if( !isDeleted( j ) ) 864 // Is this the same hash code we were looking for?
865 if( hash == aHashCodes[nCur] )
473 { 866 {
474 lKeys.push_back( aKeys[j] ); 867 // Skip over deleted entries. Deleted entries are also filled,
868 // so we only have to do this check here.
869 if( isDeleted( nCur ) )
870 continue;
871
872 // Is it really the same key? (for safety)
873 if( __cmpHashKeys( aKeys[nCur], k ) == true )
874 {
875 bFill = true;
876 return nCur;
877 }
475 } 878 }
476 } 879 }
477 }
478 880
479 return lKeys; 881 // This is our insurance, if the table is full, then go ahead and
480 } 882 // rehash, then try again.
883 if( isFilled( nCur ) && rehash == true )
884 {
885 reHash( szCalc(getCapacity(), getFill(), getDeleted()) );
481 886
482protected: 887 // This is potentially dangerous, and could cause an infinite loop.
483 virtual void onInsert() {} 888 // Be careful writing probe, eh?
484 virtual void onUpdate() {} 889 return probe( hash, k, bFill );
485 virtual void onDelete() {} 890 }
486 virtual void onReHash() {}
487 891
488 virtual void clearBits() 892 bFill = false;
489 { 893 return nCur;
490 for( uint32_t j = 0; j < nKeysSize; j++ )
491 {
492 bFilled[j] = bDeleted[j] = 0;
493 } 894 }
494 } 895
495 896 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) const
496 virtual void fill( uint32_t loc, key &k, value &v, uint32_t hash )
497 {
498 bFilled[loc/32] |= (1<<(loc%32));
499 va.construct( &aValues[loc], v );
500 ka.construct( &aKeys[loc], k );
501 aHashCodes[loc] = hash;
502 nFilled++;
503 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
504 // nFilled, nDeleted, nCapacity );
505 }
506
507 virtual void _erase( uint32_t loc )
508 {
509 bDeleted[loc/32] |= (1<<(loc%32));
510 va.destroy( &aValues[loc] );
511 ka.destroy( &aKeys[loc] );
512 nDeleted++;
513 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
514 // nFilled, nDeleted, nCapacity );
515 }
516
517 virtual std::pair<key,value> getAtPos( uint32_t nPos )
518 {
519 return std::pair<key,value>(aKeys[nPos],aValues[nPos]);
520 }
521
522 virtual key &getKeyAtPos( uint32_t nPos )
523 {
524 return aKeys[nPos];
525 }
526
527 virtual value &getValueAtPos( uint32_t nPos )
528 {
529 return aValues[nPos];
530 }
531
532 virtual uint32_t getFirstPos( bool &bFinished )
533 {
534 for( uint32_t j = 0; j < nCapacity; j++ )
535 { 897 {
536 if( isFilled( j ) ) 898 uint32_t nCur = hash%nCapacity;
537 if( !isDeleted( j ) ) 899
538 return j; 900 // First we scan to see if the key is already there, abort if we
539 } 901 // run out of probing room, or we find a non-filled entry
902 for( int8_t j = 0;
903 isFilled( nCur ) && j < 32;
904 nCur = (nCur + (1<<j))%nCapacity, j++
905 )
906 {
907 // Is this the same hash code we were looking for?
908 if( hash == aHashCodes[nCur] )
909 {
910 // Skip over deleted entries. Deleted entries are also filled,
911 // so we only have to do this check here.
912 if( isDeleted( nCur ) )
913 continue;
914
915 // Is it really the same key? (for safety)
916 if( __cmpHashKeys( aKeys[nCur], k ) == true )
917 {
918 bFill = true;
919 return nCur;
920 }
921 }
922 }
540 923
541 bFinished = true; 924 bFill = false;
542 return 0; 925 return nCur;
543 } 926 }
544 927
545 virtual uint32_t getNextPos( uint32_t nPos, bool &bFinished ) 928 void reHash( uint32_t nNewSize )
546 {
547 for( uint32_t j = nPos+1; j < nCapacity; j++ )
548 { 929 {
549 if( isFilled( j ) ) 930 //printf("---REHASH---");
550 if( !isDeleted( j ) ) 931 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
551 return j; 932 // nFilled, nDeleted, nCapacity );
552 } 933
934 // Save all the old data
935 uint32_t nOldCapacity = nCapacity;
936 uint32_t *bOldFilled = bFilled;
937 uint32_t *aOldHashCodes = aHashCodes;
938 uint32_t nOldKeysSize = nKeysSize;
939 uint32_t *bOldDeleted = bDeleted;
940 value *aOldValues = aValues;
941 key *aOldKeys = aKeys;
942
943 // Calculate new sizes
944 nCapacity = nNewSize;
945 nKeysSize = bitsToBytes( nCapacity );
946
947 // Allocate new memory + prep
948 bFilled = ca.allocate( nKeysSize );
949 bDeleted = ca.allocate( nKeysSize );
950 clearBits();
553 951
554 bFinished = true; 952 aHashCodes = ca.allocate( nCapacity );
555 return 0; 953 aKeys = ka.allocate( nCapacity );
556 } 954 aValues = va.allocate( nCapacity );
557 955
558 uint32_t probe( uint32_t hash, key k, bool &bFill, bool rehash=true ) 956 nDeleted = nFilled = 0;
559 {
560 uint32_t nCur = hash%nCapacity;
561 957
562 // First we scan to see if the key is already there, abort if we 958 // Re-insert all of the old data (except deleted items)
563 // run out of probing room, or we find a non-filled entry 959 for( uint32_t j = 0; j < nOldCapacity; j++ )
564 for( int8_t j = 0;
565 isFilled( nCur ) && j < 32;
566 nCur = (nCur + (1<<j))%nCapacity, j++
567 )
568 {
569 // Is this the same hash code we were looking for?
570 if( hash == aHashCodes[nCur] )
571 { 960 {
572 // Skip over deleted entries. Deleted entries are also filled, 961 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
573 // so we only have to do this check here. 962 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
574 if( isDeleted( nCur ) ) 963 {
575 continue; 964 insert( aOldKeys[j], aOldValues[j] );
965 }
966 }
576 967
577 // Is it really the same key? (for safety) 968 // Delete all of the old data
578 if( __cmpHashKeys( aKeys[nCur], k ) == true ) 969 for( uint32_t j = 0; j < nOldCapacity; j++ )
970 {
971 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 )
579 { 972 {
580 bFill = true; 973 va.destroy( &aOldValues[j] );
581 return nCur; 974 ka.destroy( &aOldKeys[j] );
582 } 975 }
583 } 976 }
977 va.deallocate( aOldValues, nOldCapacity );
978 ka.deallocate( aOldKeys, nOldCapacity );
979 ca.deallocate( bOldFilled, nOldKeysSize );
980 ca.deallocate( bOldDeleted, nOldKeysSize );
981 ca.deallocate( aOldHashCodes, nOldCapacity );
584 } 982 }
585 983
586 // This is our insurance, if the table is full, then go ahead and 984 virtual bool isFilled( uint32_t loc ) const
587 // rehash, then try again.
588 if( isFilled( nCur ) && rehash == true )
589 { 985 {
590 reHash( szCalc(getCapacity(), getFill(), getDeleted()) ); 986 return (bFilled[loc/32]&(1<<(loc%32)))!=0;
987 }
591 988
592 // This is potentially dangerous, and could cause an infinite loop. 989 virtual bool isDeleted( uint32_t loc ) const
593 // Be careful writing probe, eh? 990 {
594 return probe( hash, k, bFill ); 991 return (bDeleted[loc/32]&(1<<(loc%32)))!=0;
595 } 992 }
596 993
597 bFill = false; 994 protected:
598 return nCur; 995 uint32_t nCapacity;
599 } 996 uint32_t nFilled;
997 uint32_t nDeleted;
998 uint32_t *bFilled;
999 uint32_t *bDeleted;
1000 uint32_t nKeysSize;
1001 key *aKeys;
1002 value *aValues;
1003 uint32_t *aHashCodes;
1004 valuealloc va;
1005 keyalloc ka;
1006 challoc ca;
1007 sizecalc szCalc;
1008 };
600 1009
601 void reHash( uint32_t nNewSize ) 1010 template<> uint32_t __calcHashCode<int>( const int &k );
602 { 1011 template<> bool __cmpHashKeys<int>( const int &a, const int &b );
603 //printf("---REHASH---");
604 //printf("Filled: %d, Deleted: %d, Capacity: %d\n",
605 // nFilled, nDeleted, nCapacity );
606
607 // Save all the old data
608 uint32_t nOldCapacity = nCapacity;
609 uint32_t *bOldFilled = bFilled;
610 uint32_t *aOldHashCodes = aHashCodes;
611 uint32_t nOldKeysSize = nKeysSize;
612 uint32_t *bOldDeleted = bDeleted;
613 value *aOldValues = aValues;
614 key *aOldKeys = aKeys;
615
616 // Calculate new sizes
617 nCapacity = nNewSize;
618 nKeysSize = bitsToBytes( nCapacity );
619
620 // Allocate new memory + prep
621 bFilled = ca.allocate( nKeysSize );
622 bDeleted = ca.allocate( nKeysSize );
623 clearBits();
624 1012
625 aHashCodes = ca.allocate( nCapacity ); 1013 template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k );
626 aKeys = ka.allocate( nCapacity ); 1014 template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b );
627 aValues = va.allocate( nCapacity );
628 1015
629 nDeleted = nFilled = 0; 1016 template<> uint32_t __calcHashCode<const char *>( const char * const &k );
1017 template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b );
630 1018
631 // Re-insert all of the old data (except deleted items) 1019 template<> uint32_t __calcHashCode<char *>( char * const &k );
632 for( uint32_t j = 0; j < nOldCapacity; j++ ) 1020 template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b );
633 {
634 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 &&
635 (bOldDeleted[j/32]&(1<<(j%32)))==0 )
636 {
637 insert( aOldKeys[j], aOldValues[j] );
638 }
639 }
640 1021
641 // Delete all of the old data 1022 template<> uint32_t __calcHashCode<std::string>( const std::string &k );
642 for( uint32_t j = 0; j < nOldCapacity; j++ ) 1023 template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b );
1024
1025 /*
1026 template<typename key, typename value>
1027 Archive &operator<<( Archive &ar, Hash<key,value> &h )
1028 {
1029 ar << h.size();
1030 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
643 { 1031 {
644 if( (bOldFilled[j/32]&(1<<(j%32)))!=0 && 1032 std::pair<key,value> p = *i;
645 (bOldDeleted[j/32]&(1<<(j%32)))==0 ) 1033 ar << p.first << p.second;
646 {
647 va.destroy( &aOldValues[j] );
648 ka.destroy( &aOldKeys[j] );
649 }
650 } 1034 }
651 va.deallocate( aOldValues, nOldCapacity );
652 ka.deallocate( aOldKeys, nOldCapacity );
653 ca.deallocate( bOldFilled, nOldKeysSize );
654 ca.deallocate( bOldDeleted, nOldKeysSize );
655 ca.deallocate( aOldHashCodes, nOldCapacity );
656 }
657 1035
658 virtual bool isFilled( uint32_t loc ) const 1036 return ar;
659 {
660 return (bFilled[loc/32]&(1<<(loc%32)))!=0;
661 } 1037 }
662 1038
663 virtual bool isDeleted( uint32_t loc ) 1039 template<typename key, typename value>
1040 Archive &operator>>( Archive &ar, Hash<key,value> &h )
664 { 1041 {
665 return (bDeleted[loc/32]&(1<<(loc%32)))!=0; 1042 h.clear();
666 } 1043 uint32_t nSize;
1044 ar >> nSize;
667 1045
668protected: 1046 for( uint32_t j = 0; j < nSize; j++ )
669 uint32_t nCapacity; 1047 {
670 uint32_t nFilled; 1048 key k; value v;
671 uint32_t nDeleted; 1049 ar >> k >> v;
672 uint32_t *bFilled; 1050 h.insert( k, v );
673 uint32_t *bDeleted; 1051 }
674 uint32_t nKeysSize;
675 key *aKeys;
676 value *aValues;
677 uint32_t *aHashCodes;
678 valuealloc va;
679 keyalloc ka;
680 challoc ca;
681 sizecalc szCalc;
682};
683
684template<> uint32_t __calcHashCode<int>( const int &k );
685template<> bool __cmpHashKeys<int>( const int &a, const int &b );
686
687template<> uint32_t __calcHashCode<unsigned int>( const unsigned int &k );
688template<> bool __cmpHashKeys<unsigned int>( const unsigned int &a, const unsigned int &b );
689
690template<> uint32_t __calcHashCode<const char *>( const char * const &k );
691template<> bool __cmpHashKeys<const char *>( const char * const &a, const char * const &b );
692
693template<> uint32_t __calcHashCode<char *>( char * const &k );
694template<> bool __cmpHashKeys<char *>( char * const &a, char * const &b );
695
696template<> uint32_t __calcHashCode<std::string>( const std::string &k );
697template<> bool __cmpHashKeys<std::string>( const std::string &a, const std::string &b );
698
699template<> uint32_t __calcHashCode<Hashable>( const Hashable &k );
700template<> bool __cmpHashKeys<Hashable>( const Hashable &a, const Hashable &b );
701
702template<typename key, typename value>
703Serializer &operator<<( Serializer &ar, Hash<key,value> &h )
704{
705 ar << h.size();
706 for( typename Hash<key,value>::iterator i = h.begin(); i != h.end(); i++ )
707 {
708 std::pair<key,value> p = *i;
709 ar << p.first << p.second;
710 }
711 1052
712 return ar; 1053 return ar;
713} 1054 }*/
714 1055
715template<typename key, typename value> 1056 /*
716Serializer &operator>>( Serializer &ar, Hash<key,value> &h ) 1057 template<typename key, typename value>
717{ 1058 Serializer &operator&&( Serializer &ar, Hash<key,value> &h )
718 h.clear();
719 uint32_t nSize;
720 ar >> nSize;
721
722 for( uint32_t j = 0; j < nSize; j++ )
723 { 1059 {
724 key k; value v; 1060 if( ar.isLoading() )
725 ar >> k >> v; 1061 {
726 h.insert( k, v ); 1062 return ar >> h;
727 } 1063 }
728 1064 else
729 return ar; 1065 {
730} 1066 return ar << h;
731 1067 }
732template<typename key, typename value> 1068 }*/
733Serializer &operator&&( Serializer &ar, Hash<key,value> &h )
734{
735 if( ar.isLoading() )
736 {
737 return ar >> h;
738 }
739 else
740 {
741 return ar << h;
742 }
743} 1069}
744 1070
745#endif 1071#endif
diff --git a/src/hashable.cpp b/src/hashable.cpp
deleted file mode 100644
index 8565956..0000000
--- a/src/hashable.cpp
+++ /dev/null
@@ -1 +0,0 @@
1#include "hashable.h"
diff --git a/src/hashable.h b/src/hashable.h
deleted file mode 100644
index 98643d5..0000000
--- a/src/hashable.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef HASHABLE_H
2#define HASHABLE_H
3
4class Hashable
5{
6public:
7 virtual ~Hashable() {};
8 virtual unsigned long int getHashCode() = 0;
9 virtual bool compareForHash( Hashable &other ) = 0;
10};
11
12#endif
diff --git a/src/hashfunction.cpp b/src/hashfunction.cpp
deleted file mode 100644
index 51f2259..0000000
--- a/src/hashfunction.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
1#include "hashfunction.h"
2
3HashFunction::HashFunction()
4{
5}
6
7HashFunction::~HashFunction()
8{
9}
10
diff --git a/src/hashfunction.h b/src/hashfunction.h
deleted file mode 100644
index cbcf70f..0000000
--- a/src/hashfunction.h
+++ /dev/null
@@ -1,48 +0,0 @@
1#ifndef HASH_FUNCTION
2#define HASH_FUNCTION
3
4/** This represents the shell of a hash function. It must be aggregated in
5 * order to be used. Please read about it's two functions for specificatins
6 * relating to what values will be passed to them and what they should return
7 * for creating your own hash functions.
8 *@author Mike Buland.
9 */
10class HashFunction
11{
12public:
13 /**
14 * Standard Constructor.
15 */
16 HashFunction();
17
18 /**
19 * Standard Deconstructor.
20 */
21 virtual ~HashFunction();
22
23 /** Hashes the value represnted by id. This must return a fairly unique
24 * number in the range of 0-2^32 (or whatever the size of an unsigned long
25 * is on your system) based on the id given. The faster the number changes
26 * the better in a general sence. The return value will be the index
27 * (after probing takes place) to the data assosiated with an id, so this
28 * function should always produce the same number for any given id.
29 *@param id The identifier to use to create a unique numerical identifier.
30 *@returns A mostly unique numerical identifier generated using the given
31 * id.
32 */
33 virtual unsigned long int hash( const void *id ) = 0;
34
35 /** This function must compare two ids in the format that this hashfunction
36 * accepts. For example, if the hash function hashes strings it should
37 * probably { return strcmp( id1, id2 ) == 0 }.
38 *@param id1 One value to use in the comparison
39 *@param id2 Another value to use in the comparison
40 *@returns True if the two values match, otherwise false.
41 */
42 virtual bool cmpIDs( const void *id1, const void *id2 ) = 0;
43
44// virtual void *createPersistantID( const void *id ) = 0;
45// virtual void destroyPersistantID( const void *id ) = 0;
46};
47
48#endif
diff --git a/src/hashfunctioncasestring.cpp b/src/hashfunctioncasestring.cpp
deleted file mode 100644
index 6361f45..0000000
--- a/src/hashfunctioncasestring.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1#include <stdlib.h>
2#include <string.h>
3#include <ctype.h>
4#include "hashfunctioncasestring.h"
5
6HashFunctionCaseString::HashFunctionCaseString()
7{
8}
9
10HashFunctionCaseString::~HashFunctionCaseString()
11{
12}
13
14unsigned long int HashFunctionCaseString::hash( const void *id )
15{
16 const char *str = (const char *)id;
17 unsigned long int nPos = 0;
18 for( int j = 0; str[j] != '\0'; j++ )
19 {
20 nPos = tolower(str[j]) + (nPos << 6) + (nPos << 16) - nPos;
21// nPos += nPos<<16|(((unsigned long int)tolower(str[j]))<<((j*7)%24));
22 }
23 return nPos;
24}
25
26bool HashFunctionCaseString::cmpIDs( const void *id1, const void *id2 )
27{
28 const char *str1 = (const char *)id1;
29 const char *str2 = (const char *)id2;
30
31 int j;
32 for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ )
33 {
34 if( tolower(str1[j]) != tolower(str2[j]) )
35 return false;
36 }
37 return (str1[j]==str2[j]);
38}
39
diff --git a/src/hashfunctioncasestring.h b/src/hashfunctioncasestring.h
deleted file mode 100644
index 7816a1b..0000000
--- a/src/hashfunctioncasestring.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef HASH_FUNCTION_CASE_STRING
2#define HASH_FUNCTION_CASE_STRING
3
4#include "hashfunction.h"
5
6/** A hash function for string data. This hash function does strings, but is
7 * actually generalized to handle any binary stream of characters terminated
8 * by a null character. This is different than HashFunctionString in that
9 * this does comparisons without regaurd to case.
10 *@author Mike Buland.
11 */
12class HashFunctionCaseString : public HashFunction
13{
14public:
15 /**
16 * Standard Constructor.
17 */
18 HashFunctionCaseString();
19
20 /**
21 * Standard Deconstructor.
22 */
23 virtual ~HashFunctionCaseString();
24 unsigned long int hash( const void *id );
25 bool cmpIDs( const void *id1, const void *id2 );
26};
27
28#endif
diff --git a/src/hashfunctionint.cpp b/src/hashfunctionint.cpp
deleted file mode 100644
index 4bd0feb..0000000
--- a/src/hashfunctionint.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
1#include "hashfunctionint.h"
2
3HashFunctionInt::HashFunctionInt()
4{
5}
6
7HashFunctionInt::~HashFunctionInt()
8{
9}
10
11unsigned long int HashFunctionInt::hash( const void *id )
12{
13 return (unsigned long)(id);
14}
15
16bool HashFunctionInt::cmpIDs( const void *id1, const void *id2 )
17{
18 return (unsigned long)(id1) == (unsigned long)(id2);
19}
20
diff --git a/src/hashfunctionint.h b/src/hashfunctionint.h
deleted file mode 100644
index 0fbc764..0000000
--- a/src/hashfunctionint.h
+++ /dev/null
@@ -1,26 +0,0 @@
1#ifndef HASH_FUNCTION_INT
2#define HASH_FUNCTION_INT
3
4#include "hashfunction.h"
5
6/** A hash function for integer data. Really, this does almost nothing except
7 * ensure we're dealing with positive indicies.
8 *@author Mike Buland.
9 */
10class HashFunctionInt : public HashFunction
11{
12public:
13 /**
14 * Standard Constructor.
15 */
16 HashFunctionInt();
17
18 /**
19 * Standard Deconstructor.
20 */
21 virtual ~HashFunctionInt();
22 unsigned long int hash( const void *id );
23 bool cmpIDs( const void *id1, const void *id2 );
24};
25
26#endif
diff --git a/src/hashfunctionstring.cpp b/src/hashfunctionstring.cpp
deleted file mode 100644
index bd14643..0000000
--- a/src/hashfunctionstring.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
1#include "hashfunctionstring.h"
2#ifndef NULL
3#define NULL ((void *) 0)
4#endif
5
6HashFunctionString::HashFunctionString()
7{
8}
9
10HashFunctionString::~HashFunctionString()
11{
12}
13
14unsigned long int HashFunctionString::hash( const void *id )
15{
16 if (id == NULL)
17 {
18 return 0;
19 }
20
21 unsigned long int nPos = 0;
22 for( const char *s = (const char *)id; *s; s++ )
23 {
24 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
25 }
26 return nPos;
27}
28
29bool HashFunctionString::cmpIDs( const void *id1, const void *id2 )
30{
31 if (id1 == NULL || id2 == NULL)
32 {
33 return false;
34 }
35 if (id1 == id2)
36 {
37 return true;
38 }
39
40 const char *str1 = (const char *)id1;
41 const char *str2 = (const char *)id2;
42
43 int j;
44 for( j = 0; str1[j] != '\0' && str2[j] != '\0'; j++ )
45 {
46 if( str1[j] != str2[j] )
47 return false;
48 }
49 return (str1[j]==str2[j]);
50}
51
diff --git a/src/hashfunctionstring.h b/src/hashfunctionstring.h
deleted file mode 100644
index 7d2a1a6..0000000
--- a/src/hashfunctionstring.h
+++ /dev/null
@@ -1,27 +0,0 @@
1#ifndef HASH_FUNCTION_STRING
2#define HASH_FUNCTION_STRING
3
4#include "hashfunction.h"
5
6/** A hash function for string data. This hash function does strings, but is
7 * actually generalized to handle any binary stream of characters terminated
8 * by a null character.
9 *@author Mike Buland.
10 */
11class HashFunctionString : public HashFunction
12{
13public:
14 /**
15 * Standard Constructor.
16 */
17 HashFunctionString();
18
19 /**
20 * Standard Deconstructor.
21 */
22 virtual ~HashFunctionString();
23 unsigned long int hash( const void *id );
24 bool cmpIDs( const void *id1, const void *id2 );
25};
26
27#endif
diff --git a/src/hashtable.cpp b/src/hashtable.cpp
deleted file mode 100644
index dbcd964..0000000
--- a/src/hashtable.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
1#include <string.h>
2#include <stdio.h>
3#include <math.h>
4
5#include "hashtable.h"
6
7HashTable::HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes )
8{
9 hFunc = hNewFunc;
10 nTableSize = nextPrime( nInitSize );
11 aTable = new HashNode[nTableSize];
12 //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n");
13 nSize = 0;
14 nFilled = 0;
15 this->bAllowDupes = bAllowDupes;
16}
17
18HashTable::~HashTable()
19{
20 delete[] aTable;
21 delete hFunc;
22}
23
24void HashTable::set( int j, const void *newID, const void *newData )
25{
26 if( newData == NULL )
27 {
28 printf("Inserting NULL data is indestinguishable from uninserted data!\n");
29 }
30 aTable[j].id = newID;
31 aTable[j].data = newData;
32}
33
34void HashTable::clear()
35{
36 memset( aTable, 0, sizeof(HashNode) * nTableSize );
37}
38
39bool HashTable::isFilled( int j )
40{
41 return (aTable[j].id != NULL)||(aTable[j].bDeleted);
42}
43
44void HashTable::reHash( unsigned long int nNewSize )
45{
46 HashNode *aOldTable = aTable;
47 unsigned long int oldSize = nTableSize;
48
49 // If the table can still be used if we just get rid of deleted items, don't
50 // change the size of the table, otherwise, go ahead and use the number
51 // passed in.
52 if( nSize > nTableSize>>1 )
53 {
54 nTableSize = nextPrime( nNewSize );
55 }
56
57 aTable = newTable( nTableSize );
58 //for( int j = 0; j < nTableSize; j++ ) if( aTable[j].id || aTable[j].data || aTable[j].bDeleted ) printf("Unclean entry\n");
59
60 nSize = 0;
61 nFilled = 0;
62
63 for( unsigned long int j = 0; j < oldSize; j++ )
64 {
65 if( aOldTable[j].id != NULL && aOldTable[j].bDeleted == false )
66 {
67 insert( aOldTable[j].id, aOldTable[j].data );
68 }
69 }
70
71 delete[] aOldTable;
72}
73
74unsigned long int HashTable::probe( unsigned long int nStart, const void *id )
75{
76 int nHash = nStart;
77 nStart = nStart%nTableSize;
78 if( bAllowDupes == true )
79 {
80 for(
81 unsigned long int j=0;
82 isFilled( nStart ) && j < 32;
83 nStart = (nStart+(1<<j))%nTableSize, j++
84 );
85
86 /**
87 * This is an ugly little hack. If the hash table is too full in allow-
88 * dups mode we have to fall back on a linear search, otherwise you can
89 * only get up to 32 entries with the same name.
90 */
91 if( isFilled( nStart ) )
92 {
93 unsigned long int nOldStart = nStart;
94 for(
95 nStart++;
96 isFilled( nStart ) && nStart != nOldStart;
97 nStart = (nStart+1)%nTableSize
98 );
99 }
100 }
101 else
102 {
103 for(
104 unsigned long int j=0;
105 isFilled( nStart ) && j < 32;
106 nStart = (nStart+(1<<j))%nTableSize, j++
107 )
108 {
109 if( isFilled( nStart ) )
110 {
111 if( hFunc->cmpIDs( aTable[nStart].id, id ) == true &&
112 aTable[nStart].bDeleted == false )
113 {
114 return nStart;
115 }
116 }
117 }
118 }
119 // This is our insurance, if the table is full, then go ahead and rehash,
120 // then try again.
121 if( isFilled( nStart ) )
122 {
123 reHash( getCapacity()*2 );
124 return probe( nHash, id );
125 }
126 return nStart;
127}
128
129HashTable::HashNode *HashTable::newTable( unsigned long int nNewSize )
130{
131 return new HashNode[nNewSize];
132}
133
134#ifdef HASH_DEBUG_VIS
135void HashTable::printDebugLine( const char *exData )
136{
137 char *buf = new char[getCapacity()+3];
138 int j;
139 buf[0] = '[';
140 for( j = 0; j < getCapacity(); j++ )
141 {
142 buf[j+1] = (aTable[j].bDeleted)?('X'):((isFilled( j ))?('#'):('-'));
143 }
144 buf[j+1] = ']';
145 buf[j+2] = '\0';
146 printf("%s %s\n", buf, exData );
147 delete[] buf;
148}
149#endif
150
151bool HashTable::insert( const void *id, const void *data )
152{
153 unsigned long int nPos = probe( hFunc->hash( id ), id )%nTableSize;
154
155 if( bAllowDupes == true )
156 {
157 if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false )
158 {
159 set( nPos, id, data );
160#ifdef HASH_DEBUG_VIS
161 printDebugLine( (const char *)id );
162#endif
163 nSize++;
164 nFilled++;
165 return true;
166 }
167 else
168 {
169 return false;
170 }
171 }
172 else
173 {
174 if( aTable[nPos].id == NULL && aTable[nPos].bDeleted == false )
175 {
176 set( nPos, id, data );
177#ifdef HASH_DEBUG_VIS
178 printDebugLine( (const char *)id );
179#endif
180 nSize++;
181 nFilled++;
182 return true;
183 }
184 else if( hFunc->cmpIDs( aTable[nPos].id, id ) == true )
185 {
186 set( nPos, id, data );
187#ifdef HASH_DEBUG_VIS
188 printDebugLine( (const char *)id );
189#endif
190 return true;
191 }
192 else
193 {
194 return false;
195 }
196 }
197}
198
199const void *HashTable::get( const void *id, unsigned long int nSkip )
200{
201 unsigned long int nPos = hFunc->hash( id )%nTableSize;
202
203 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
204 {
205 if( !isFilled( nPos ) ) return NULL;
206 if( aTable[nPos].bDeleted == false )
207 {
208 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
209 {
210 if( nSkip == 0 )
211 {
212 return aTable[nPos].data;
213 }
214 else
215 {
216 nSkip--;
217 }
218 }
219 }
220 }
221
222 if( bAllowDupes )
223 {
224 unsigned long int nOldPos = nPos;
225 for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize )
226 {
227 if( !isFilled( nPos ) ) return NULL;
228 if( aTable[nPos].bDeleted == false )
229 {
230 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
231 {
232 if( nSkip == 0 )
233 {
234 return aTable[nPos].data;
235 }
236 else
237 {
238 nSkip--;
239 }
240 }
241 }
242 }
243 }
244
245 return NULL;
246}
247
248const void *HashTable::getKey( const void *id, unsigned long int nSkip )
249{
250 unsigned long int nPos = hFunc->hash( id )%nTableSize;
251
252 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
253 {
254 if( !isFilled( nPos ) ) return NULL;
255 if( aTable[nPos].bDeleted == false )
256 {
257 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
258 {
259 if( nSkip == 0 )
260 {
261 return aTable[nPos].id;
262 }
263 else
264 {
265 nSkip--;
266 }
267 }
268 }
269 }
270
271 if( bAllowDupes )
272 {
273 unsigned long int nOldPos = nPos;
274 for( nPos++; nPos != nOldPos; nPos=(nPos+1)%nTableSize )
275 {
276 if( !isFilled( nPos ) ) return NULL;
277 if( aTable[nPos].bDeleted == false )
278 {
279 if( hFunc->cmpIDs( id, aTable[nPos].id ) )
280 {
281 if( nSkip == 0 )
282 {
283 return aTable[nPos].id;
284 }
285 else
286 {
287 nSkip--;
288 }
289 }
290 }
291 }
292 }
293
294 return NULL;
295}
296
297void *HashTable::getFirstItemPos()
298{
299 HashPos *pos = new HashPos;
300 return pos;
301}
302
303const void *HashTable::getItemData( void *xPos )
304{
305 return aTable[((HashPos *)xPos)->nPos].data;
306}
307
308const void *HashTable::getItemID( void *xPos )
309{
310 return aTable[((HashPos *)xPos)->nPos].id;
311}
312
313void *HashTable::getNextItemPos( void *xPos )
314{
315 HashPos *pos = (HashPos *)xPos;
316 if( pos->bStarted == false )
317 {
318 pos->bStarted = true;
319 pos->nPos = 0;
320 }
321 else
322 {
323 pos->nPos++;
324 }
325 if( pos->nPos < nTableSize )
326 {
327 for( ; pos->nPos < nTableSize; pos->nPos++ )
328 {
329 if( isFilled( pos->nPos ) &&
330 aTable[pos->nPos].bDeleted == false )
331 {
332 return xPos;
333 }
334 }
335 }
336
337 delete pos;
338
339 return NULL;
340}
341
342// Big-O sqrt(n)
343// Change this to be erethpothynies table with a storage
344// lookup later on.
345bool HashTable::isPrime (int num)
346{
347 if (num == 2) // the only even prime
348 return true;
349 else if (num % 2 == 0) // other even numbers are composite
350 return false;
351 else
352 {
353 //bool prime = true;
354 int divisor = 3;
355 int upperLimit = static_cast<int>(sqrt(num) + 1);
356 while (divisor <= upperLimit)
357 {
358 if (num % divisor == 0)
359 return false;
360 // prime = false;
361 divisor +=2;
362 }
363 return true;
364 }
365}
366
367// Big-O n^(3/2)
368int HashTable::nextPrime( int base )
369{
370 int nPrime;
371 for( nPrime = base; isPrime( nPrime ) == false; nPrime++ );
372 return nPrime;
373}
374
375unsigned long int HashTable::getCapacity()
376{
377 return nTableSize;
378}
379
380unsigned long int HashTable::getSize()
381{
382 return nSize;
383}
384
385double HashTable::getLoad()
386{
387 return (double)(nFilled)/(double)(nTableSize);
388}
389
390const void *HashTable::operator[](const void *id)
391{
392 return get( id );
393}
394
395bool HashTable::del( const void *id, int nSkip )
396{
397 unsigned long int nPos = hFunc->hash( id )%nTableSize;
398
399 for( unsigned long int j=0; j < 32; nPos = (nPos+(1<<j))%nTableSize, j++ )
400 {
401 if( !isFilled( nPos ) ) return false;
402 //printf("0x%08X \"%s\" == 0x%08X \"%s\" (%d)\n", id, id, aTable[nPos].id, aTable[nPos].id, nPos );
403 if( hFunc->cmpIDs( id, aTable[nPos].id ) &&
404 aTable[nPos].bDeleted == false )
405 {
406 if( nSkip == 0 )
407 {
408 aTable[nPos].bDeleted = true;
409 nSize--;
410#ifdef HASH_DEBUG_VIS
411 printDebugLine( (const char *)id );
412#endif
413 return true;
414 }
415 else
416 {
417 nSkip--;
418 }
419 }
420 }
421
422 return false;
423}
424
diff --git a/src/hashtable.h b/src/hashtable.h
deleted file mode 100644
index 179b694..0000000
--- a/src/hashtable.h
+++ /dev/null
@@ -1,308 +0,0 @@
1/**\hashtable.h
2 * Describes the HashFunction, HashFunctionString, and HashTable classes. It
3 * was just easier to put them all in one set of files.
4 *@author Mike Buland
5 */
6
7#ifndef HASH_TABLE_H
8#define HASH_TABLE_H
9
10//Uncomment this line to see a cool text-mode visualization of what's going on
11//#define HASH_DEBUG_VIS 1
12
13#include <stdlib.h>
14#include <string.h>
15#include <ctype.h>
16
17#include "hashfunction.h"
18
19/**
20 * A simple yet flexable hash-table. This uses several tricks to help ensure
21 * that the table is always running at maximum efficiency. You no longer have
22 * to specify a "danger fill level" when more space is needed a rehash is
23 * automatically trigered. Deleting elements is fully supported, as well as
24 * duplicate elements. To work with and allow duplicates simple construct your
25 * HashTable the way you normally would, but when deleting or getting elements
26 * you can specify a skip value. This effectively allows you to treat elements
27 * with duplicate ID's as though they were in a zero-based array. The first
28 * element inserted with a given ID would be at skip zero, the next at skip 1
29 * and so on. This allows you to quickly search for elements with duplicate
30 * names, just stop when you get a null for a skip number, i.e.
31 * <pre>
32 * for( int j = 0;; j++ )
33 * {
34 * void *pData = hash.get( myID, j );
35 * if( !pData ) break;
36 * // Do something interesting with pData
37 * }
38 * </pre>
39 * There are new features in this HashTable that also allow for memory saving
40 * when dealing with systems where many elements are being deleted from the
41 * table. In those cases the elements deleted cannot be simply deleted, instead
42 * they have to be marked as deleted and hidden from the user, but maintained in
43 * the table so that future hashing operations don't fail. When rehashing
44 * occurs all elements marked as deleted are quietly removed. In these cases,
45 * if the number of deleted items would free enough space in the table for the
46 * table to be used efficiently without resizing, it is left the same size and
47 * rehashing is performed effectively in place, allowing the deleted items to
48 * be removed.
49 * <br>
50 * For info on adding new hashing algorithms, please see the HashFunction class.
51 *@author Mike Buland
52 *@todo Fix probing for tables that allow duplicates, and delete an item, then
53 * insert an item with the same name.
54 */
55class HashTable
56{
57public:
58 /** Constructs a hash table.
59 *@param hNewFunc A pointer to a hashfunction class to use. If this is
60 * null the default general string type will be used.
61 *@param nInitSize The initial size of the hashtable.
62 *@param bAllowDupes Setting this value to true allows the system to
63 * insert more than one copy of any given key. This can be tricky, and
64 * will require you to use the nSkip parameter on the get function.
65 */
66 HashTable( HashFunction *hNewFunc, unsigned long int nInitSize, bool bAllowDupes=false );
67
68 /**
69 * Destroys the hashtable, cleaning up all internal storage, but not stored
70 * elements. Also deletes the HashFunction passed in in the constructor.
71 */
72 virtual ~HashTable();
73
74 /** Inserts an item into the hashtable. This function will trigger a
75 * rehash if adding another item would force the table's load factor over
76 * the danger level.
77 *@param id used to find the data later.
78 *@param data The data item to insert into the table with the identifier
79 * id
80 *@returns True if insertion was successfull, and false if it failed.
81 */
82 bool insert( const void *id, const void *data );
83
84 /** Gets an item in the hashtable based on the id of that item. If there
85 * is more than one item with the same id you can use the nSkip parameter
86 * to access all of them.
87 *@param id The id of the item you're trying to find.
88 *@param nSkip The number of items with that id to skip before returning
89 * with the requested item.
90 *@returns A pointer to the data stored at the given id.
91 */
92 const void *get( const void *id, unsigned long int nSkip=0 );
93
94 const void *getKey( const void *id, unsigned long int nSkip=0 );
95
96 /** Gets the total capacity of the hashtable. This is actually the number
97 * of total positions available inside the hashtable at the moment. This
98 * will change when the hashtable's load exceeds the danger level.
99 * Please note that this is NOT the actual amount of space available.
100 * In reality you can only access about 45-50 percent of that space.
101 *@returns The total capacity.
102 */
103 unsigned long int getCapacity();
104
105 /** Gets the number of filled in items in the hash table. This is roughly
106 * equivelent to the getSize function assosiated with the Lists.
107 *@returns The number of filled in items in the hash table.
108 */
109 unsigned long int getSize();
110
111 /** Gets the load (percentage) of filled in items in the table. This is
112 * technically the size divided by the capacity, but is definately usefull
113 * since it's required to check if it's time to rehash.
114 *@returns The table load in the range 0.0 to 1.0
115 */
116 double getLoad();
117
118 /** Sets up an xPos object for use indexing the items in the table. Call
119 * this first and follow the directions for getNextItemPos below to
120 * iterate through every item in the table, while avoiding the empty
121 * spaces.
122 *@returns A pointer to a xPos object telling the hashtable where to find
123 * the item you're looking at.
124 */
125 void *getFirstItemPos();
126
127 /** Get the item's data that is being pointed to by xPos. This is only
128 * valid after xPos was created using getFirstItemPos and getNextItemPos
129 * was called at least once.
130 *@param xPos supplied by getFirstItemPos.
131 *@returns The key value that was used to insert the data into the table.
132 */
133 const void *getItemData( void *xPos );
134
135 /** Get the item's ID that is being pointed to by xPos. This is only
136 * valid after xPos was created using getFirstItemPos and getNextItemPos
137 * was called at least once.
138 *@param xPos supplied by getFirstItemPos.
139 *@returns The key value that was used to insert the data into the table.
140 */
141 const void *getItemID( void *xPos );
142
143 /** Used for iterating through a hash table sequentially. This will
144 * update the xPos pointer to point to the next time, all ready to
145 * be accessed with getItemID and getItemData. This must be called at
146 * least once before xPos is meaningful, and will return a NULL when it
147 * has reached the last item.
148 *@param xPos This must be an object created by a call to the function
149 * getFirstItemPos, and is only meaningful to the internal routines.
150 * Aborting a call in the middle (not running to the end of the table)
151 * may result in a memory leak at the moment.
152 *@returns xPos if still iterating through the list, otherwise it will
153 * return NULL when the end has been reached and the xPos variable has
154 * been deleted.
155 */
156 void *getNextItemPos( void *xPos );
157
158 /** A helpful operator to make accessing items easier. Please note that
159 * this simply returns a pointer to the data stored internally, and cannot
160 * be used like the STL operator to store new data, use insert for that.
161 *@param id The identifier used to store the requested item.
162 *@returns The data value assosiated with the given id, or NULL if it
163 * wasn't found in the table.
164 */
165 const void *operator[](const void *id);
166
167 /**
168 * Delete the specified item from the hashtable. This actually keeps the
169 * data and marks it deleted. For all intents and purposes to the user it
170 * is deleted, except that the space is still used until a rehash is forced.
171 * This means that in hashtables where elements are being inserted and
172 * deleted frequently you may run into a higher rate of expansion.
173 *@param id The ID to delete.
174 *@param nSkip The number of similar id's to skip before deleting in a
175 * hashtable that allows duplicates.
176 *@returns True if the element was found and deleted, false otherwise.
177 */
178 bool del( const void *id, int nSkip=0 );
179
180 /**
181 * Deletes every entry in the hash table. See the notes on del to see what
182 * this means, except that since no data is being kept, the entire table is
183 * just marked as usable space.
184 */
185 void clear();
186
187private:
188 /**
189 * Contains info related to a position in the hashtable. Used for
190 * searching through hashtables one item at a time, in order. This class
191 * should never be created by anything but a HashTable, and should never
192 * be referenced directly. Instead the hashtable returns a void pointer,
193 * which is what should be passed back in next time you use a search
194 * function. Always finish a search, since the object is deleted at the
195 * end of the search.
196 *@author Mike Buland
197 */
198 class HashPos
199 {
200 public:
201 /** Create a blank HashPos. */
202 HashPos() { bStarted=false; nPos = 0; };
203 /** Has the search been started? */
204 bool bStarted;
205 /** The position (index) into the backend storage structure. */
206 unsigned long int nPos;
207 };
208
209 /**
210 * All data related to a single element in the hashtable. This should
211 * really only be used and manipulated by the HashTable itself.
212 *@author Mike Buland
213 */
214 typedef struct HashNode
215 {
216 public:
217 /** Create a new, empty HashNode. */
218 HashNode() { id = NULL; data = NULL; bDeleted = false; };
219 /** A pointer to the original ID that was used to key the data. */
220 const void *id;
221 /** A pointer to the data stored along with the above ID. */
222 const void *data;
223 /** Weather or not this data should really...exist */
224 bool bDeleted;
225 } HashNode;
226
227private:
228 /**
229 * Just sets the values in the element to some friendly values.
230 *@param newID The new ID to store.
231 *@param newData The new Data to store.
232 */
233 void set( int j, const void *newID, const void *newData );
234 /**
235 * Tells you if the node is filled or not.
236 *@returns True=an ID has been stored here, False=no ID.
237 */
238 bool isFilled( int j );
239 /**
240 * This actually resizes, but since every resize requires a reHash to go
241 * along with it, that's the name. This actually creates a new buffer for
242 * all of the contained data and then pulls every old element that was in
243 * the old table out and performs the hashing placement calculations again.
244 * This function skips all data that was marked as deleted, so at this
245 * point it really will be.
246 *@param nNewSize The new size to set the table to while re-hashing.
247 *@returns True if the operation was successful, false otherwise.
248 */
249 void reHash( unsigned long int nNewSize );
250
251 /**
252 * Helper function to allocate a new table. Really just does the memory
253 * allocation.
254 *@param nNewSize The size of the table to generate.
255 *@returns A new, blank array of HashNode objects the size you specified.
256 */
257 HashNode *newTable( unsigned long int nNewSize );
258
259 /**
260 * This function is used once an actual hash code is obtained. nStart is
261 * the given hash code, which is then wrapped to the size of the table. If
262 * there is data at that location, tests are performed to see if it's the
263 * right one. If it is, then it is returned, otherwise a series of further
264 * tests based on a 2^n search pattern is performed. The position of the
265 * requested data in the back-end storage is returned if found, otherwise
266 * another less useful value is returned...
267 *@param nStart The initial hashcode of the ID testing for.
268 *@param id A pointer to the id that is being searched for.
269 *@returns The real location of the data requested.
270 */
271 unsigned long int probe( unsigned long int nStart, const void *id );
272
273 /**
274 * Simple helper function to determine if a number is prime or not.
275 * This function runs in sqrt(n) time.
276 *@param num Number to test for prime-hood.
277 *@returns True if the number is prime, false otherwise.
278 */
279 bool isPrime( int num );
280
281 /**
282 * Given any number, this function finds the first number after it that is
283 * prime. Since this number is a multiple internally it's rare that the
284 * starting number would be prime.
285 *@param base The number to start the prime search on.
286 *@returns The first prime after the number given.
287 */
288 int nextPrime( int base );
289
290#ifdef HASH_DEBUG_VIS
291 void printDebugLine( const char *exData );
292#endif
293
294 /** A pointer to the HashFunction subclass instance to use. */
295 HashFunction *hFunc;
296 /** The complete array of HashNode objects to store data in. */
297 HashNode *aTable;
298 /** The actual size of the table, not how many elements are in it. */
299 unsigned long int nTableSize;
300 /** The number of elements that are in the table. */
301 unsigned long int nSize;
302 /** The number of elements that are unavailable now. */
303 unsigned long int nFilled;
304 /** Allow duplicate ID's in the table. */
305 bool bAllowDupes;
306};
307
308#endif
diff --git a/src/inprogress/xmldocument.cpp b/src/inprogress/xmldocument.cpp
new file mode 100644
index 0000000..cb21826
--- /dev/null
+++ b/src/inprogress/xmldocument.cpp
@@ -0,0 +1,9 @@
1#include "xmldocument.h"
2
3Bu::XmlDocument::XmlDocument()
4{
5}
6
7Bu::XmlDocument::~XmlDocument()
8{
9}
diff --git a/src/inprogress/xmldocument.h b/src/inprogress/xmldocument.h
new file mode 100644
index 0000000..e16e3ea
--- /dev/null
+++ b/src/inprogress/xmldocument.h
@@ -0,0 +1,22 @@
1#ifndef XML_DOCUMENT_H
2#define XML_DOCUMENT_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlDocument
12 {
13 public:
14 XmlDocument();
15 virtual ~XmlDocument();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/inprogress/xmlnode.cpp b/src/inprogress/xmlnode.cpp
new file mode 100644
index 0000000..58ef5c5
--- /dev/null
+++ b/src/inprogress/xmlnode.cpp
@@ -0,0 +1,9 @@
1#include "xmlnode.h"
2
3Bu::XmlNode::XmlNode()
4{
5}
6
7Bu::XmlNode::~XmlNode()
8{
9}
diff --git a/src/inprogress/xmlnode.h b/src/inprogress/xmlnode.h
new file mode 100644
index 0000000..cd9961a
--- /dev/null
+++ b/src/inprogress/xmlnode.h
@@ -0,0 +1,22 @@
1#ifndef XML_NODE_H
2#define XML_NODE_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlNode
12 {
13 public:
14 XmlNode();
15 virtual ~XmlNode();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/inprogress/xmlreader.cpp b/src/inprogress/xmlreader.cpp
new file mode 100644
index 0000000..bd241cf
--- /dev/null
+++ b/src/inprogress/xmlreader.cpp
@@ -0,0 +1,267 @@
1#include "xmlreader.h"
2
3Bu::XmlReader::XmlReader( Bu::Stream &sIn ) :
4 sIn( sIn )
5{
6}
7
8Bu::XmlReader::~XmlReader()
9{
10}
11
12const char *Bu::XmlReader::lookahead( int nAmnt )
13{
14 if( sBuf.getSize() >= nAmnt )
15 return sBuf.getStr();
16
17 int nNew = nAmnt - sBuf.getSize();
18 char *buf = new char[nNew];
19 sIn.read( buf, nNew );
20 sBuf.append( buf );
21
22 return sBuf.getStr();
23}
24
25void Bu::XmlReader::burn( int nAmnt )
26{
27 if( sBuf.getSize() < nAmnt )
28 {
29 lookahead( nAmnt );
30 }
31
32 //sBuf.remove( nAmnt );
33}
34
35void Bu::XmlReader::checkString( const char *str, int nLen )
36{
37 if( !strncmp( str, lookahead( nLen ), nLen ) )
38 {
39 burn( nLen );
40 return;
41 }
42
43 throw Bu::ExceptionBase("Expected string '%s'", str );
44}
45
46Bu::XmlNode *Bu::XmlReader::read()
47{
48 prolog();
49}
50
51void Bu::XmlReader::prolog()
52{
53 XMLDecl();
54 Misc();
55}
56
57void Bu::XmlReader::XMLDecl()
58{
59 checkString("<?xml", 5 );
60 S();
61 VersionInfo();
62 EncodingDecl();
63 SDDecl();
64 Sq();
65 checkString("?>", 2 );
66}
67
68void Bu::XmlReader::Misc()
69{
70 for(;;)
71 {
72 S();
73 if( !strncmp("<!--", lookahead( 4 ), 4 ) )
74 {
75 Comment();
76 }
77 else if( !strncmp("<?", lookahead( 2 ), 2 ) )
78 {
79 PI();
80 }
81 else
82 {
83 return;
84 }
85 }
86}
87
88void Bu::XmlReader::Comment()
89{
90 checkString("<!--", 4 );
91 for(;;)
92 {
93 unsigned char c = *lookahead(1);
94 if( c == '-' )
95 {
96 if( lookahead(2)[1] == '-' )
97 {
98 checkString("-->", 3 );
99 return;
100 }
101 }
102 burn( 1 );
103 }
104}
105
106void Bu::XmlReader::PI()
107{
108 checkString("<?", 2 );
109 FString sName = Name();
110 printf("PI: %s\n---\n", sName.getStr() );
111 S();
112 for(int j = 0;; j++ )
113 {
114 if( !strncmp( "?>", lookahead(j+2)+j, 2 ) )
115 {
116 burn( j+2 );
117 return;
118 }
119 }
120}
121
122void Bu::XmlReader::S()
123{
124 for( int j = 0;; j++ )
125 {
126 char c = *lookahead( 1 );
127 if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA )
128 continue;
129 if( j == 0 )
130 throw ExceptionBase("Expected whitespace.");
131 return;
132 }
133}
134
135void Bu::XmlReader::Sq()
136{
137 for(;;)
138 {
139 char c = *lookahead( 1 );
140 if( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA )
141 continue;
142 return;
143 }
144}
145
146void Bu::XmlReader::VersionInfo()
147{
148 try
149 {
150 S();
151 checkString("version", 7 );
152 }
153 catch( ExceptionBase &e )
154 {
155 return;
156 }
157 Eq();
158 Bu::FString ver = AttValue();
159 if( ver != "1.1" )
160 throw ExceptionBase("Currently we only support xml version 1.1\n");
161}
162
163void Bu::XmlReader::Eq()
164{
165 Sq();
166 checkString("=", 1 );
167 Sq();
168}
169
170void Bu::XmlReader::EncodingDecl()
171{
172 S();
173 try
174 {
175 checkString("encoding", 8 );
176 }
177 catch( ExceptionBase &e )
178 {
179 return;
180 }
181
182 Eq();
183 AttValue();
184}
185
186void Bu::XmlReader::SDDecl()
187{
188 S();
189 try
190 {
191 checkString("standalone", 10 );
192 }
193 catch( ExceptionBase &e )
194 {
195 return;
196 }
197
198 Eq();
199 AttValue();
200}
201
202Bu::FString Bu::XmlReader::AttValue()
203{
204 char q = *lookahead(1);
205 if( q == '\"' )
206 {
207 for( int j = 2;; j++ )
208 {
209 if( lookahead(j)[j-1] == '\"' )
210 {
211 Bu::FString ret( lookahead(j)+1, j-2 );
212 burn( j );
213 return ret;
214 }
215 }
216 }
217 else if( q == '\'' )
218 {
219 for( int j = 2;; j++ )
220 {
221 if( lookahead(j)[j-1] == '\'' )
222 {
223 Bu::FString ret( lookahead(j)+1, j-2 );
224 burn( j );
225 return ret;
226 }
227 }
228 }
229
230 throw ExceptionBase("Excpected either \' or \".\n");
231}
232
233Bu::FString Bu::XmlReader::Name()
234{
235 unsigned char c = *lookahead( 1 );
236 if( c != ':' && c != '_' &&
237 (c < 'A' || c > 'Z') &&
238 (c < 'a' || c > 'z') &&
239 (c < 0xC0 || c > 0xD6 ) &&
240 (c < 0xD8 || c > 0xF6 ) &&
241 (c < 0xF8))
242 {
243 throw ExceptionBase("Invalid entity name starting character.");
244 }
245
246 for( int j = 1;; j++ )
247 {
248 unsigned char c = lookahead(j+1)[j];
249 if( isS( c ) )
250 {
251 FString ret( lookahead(j+1), j+1 );
252 burn( j+1 );
253 return ret;
254 }
255 if( c != ':' && c != '_' && c != '-' && c != '.' && c != 0xB7 &&
256 (c < 'A' || c > 'Z') &&
257 (c < 'a' || c > 'z') &&
258 (c < '0' || c > '9') &&
259 (c < 0xC0 || c > 0xD6 ) &&
260 (c < 0xD8 || c > 0xF6 ) &&
261 (c < 0xF8))
262 {
263 throw ExceptionBase("Invalid character in name.");
264 }
265 }
266}
267
diff --git a/src/inprogress/xmlreader.h b/src/inprogress/xmlreader.h
new file mode 100644
index 0000000..708a386
--- /dev/null
+++ b/src/inprogress/xmlreader.h
@@ -0,0 +1,121 @@
1#ifndef XML_READER_H
2#define XML_READER_H
3
4#include <stdint.h>
5#include "bu/stream.h"
6#include "bu/fstring.h"
7#include "bu/xmlnode.h"
8
9namespace Bu
10{
11 /**
12 * An Xml 1.1 reader. I've decided to write this, this time, based on the
13 * official W3C reccomendation, now included with the source code. I've
14 * named the productions in the parser states the same as in that document,
15 * which may make them easier to find, etc, although possibly slightly less
16 * optimized than writing my own reduced grammer.
17 *
18 * Below I will list differences between my parser and the official standard
19 * as I come up with them.
20 * - Encoding and Standalone headings are ignored for the moment. (4.3.3,
21 * 2.9)
22 * - The standalone heading attribute can have any standard whitespace
23 * before it (the specs say only spaces, no newlines). (2.9)
24 * - Since standalone is ignored, it is currently allowed to have any
25 * value (should be restricted to "yes" or "no"). (2.9)
26 * - Currently only UTF-8 / ascii are parsed.
27 * - [optional] The content of comments is thrown away. (2.5)
28 * - The content of processing instruction blocks is parsed properly, but
29 * thrown away. (2.6)
30 */
31 class XmlReader
32 {
33 public:
34 XmlReader( Bu::Stream &sIn );
35 virtual ~XmlReader();
36
37 XmlNode *read();
38
39 private:
40 Bu::Stream &sIn;
41 Bu::FString sBuf;
42
43 private: // Helpers
44 const char *lookahead( int nAmnt );
45 void burn( int nAmnt );
46 void checkString( const char *str, int nLen );
47
48 private: // States
49 /**
50 * The headers, etc.
51 */
52 void prolog();
53
54 /**
55 * The xml decleration (version, encoding, etc).
56 */
57 void XMLDecl();
58
59 /**
60 * Misc things, Includes Comments and PIData (Processing Instructions).
61 */
62 void Misc();
63
64 /**
65 * Comments
66 */
67 void Comment();
68
69 /**
70 * Processing Instructions
71 */
72 void PI();
73
74 /**
75 * Whitespace eater.
76 */
77 void S();
78
79 /**
80 * Optional whitespace eater.
81 */
82 void Sq();
83
84 /**
85 * XML Version spec
86 */
87 void VersionInfo();
88
89 /**
90 * Your basic equals sign with surrounding whitespace.
91 */
92 void Eq();
93
94 /**
95 * Read in an attribute value.
96 */
97 FString AttValue();
98
99 /**
100 * Read in the name of something.
101 */
102 FString Name();
103
104 /**
105 * Encoding decleration in the header
106 */
107 void EncodingDecl();
108
109 /**
110 * Standalone decleration in the header
111 */
112 void SDDecl();
113
114 bool isS( unsigned char c )
115 {
116 return ( c == 0x20 || c == 0x9 || c == 0xD || c == 0xA );
117 }
118 };
119}
120
121#endif
diff --git a/src/inprogress/xmlwriter.cpp b/src/inprogress/xmlwriter.cpp
new file mode 100644
index 0000000..23a5175
--- /dev/null
+++ b/src/inprogress/xmlwriter.cpp
@@ -0,0 +1,9 @@
1#include "xmlwriter.h"
2
3Bu::XmlWriter::XmlWriter()
4{
5}
6
7Bu::XmlWriter::~XmlWriter()
8{
9}
diff --git a/src/inprogress/xmlwriter.h b/src/inprogress/xmlwriter.h
new file mode 100644
index 0000000..796d6fb
--- /dev/null
+++ b/src/inprogress/xmlwriter.h
@@ -0,0 +1,22 @@
1#ifndef XML_WRITER_H
2#define XML_WRITER_H
3
4#include <stdint.h>
5
6namespace Bu
7{
8 /**
9 *
10 */
11 class XmlWriter
12 {
13 public:
14 XmlWriter();
15 virtual ~XmlWriter();
16
17 private:
18
19 };
20}
21
22#endif
diff --git a/src/ito.cpp b/src/ito.cpp
new file mode 100644
index 0000000..001ca06
--- /dev/null
+++ b/src/ito.cpp
@@ -0,0 +1,40 @@
1#include "ito.h"
2
3Bu::Ito::Ito()
4{
5}
6
7Bu::Ito::~Ito()
8{
9}
10
11bool Bu::Ito::start()
12{
13 nHandle = pthread_create( &ptHandle, NULL, threadRunner, this );
14
15 return true;
16}
17
18bool Bu::Ito::stop()
19{
20 pthread_exit( &ptHandle );
21
22 return true;
23}
24
25void *Bu::Ito::threadRunner( void *pThread )
26{
27 return ((Ito *)pThread)->run();
28}
29
30bool Bu::Ito::join()
31{
32 pthread_join( ptHandle, NULL );
33 return true;
34}
35
36void Bu::Ito::yield()
37{
38 pthread_yield();
39}
40
diff --git a/src/ito.h b/src/ito.h
new file mode 100644
index 0000000..c062052
--- /dev/null
+++ b/src/ito.h
@@ -0,0 +1,98 @@
1#ifndef BU_ITO_H
2#define BU_ITO_H
3
4#include <pthread.h>
5
6namespace Bu
7{
8 /**
9 * Simple thread class. This wraps the basic pthread (posix threads) system in
10 * an object oriented sort of way. It allows you to create a class with
11 * standard member variables and callable functions that can be run in it's own
12 * thread, one per class instance.
13 *@author Mike Buland
14 */
15 class Ito
16 {
17 public:
18 /**
19 * Construct an Ito thread.
20 */
21 Ito();
22
23 /**
24 * Destroy an Ito thread.
25 */
26 virtual ~Ito();
27
28 /**
29 * Begin thread execution. This will call the overridden run function,
30 * which will simply execute in it's own thread until the function exits,
31 * the thread is killed, or the thread is cancelled (optionally). The
32 * thread started in this manner has access to all of it's class variables,
33 * but be sure to protect possible multiple-access with ItoMutex objects.
34 *@returns True if starting the thread was successful. False if something
35 * went wrong and the thread has not started.
36 */
37 bool start();
38
39 /**
40 * Forcibly kill a thread. This is not generally considered a good thing to
41 * do, but in those rare cases you need it, it's invaluable. The problem
42 * with stopping (or killing) a thread is that it stops it the moment you
43 * call stop, no matter what it's doing. The object oriented approach to
44 * this will help clean up any class variables that were used, but anything
45 * not managed as a member variable will probably create a memory leak type
46 * of situation. Instead of stop, consider using cancel, which can be
47 * handled by the running thread in a graceful manner.
48 *@returns True if the thread was stopped, false otherwise. When this
49 * function returns the thread may not have stopped, to ensure that the
50 * thread has really stopped, call join.
51 */
52 bool stop();
53
54 /**
55 * The workhorse of the Ito class. This is the function that will run in
56 * the thread, when this function exits the thread dies and is cleaned up
57 * by the system. Make sure to read up on ItoMutex, ItoCondition, and
58 * cancel to see how to control and protect everything you do in a safe way
59 * within this function.
60 *@returns I'm not sure right now, but this is the posix standard form.
61 */
62 virtual void *run()=0;
63
64 /**
65 * Join the thread in action. This function performs what is commonly
66 * called a thread join. That is that it effectively makes the calling
67 * thread an the Ito thread contained in the called object one in the same,
68 * and pauses the calling thread until the called thread exits. That is,
69 * when called from, say, your main(), mythread.join() will not return until
70 * the thread mythread has exited. This is very handy at the end of
71 * programs to ensure all of your data was cleaned up.
72 *@returns True if the thread was joined, false if the thread couldn't be
73 * joined, usually because it isn't running to begin with.
74 */
75 bool join();
76
77 private:
78 pthread_t ptHandle; /**< Internal handle to the posix thread. */
79 int nHandle; /**< Numeric handle to the posix thread. */
80
81 protected:
82 /**
83 * This is the hidden-heard of the thread system. While run is what the
84 * user gets to override, and everything said about it is true, this is
85 * the function that actually makes up the thread, it simply calls the
86 * run member function in an OO-friendly way. This is what allows us to
87 * use member variables from within the thread itself.
88 *@param Should always be this.
89 *@returns This is specified by posix, I'm not sure yet.
90 */
91 static void *threadRunner( void *pThread );
92
93 void yield();
94
95 };
96}
97
98#endif
diff --git a/src/itoatom.h b/src/itoatom.h
new file mode 100644
index 0000000..7fc9090
--- /dev/null
+++ b/src/itoatom.h
@@ -0,0 +1,56 @@
1#ifndef BU_ITO_QUEUE_H
2#define BU_ITO_QUEUE_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7#include "itocondition.h"
8
9/**
10 * A thread-safe wrapper class.
11 *@author Mike Buland
12 */
13template <class T>
14class ItoAtom
15{
16public:
17 /**
18 * Construct an empty queue.
19 */
20 ItoAtom()
21 {
22 }
23
24 ItoAtom( const T &src ) :
25 data( src )
26 {
27 }
28
29 ~ItoQueue()
30 {
31 }
32
33 T get()
34 {
35 mOperate.lock();
36 mOperate.unlock();
37 return data;
38 }
39
40 void set( const T &val )
41 {
42 mOperate.lock();
43 data = val;
44 cBlock.signal();
45 mOperate.unlock();
46 }
47
48private:
49 Item *pStart; /**< The start of the queue, the next element to dequeue. */
50 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
51
52 ItoMutex mOperate; /**< The master mutex, used on all operations. */
53 ItoCondition cBlock; /**< The condition for blocking dequeues. */
54};
55
56#endif
diff --git a/src/itocondition.cpp b/src/itocondition.cpp
new file mode 100644
index 0000000..d8f5375
--- /dev/null
+++ b/src/itocondition.cpp
@@ -0,0 +1,42 @@
1#include <sys/time.h>
2
3#include "itocondition.h"
4
5Bu::ItoCondition::ItoCondition()
6{
7 pthread_cond_init( &cond, NULL );
8}
9
10Bu::ItoCondition::~ItoCondition()
11{
12 pthread_cond_destroy( &cond );
13}
14
15int Bu::ItoCondition::wait()
16{
17 return pthread_cond_wait( &cond, &mutex );
18}
19
20int Bu::ItoCondition::wait( int nSec, int nUSec )
21{
22 struct timeval now;
23 struct timespec timeout;
24 struct timezone tz;
25
26 gettimeofday( &now, &tz );
27 timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000);
28 timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000;
29
30 return pthread_cond_timedwait( &cond, &mutex, &timeout );
31}
32
33int Bu::ItoCondition::signal()
34{
35 return pthread_cond_signal( &cond );
36}
37
38int Bu::ItoCondition::broadcast()
39{
40 return pthread_cond_broadcast( &cond );
41}
42
diff --git a/src/itocondition.h b/src/itocondition.h
new file mode 100644
index 0000000..1793f81
--- /dev/null
+++ b/src/itocondition.h
@@ -0,0 +1,81 @@
1#ifndef BU_ITO_CONDITION_H
2#define BU_ITO_CONDITION_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7
8namespace Bu
9{
10 /**
11 * Ito condition. This is a fairly simple condition mechanism. As you may
12 * notice this class inherits from the ItoMutex class, this is because all
13 * conditions must be within a locked block. The standard usage of a condition
14 * is to pause one thread, perhaps indefinately, until another thread signals
15 * that it is alright to procede.
16 * <br>
17 * Standard usage for the thread that wants to wait is as follows:
18 * <pre>
19 * ItoCondition cond;
20 * ... // Perform setup and enter your run loop
21 * cond.lock();
22 * while( !isFinished() ) // Could be anything you're waiting for
23 * cond.wait();
24 * ... // Take care of what you have to.
25 * cond.unlock();
26 * </pre>
27 * The usage for the triggering thread is much simpler, when it needs to tell
28 * the others that it's time to grab some data it calls either signal or
29 * broadcast. See both of those functions for the difference.
30 *@author Mike Buland
31 */
32 class ItoCondition : public ItoMutex
33 {
34 public:
35 /**
36 * Create a condition.
37 */
38 ItoCondition();
39
40 /**
41 * Destroy a condition.
42 */
43 ~ItoCondition();
44
45 /**
46 * Wait forever, or until signalled. This has to be called from within a
47 * locked section, i.e. before calling this this object's lock function
48 * should be called.
49 */
50 int wait();
51
52 /**
53 * Wait for a maximum of nSec seconds and nUSec micro-seconds or until
54 * signalled. This is a little more friendly function if you want to
55 * perform other operations in the thrad loop that calls this function.
56 * Like the other wait function, this must be inside a locked section.
57 *@param nSec The seconds to wait.
58 *@param nUSec the micro-seconds to wait.
59 */
60 int wait( int nSec, int nUSec );
61
62 /**
63 * Notify the next thread waiting on this condition that they can go ahead.
64 * This only signals one thread, the next one in the condition queue, that
65 * it is safe to procede with whatever operation was being waited on.
66 */
67 int signal();
68
69 /**
70 * Notify all threads waiting on this condition that they can go ahead now.
71 * This function is slower than signal, but more effective in certain
72 * situations where you may not know how many threads should be activated.
73 */
74 int broadcast();
75
76 private:
77 pthread_cond_t cond; /**< Internal condition reference. */
78 };
79}
80
81#endif
diff --git a/src/itomutex.cpp b/src/itomutex.cpp
new file mode 100644
index 0000000..dc51af9
--- /dev/null
+++ b/src/itomutex.cpp
@@ -0,0 +1,27 @@
1#include "itomutex.h"
2
3Bu::ItoMutex::ItoMutex()
4{
5 pthread_mutex_init( &mutex, NULL );
6}
7
8Bu::ItoMutex::~ItoMutex()
9{
10 pthread_mutex_destroy( &mutex );
11}
12
13int Bu::ItoMutex::lock()
14{
15 return pthread_mutex_lock( &mutex );
16}
17
18int Bu::ItoMutex::unlock()
19{
20 return pthread_mutex_unlock( &mutex );
21}
22
23int Bu::ItoMutex::trylock()
24{
25 return pthread_mutex_trylock( &mutex );
26}
27
diff --git a/src/itomutex.h b/src/itomutex.h
new file mode 100644
index 0000000..9c9d205
--- /dev/null
+++ b/src/itomutex.h
@@ -0,0 +1,61 @@
1#ifndef BU_ITO_MUTEX_H
2#define BU_ITO_MUTEX_H
3
4#include <pthread.h>
5
6namespace Bu
7{
8 /**
9 * Simple mutex wrapper. Currently this doesn't do anything extra for you
10 * except keep all of the functionality together in an OO sorta' way and keep
11 * you from having to worry about cleaning up your mutexes properly, or initing
12 * them.
13 *@author Mike Buland
14 */
15 class ItoMutex
16 {
17 public:
18 /**
19 * Create an unlocked mutex.
20 */
21 ItoMutex();
22
23 /**
24 * Destroy a mutex. This can only be done when a mutex is unlocked.
25 * Failure to unlock before destroying a mutex object could cause it to
26 * wait for the mutex to unlock, the odds of which are usually farily low
27 * at deconstruction time.
28 */
29 ~ItoMutex();
30
31 /**
32 * Lock the mutex. This causes all future calls to lock on this instance
33 * of mutex to block until the first thread that called mutex unlocks it.
34 * At that point the next thread that called lock will get a chance to go
35 * to work. Because of the nature of a mutex lock it is a very bad idea to
36 * do any kind of serious or rather time consuming computation within a
37 * locked section. This can cause thread-deadlock and your program may
38 * hang.
39 */
40 int lock();
41
42 /**
43 * Unlock the mutex. This allows the next thread that asked for a lock to
44 * lock the mutex and continue with execution.
45 */
46 int unlock();
47
48 /**
49 * Try to lock the mutex. This is the option to go with if you cannot avoid
50 * putting lengthy operations within a locked section. trylock will attempt
51 * to lock the mutex, if the mutex is already locked this function returns
52 * immediately with an error code.
53 */
54 int trylock();
55
56 protected:
57 pthread_mutex_t mutex; /**< The internal mutex reference. */
58 };
59}
60
61#endif
diff --git a/src/itoqueue.h b/src/itoqueue.h
new file mode 100644
index 0000000..75a2f27
--- /dev/null
+++ b/src/itoqueue.h
@@ -0,0 +1,231 @@
1#ifndef BU_ITO_QUEUE_H
2#define BU_ITO_QUEUE_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7#include "itocondition.h"
8
9namespace Bu
10{
11 /**
12 * A thread-safe queue class. This class is a very simple queue with some cool
13 * extra functionality for use with the Ito system. The main extra that it
14 * provides is the option to either dequeue without blocking, with infinite
15 * blocking, or with timed blocking, which will return a value if something is
16 * enqueued within the specified time limit, or NULL if the time limit is
17 * exceded.
18 *@author Mike Buland
19 */
20 template <class T>
21 class ItoQueue
22 {
23 private:
24 /**
25 * Helper struct. Keeps track of linked-list items for the queue data.
26 */
27 typedef struct Item
28 {
29 T pData;
30 Item *pNext;
31 } Item;
32
33 public:
34 /**
35 * Construct an empty queue.
36 */
37 ItoQueue() :
38 pStart( NULL ),
39 pEnd( NULL ),
40 nSize( 0 )
41 {
42 }
43
44 /**
45 * Destroy the queue. This function will simply free all contained
46 * structures. If you stored pointers in the queue, this will lose the
47 * pointers without cleaning up the memory they pointed to. Make sure
48 * you're queue is empty before allowing it to be destroyed!
49 */
50 ~ItoQueue()
51 {
52 Item *pCur = pStart;
53 while( pCur )
54 {
55 Item *pTmp = pCur->pNext;
56 delete pCur;
57 pCur = pTmp;
58 }
59 }
60
61 /**
62 * Enqueue a pieces of data. The new data will go at the end of the queue,
63 * and unless another piece of data is enqueued, will be the last piece of
64 * data to be dequeued.
65 *@param pData The data to enqueue. If this is not a primitive data type
66 * it's probably best to use a pointer type.
67 */
68 void enqueue( T pData )
69 {
70 mOperate.lock();
71
72 if( pStart == NULL )
73 {
74 pStart = pEnd = new Item;
75 pStart->pData = pData;
76 pStart->pNext = NULL;
77 nSize++;
78 }
79 else
80 {
81 pEnd->pNext = new Item;
82 pEnd = pEnd->pNext;
83 pEnd->pData = pData;
84 pEnd->pNext = NULL;
85 nSize++;
86 }
87
88 cBlock.signal();
89
90 mOperate.unlock();
91 }
92
93 /**
94 * Dequeue the first item from the queue. This function can operate in two
95 * different modes, blocking and non-blocking. In non-blocking mode it will
96 * return immediately weather there was data in the queue or not. If there
97 * was data it will remove it from the queue and return it to the caller.
98 * In blocking mode it will block forever wating for data to be enqueued.
99 * When data finally is enqueued this function will return immediately with
100 * the new data. The only way this function should ever return a null in
101 * blocking mode is if the calling thread was cancelled. It's probably a
102 * good idea to check for NULL return values even if you use blocking, just
103 * to be on the safe side.
104 *@param bBlock Set to true to enable blocking, leave as false to work in
105 * non-blocking mode.
106 *@returns The next piece of data in the queue, or NULL if no data was in
107 * the queue.
108 */
109 T dequeue( bool bBlock=false )
110 {
111 mOperate.lock();
112 if( pStart == NULL )
113 {
114 mOperate.unlock();
115
116 if( bBlock )
117 {
118 cBlock.lock();
119
120 while( pStart == NULL )
121 cBlock.wait();
122
123 T tmp = dequeue( false );
124
125 cBlock.unlock();
126 return tmp;
127
128 }
129
130 return NULL;
131 }
132 else
133 {
134 T pTmp = pStart->pData;
135 Item *pDel = pStart;
136 pStart = pStart->pNext;
137 delete pDel;
138 nSize--;
139
140 mOperate.unlock();
141 return pTmp;
142 }
143 }
144
145 /**
146 * Operates just like the other dequeue function in blocking mode with one
147 * twist. This function will block for at most nSec seconds and nUSec
148 * micro-seconds. If the timer is up and no data is available, this will
149 * just return NULL. If data is enqueued before the timeout expires, it
150 * will dequeue and exit immediately.
151 *@param nSec The number of seconds to wait, max.
152 *@param nUSec The number of micro-seconds to wait, max.
153 *@returns The next piece of data in the queue, or NULL if the timeout was
154 * exceeded.
155 */
156 T dequeue( int nSec, int nUSec )
157 {
158 mOperate.lock();
159 if( pStart == NULL )
160 {
161 mOperate.unlock();
162
163 cBlock.lock();
164
165 cBlock.wait( nSec, nUSec );
166
167 if( pStart == NULL )
168 {
169 cBlock.unlock();
170 return NULL;
171 }
172
173 mOperate.lock();
174 T pTmp = pStart->pData;
175 Item *pDel = pStart;
176 pStart = pStart->pNext;
177 delete pDel;
178 nSize--;
179 mOperate.unlock();
180
181 cBlock.unlock();
182 return pTmp;
183 }
184 else
185 {
186 T pTmp = pStart->pData;
187 Item *pDel = pStart;
188 pStart = pStart->pNext;
189 delete pDel;
190 nSize--;
191
192 mOperate.unlock();
193 return pTmp;
194 }
195 }
196
197 /**
198 * Checks to see if the queue has data in it or not. Note that there is no
199 * function to determine the length of the queue. This data isn't kept
200 * track of. If you really need to know, fix this.
201 *@returns True if the queue is empty, false if it has data in it.
202 */
203 bool isEmpty()
204 {
205 mOperate.lock();
206 bool bEmpty = (pStart == NULL );
207 mOperate.unlock();
208
209 return bEmpty;
210 }
211
212 long getSize()
213 {
214 mOperate.lock();
215 long nRet = nSize;
216 mOperate.unlock();
217
218 return nRet;
219 }
220
221 private:
222 Item *pStart; /**< The start of the queue, the next element to dequeue. */
223 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
224 long nSize; /**< The number of items in the queue. */
225
226 ItoMutex mOperate; /**< The master mutex, used on all operations. */
227 ItoCondition cBlock; /**< The condition for blocking dequeues. */
228 };
229}
230
231#endif
diff --git a/src/linkmessage.cpp b/src/linkmessage.cpp
index cf3df42..abe113c 100644
--- a/src/linkmessage.cpp
+++ b/src/linkmessage.cpp
@@ -1,12 +1,11 @@
1#include "linkmessage.h" 1#include "bu/linkmessage.h"
2#include <string.h>
3 2
4LinkMessage::LinkMessage( int nNewMsg ) 3Bu::LinkMessage::LinkMessage( int nNewMsg )
5{ 4{
6 nMsg = nNewMsg; 5 nMsg = nNewMsg;
7} 6}
8 7
9LinkMessage::~LinkMessage() 8Bu::LinkMessage::~LinkMessage()
10{ 9{
11} 10}
12 11
diff --git a/src/linkmessage.h b/src/linkmessage.h
index 6cdfb2f..baa22a6 100644
--- a/src/linkmessage.h
+++ b/src/linkmessage.h
@@ -1,39 +1,42 @@
1/**\file linkmessage.h 1/**\file linkmessage.h
2 */ 2 */
3 3
4#ifndef LINKMESSAGE_H 4#ifndef BU_LINKMESSAGE_H
5#define LINKMESSAGE_H 5#define BU_LINKMESSAGE_H
6 6
7/** 7namespace Bu
8 * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally
9 * one would make a subclass of this in order to transmit more useful
10 * information, but sometimes it isn't necesarry.
11 *@author Mike Buland
12 */
13class LinkMessage
14{ 8{
15public:
16 /** 9 /**
17 * Construct a blank LinkMessage. 10 * A message to be broadcast accross ProgramLinks in a ProgramChain. Generally
11 * one would make a subclass of this in order to transmit more useful
12 * information, but sometimes it isn't necesarry.
13 *@author Mike Buland
18 */ 14 */
19 LinkMessage() {}; 15 class LinkMessage
16 {
17 public:
18 /**
19 * Construct a blank LinkMessage.
20 */
21 LinkMessage() {};
20 22
21 /** 23 /**
22 * Deconstruct a LinkMessage. 24 * Deconstruct a LinkMessage.
23 */ 25 */
24 virtual ~LinkMessage(); 26 virtual ~LinkMessage();
25 27
26 /** 28 /**
27 * Create a LinkMessage object with a specific message assosiated with it 29 * Create a LinkMessage object with a specific message assosiated with it
28 * to start with. 30 * to start with.
29 *@param nNewMsg The message to use in the Message object. 31 *@param nNewMsg The message to use in the Message object.
30 */ 32 */
31 LinkMessage( int nNewMsg ); 33 LinkMessage( int nNewMsg );
32 34
33 /** 35 /**
34 * The message contained in the Message object. 36 * The message contained in the Message object.
35 */ 37 */
36 int nMsg; 38 int nMsg;
37}; 39 };
40}
38 41
39#endif 42#endif
diff --git a/src/list.cpp b/src/list.cpp
index 18f1a66..abe92ad 100644
--- a/src/list.cpp
+++ b/src/list.cpp
@@ -1,10 +1,2 @@
1#include "list.h" 1#include "bu/list.h"
2
3List::List( )
4{
5}
6
7List::~List( )
8{
9}
10 2
diff --git a/src/list.h b/src/list.h
index c71b328..e05ebbc 100644
--- a/src/list.h
+++ b/src/list.h
@@ -1,101 +1,489 @@
1#ifndef LIST_H 1#ifndef BU_LIST_H
2#define LIST_H 2#define BU_LIST_H
3 3
4#include <memory>
5#include "bu/exceptionbase.h"
4 6
5/** The basic List class ADT. This, on it's own, does absolutely nothing, but 7namespace Bu
6 * does define all standard interface functions to access a list.
7 *@author Mike Buland
8 */
9class List
10{ 8{
11public: 9 template<typename value>
12 /** 10 struct ListLink
13 * Construct a list. 11 {
14 */ 12 value *pValue;
15 List(); 13 ListLink *pNext;
14 ListLink *pPrev;
15 };
16 16
17 /** 17 /**
18 * Desconstruct a list. 18 * Linked list template container. This class is similar to the stl list
19 * class except for a few minor changes. First, it doesn't mimic a stack or
20 * queue, use the Stack or Queue clasess for that. Second, when const, all
21 * members are only accessable const. Third, erasing a location does not
22 * invalidate the iterator, it simply points to the next valid location, or
23 * end() if there are no more.
24 *
25 *@param value (typename) The type of data to store in your list
26 *@param valuealloc (typename) Memory Allocator for your value type
27 *@param linkalloc (typename) Memory Allocator for the list links.
19 */ 28 */
20 virtual ~List(); 29 template<typename value, typename valuealloc=std::allocator<value>, typename linkalloc=std::allocator<struct ListLink<value> > >
21 30 class List
22 /** Gets the value at a specified index. 31 {
23 *@param nIndex The index of the item to return. 32 private:
24 *@returns The specified item, or NULL if the index was beyond the range 33 typedef struct ListLink<value> Link;
25 * of the list. 34 typedef class List<value, valuealloc, linkalloc> MyType;
26 *@author Mike Buland
27 */
28 virtual void *getAt( int nIndex ) = 0;
29
30 /** Append the given data to the end of the list. This increases the
31 * size of the list by one.
32 *@param pData The data to append to the list.
33 *@author Mike Buland
34 */
35 virtual void append( void *pData ) = 0;
36
37 /** Inserts an item at the specified position in the list. The
38 * new item takes the index that you specify, and all other items
39 * are moved up one position. The size of the list is increased by
40 * one.
41 *@param pData The value to insert into the list.
42 *@param nPos Where to insert the data into the list.
43 *@author Mike Buland
44 */
45 virtual void insertBefore( void *pData, int nPos = 0 ) = 0;
46
47 /** Determines the size of the list, in elements.
48 *@returns The size of the list.
49 *@author Mike Buland
50 */
51 virtual int getSize( ) = 0;
52
53 /** Determines if the list is empty or not.
54 *@returns True if the list is empty, or false if the list has
55 * data in it (if the size is greater than zero).
56 *@author Mike Buland
57 */
58 virtual bool isEmpty( ) = 0;
59
60 /** Deletes an item at the specified index and moves all other
61 * values down one index. The size of the list is decreased by one.
62 *@param nIndex The index of the item to delete.
63 *@author Mike Buland
64 */
65 virtual void deleteAt( int nIndex ) = 0;
66
67 /** Completely empties the list, and sets the effective size to
68 * zero.
69 *@author Mike Buland
70 */
71 virtual void empty() = 0;
72
73 /** Sets the size of the list. This can be larger or smaller
74 * than what it was previously. If larger, new blank items will
75 * be added to the end of the list. If smaller than the old list
76 * items will be deleted from the end.
77 *@param nNewSize The new size of the list.
78 *@author Mike Buland
79 */
80 virtual void setSize( int nNewSize ) = 0;
81
82 /** Sets a member at a specified location to a new value.
83 * If the member being set is outside of the range of the
84 * current list it should be expanded.
85 *@param nIndex The zero-based index of the item to change.
86 *@param pData The new value for that index.
87 *@author Mike Buland
88 */
89 virtual void setAt( int nIndex, void *pData ) = 0;
90
91 /** Makes the List work like an array. Just say listObj[2] to get
92 * the third element.
93 *@param nIndex The index to access in the list.
94 *@returns A pointer to the data at element index.
95 *@author Mike Buland
96 */
97 void *operator[]( int nIndex ) { return getAt( nIndex ); };
98};
99 35
100#endif 36 public:
37 List() :
38 pFirst( NULL ),
39 pLast( NULL ),
40 nSize( 0 )
41 {
42 }
43
44 List( const MyType &src ) :
45 pFirst( NULL ),
46 pLast( NULL ),
47 nSize( 0 )
48 {
49 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
50 {
51 append( *pCur->pValue );
52 }
53 }
54
55 ~List()
56 {
57 clear();
58 }
59
60 /**
61 * Assignment operator.
62 *@param src (const MyType &) The list to assign to your list.
63 */
64 MyType &operator=( const MyType &src )
65 {
66 clear();
67 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
68 {
69 append( *pCur->pValue );
70 }
71 }
72
73 /**
74 * Clear the data from the list.
75 */
76 void clear()
77 {
78 Link *pCur = pFirst;
79 for(;;)
80 {
81 if( pCur == NULL ) break;
82 va.destroy( pCur->pValue );
83 va.deallocate( pCur->pValue, 1 );
84 Link *pTmp = pCur->pNext;
85 la.destroy( pCur );
86 la.deallocate( pCur, 1 );
87 pCur = pTmp;
88 }
89 pFirst = pLast = NULL;
90 nSize = 0;
91 }
92
93 /**
94 * Append a value to the list.
95 *@param v (const value_type &) The value to append.
96 */
97 void append( const value &v )
98 {
99 Link *pNew = la.allocate( 1 );
100 pNew->pValue = va.allocate( 1 );
101 va.construct( pNew->pValue, v );
102 nSize++;
103 if( pFirst == NULL )
104 {
105 // Empty list
106 pFirst = pLast = pNew;
107 pNew->pNext = pNew->pPrev = NULL;
108 }
109 else
110 {
111 pNew->pNext = NULL;
112 pNew->pPrev = pLast;
113 pLast->pNext = pNew;
114 pLast = pNew;
115 }
116 }
117
118 /**
119 * Prepend a value to the list.
120 *@param v (const value_type &) The value to prepend.
121 */
122 void prepend( const value &v )
123 {
124 Link *pNew = la.allocate( 1 );
125 pNew->pValue = va.allocate( 1 );
126 va.construct( pNew->pValue, v );
127 nSize++;
128 if( pFirst == NULL )
129 {
130 // Empty list
131 pFirst = pLast = pNew;
132 pNew->pNext = pNew->pPrev = NULL;
133 }
134 else
135 {
136 pNew->pNext = pFirst;
137 pNew->pPrev = NULL;
138 pFirst->pPrev = pNew;
139 pFirst = pNew;
140 }
141 }
142
143 /**
144 * An iterator to iterate through your list.
145 */
146 typedef struct iterator
147 {
148 friend class List<value, valuealloc, linkalloc>;
149 private:
150 Link *pLink;
151 iterator() :
152 pLink( NULL )
153 {
154 }
155
156 iterator( Link *pLink ) :
157 pLink( pLink )
158 {
159 }
160
161 public:
162 /**
163 * Equals comparison operator.
164 *@param oth (const iterator &) The iterator to compare to.
165 *@returns (bool) Are they equal?
166 */
167 bool operator==( const iterator &oth ) const
168 {
169 return ( pLink == oth.pLink );
170 }
171
172 /**
173 * Equals comparison operator.
174 *@param pOth (const Link *) The link to compare to.
175 *@returns (bool) Are they equal?
176 */
177 bool operator==( const Link *pOth ) const
178 {
179 return ( pLink == pOth );
180 }
181
182 /**
183 * Not equals comparison operator.
184 *@param oth (const iterator &) The iterator to compare to.
185 *@returns (bool) Are they not equal?
186 */
187 bool operator!=( const iterator &oth ) const
188 {
189 return ( pLink != oth.pLink );
190 }
191
192 /**
193 * Not equals comparison operator.
194 *@param pOth (const Link *) The link to compare to.
195 *@returns (bool) Are they not equal?
196 */
197 bool operator!=( const Link *pOth ) const
198 {
199 return ( pLink != pOth );
200 }
201
202 /**
203 * Dereference operator.
204 *@returns (value_type &) The value.
205 */
206 value &operator*()
207 {
208 return *(pLink->pValue);
209 }
210
211 /**
212 * Pointer access operator.
213 *@returns (value_type *) A pointer to the value.
214 */
215 value *operator->()
216 {
217 return pLink->pValue;
218 }
219
220 /**
221 * Increment operator.
222 */
223 iterator &operator++()
224 {
225 if( pLink != NULL )
226 pLink = pLink->pNext;
227 return *this;
228 }
229
230 /**
231 * Decrement operator.
232 */
233 iterator &operator--()
234 {
235 if( pLink != NULL )
236 pLink = pLink->pPrev;
237 return *this;
238 }
239
240 /**
241 * Increment operator.
242 */
243 iterator &operator++( int )
244 {
245 if( pLink != NULL )
246 pLink = pLink->pNext;
247 return *this;
248 }
249
250 /**
251 * Decrement operator.
252 */
253 iterator &operator--( int )
254 {
255 if( pLink != NULL )
256 pLink = pLink->pPrev;
257 return *this;
258 }
259
260 /**
261 * Assignment operator.
262 *@param oth (const iterator &) The other iterator to set this
263 * one to.
264 */
265 iterator &operator=( const iterator &oth )
266 {
267 pLink = oth.pLink;
268 return *this;
269 }
270 };
271
272 /**
273 *@see iterator
274 */
275 typedef struct const_iterator
276 {
277 friend class List<value, valuealloc, linkalloc>;
278 private:
279 Link *pLink;
280 const_iterator() :
281 pLink( NULL )
282 {
283 }
101 284
285 const_iterator( Link *pLink ) :
286 pLink( pLink )
287 {
288 }
289
290 const_iterator( const iterator &i ) :
291 pLink( i.pLink )
292 {
293 }
294
295 public:
296 bool operator==( const const_iterator &oth ) const
297 {
298 return ( pLink == oth.pLink );
299 }
300
301 bool operator==( const Link *pOth ) const
302 {
303 return ( pLink == pOth );
304 }
305
306 bool operator!=( const const_iterator &oth ) const
307 {
308 return ( pLink != oth.pLink );
309 }
310
311 bool operator!=( const Link *pOth ) const
312 {
313 return ( pLink != pOth );
314 }
315
316 const value &operator*()
317 {
318 return *(pLink->pValue);
319 }
320
321 const value *operator->()
322 {
323 return pLink->pValue;
324 }
325
326 const_iterator &operator++()
327 {
328 if( pLink != NULL )
329 pLink = pLink->pNext;
330 return *this;
331 }
332
333 const_iterator &operator--()
334 {
335 if( pLink != NULL )
336 pLink = pLink->pPrev;
337 return *this;
338 }
339
340 const_iterator &operator++( int )
341 {
342 if( pLink != NULL )
343 pLink = pLink->pNext;
344 return *this;
345 }
346
347 const_iterator &operator--( int )
348 {
349 if( pLink != NULL )
350 pLink = pLink->pPrev;
351 return *this;
352 }
353
354 const_iterator &operator=( const iterator &oth )
355 {
356 pLink = oth.pLink;
357 return *this;
358 }
359
360 const_iterator &operator=( const const_iterator &oth )
361 {
362 pLink = oth.pLink;
363 return *this;
364 }
365 };
366
367 /**
368 * Get an iterator pointing to the first item in the list.
369 *@returns (iterator)
370 */
371 iterator begin()
372 {
373 return iterator( pFirst );
374 }
375
376 /**
377 * Get a const iterator pointing to the first item in the list.
378 *@returns (const const_iterator)
379 */
380 const const_iterator begin() const
381 {
382 return const_iterator( pFirst );
383 }
384
385 /**
386 * Get an iterator pointing to a place just past the last item in
387 * the list.
388 *@returns (const Link *)
389 */
390 const Link *end() const
391 {
392 return NULL;
393 }
394
395 /**
396 * Erase an item from the list.
397 *@param i (iterator) The item to erase.
398 */
399 void erase( iterator &i )
400 {
401 Link *pCur = i.pLink;
402 Link *pPrev = pCur->pPrev;
403 if( pPrev == NULL )
404 {
405 va.destroy( pCur->pValue );
406 va.deallocate( pCur->pValue, 1 );
407 pFirst = pCur->pNext;
408 la.destroy( pCur );
409 la.deallocate( pCur, 1 );
410 if( pFirst == NULL )
411 pLast = NULL;
412 nSize--;
413 i.pLink = pFirst;
414 }
415 else
416 {
417 va.destroy( pCur->pValue );
418 va.deallocate( pCur->pValue, 1 );
419 Link *pTmp = pCur->pNext;
420 la.destroy( pCur );
421 la.deallocate( pCur, 1 );
422 pPrev->pNext = pTmp;
423 if( pTmp != NULL )
424 pTmp->pPrev = pPrev;
425 nSize--;
426 i.pLink = pTmp;
427 }
428 }
429
430 /**
431 * Get the current size of the list.
432 *@returns (int) The current size of the list.
433 */
434 int getSize() const
435 {
436 return nSize;
437 }
438
439 /**
440 * Get the first item in the list.
441 *@returns (value_type &) The first item in the list.
442 */
443 value &first()
444 {
445 return *pFirst->pValue;
446 }
447
448 /**
449 * Get the first item in the list.
450 *@returns (const value_type &) The first item in the list.
451 */
452 const value &first() const
453 {
454 return *pFirst->pValue;
455 }
456
457 /**
458 * Get the last item in the list.
459 *@returns (value_type &) The last item in the list.
460 */
461 value &last()
462 {
463 return *pLast->pValue;
464 }
465
466 /**
467 * Get the last item in the list.
468 *@returns (const value_type &) The last item in the list.
469 */
470 const value &last() const
471 {
472 return *pLast->pValue;
473 }
474
475 const bool isEmpty() const
476 {
477 return (nSize == 0);
478 }
479
480 private:
481 Link *pFirst;
482 Link *pLast;
483 linkalloc la;
484 valuealloc va;
485 int nSize;
486 };
487}
488
489#endif
diff --git a/src/logger.cpp b/src/logger.cpp
new file mode 100644
index 0000000..1fc2262
--- /dev/null
+++ b/src/logger.cpp
@@ -0,0 +1,131 @@
1#include "bu/logger.h"
2#include <stdarg.h>
3#include <time.h>
4#include <stdio.h>
5
6Bu::Logger::Logger()
7{
8}
9
10Bu::Logger::~Logger()
11{
12}
13
14void Bu::Logger::log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...)
15{
16 if( (nLevel&nLevelMask) == 0 )
17 return;
18
19 va_list ap;
20 va_start( ap, sFormat );
21 char *text;
22 vasprintf( &text, sFormat, ap );
23 va_end(ap);
24
25 time_t t = time(NULL);
26
27 char *line = NULL;
28 struct tm *pTime;
29 pTime = localtime( &t );
30 asprintf(
31 &line,
32 sLogFormat.getStr(),
33 pTime->tm_year+1900,
34 pTime->tm_mon+1,
35 pTime->tm_mday,
36 pTime->tm_hour,
37 pTime->tm_min,
38 pTime->tm_sec,
39 nLevel,
40 sFile,
41 nLine,
42 text,
43 sFunction
44 );
45 write( fileno(stdout), line, strlen(line) );
46 free( text );
47 free( line );
48}
49
50void Bu::Logger::setFormat( const Bu::FString &str )
51{
52 sLogFormat = "";
53
54 static char fmts[][4]={
55 {'y', 'd', '0', '1'},
56 {'m', 'd', '0', '2'},
57 {'d', 'd', '0', '3'},
58 {'h', 'd', '0', '4'},
59 {'M', 'd', '0', '5'},
60 {'s', 'd', '0', '6'},
61 {'L', 'd', '0', '7'},
62 {'f', 's', '0', '8'},
63 {'l', 'd', '0', '9'},
64 {'t', 's', '1', '0'},
65 {'F', 's', '1', '1'},
66 {'\0', '\0', '\0', '\0'},
67 };
68
69 for( const char *s = str.getStr(); *s; s++ )
70 {
71 if( *s == '%' )
72 {
73 sLogFormat += '%';
74 Bu::FString sBuf;
75 for(;;)
76 {
77 s++;
78 int l;
79 for( l = 0;; l++ )
80 {
81 if( fmts[l][0] == '\0' )
82 {
83 sBuf += *s;
84 break;
85 }
86 else if( *s == fmts[l][0] )
87 {
88 sLogFormat += fmts[l][2];
89 sLogFormat += fmts[l][3];
90 sLogFormat += '$';
91 sLogFormat += sBuf;
92 sLogFormat += fmts[l][1];
93 break;
94 }
95 }
96 if( fmts[l][0] != '\0' )
97 break;
98 }
99 }
100 else
101 {
102 sLogFormat += *s;
103 }
104 }
105 sLogFormat += '\n';
106
107 write( fileno(stdout), sLogFormat.getStr(), sLogFormat.getSize() );
108}
109
110void Bu::Logger::setMask( int n )
111{
112 nLevelMask = n;
113}
114
115void Bu::Logger::setLevel( int n )
116{
117 int j;
118 for( j = 31; j > 0; j-- )
119 {
120 if( (n&(1<<j)) )
121 {
122 for(; j >= 0; j-- )
123 {
124 n |= (1<<j);
125 }
126 nLevelMask = n;
127 return;
128 }
129 }
130}
131
diff --git a/src/logger.h b/src/logger.h
new file mode 100644
index 0000000..f8e1692
--- /dev/null
+++ b/src/logger.h
@@ -0,0 +1,112 @@
1#ifndef BU_LOGGER_H
2#define BU_LOGGER_H
3
4#include "bu/singleton.h"
5#include "bu/fstring.h"
6
7namespace Bu
8{
9 /**
10 * Simple logging facility. All output goes straight to stdout, unlike the
11 * old multi-log system. Generally we expect any program complex enough to
12 * want to use this will have other facilities for processing the logging
13 * output, but if we need it we can add other output methods.
14 *
15 * Currently implemented as a singleton to avoid clutter with globals, you
16 * generally never want to use the logging system directly, it's annoying.
17 * Instead use the handy macros lineLog, setLogMask, setLogFormat, and
18 * setLogLevel. They do all the real work for you.
19 *
20 * In the log format, you can specify extra information that will be written
21 * to the log with every message, and extras in printf style. Use %X flags
22 * where X is one of the following:
23 * - L - Logging level of the log message (not the current mask)
24 * - y - Full year
25 * - m - Month
26 * - d - Day of month
27 * - h - Hour (24-hour format)
28 * - M - Minutes
29 * - s - Seconds
30 * - f - Source file
31 * - l - Line number
32 * - F - function name
33 * - t - Text of message (usually important)
34 *
35 * You can include anything extra that you would like, a newline will always
36 * be added automatically, so no need to worry about that. You can also
37 * include any extra printf style formatting that you would like, for
38 * example: "%h:%02M:%02s" for the time 4:02:09 instead of 4:2:9.
39 *
40 * It's generally handy to create an enum of values you use as levels during
41 * program execution (such as error, warning, info, debug, etc). These
42 * levels should be treated as bitflags, and the most desirable messages,
43 * i.e. serious errors and the like should be low order (0x01), and the much
44 * less desirable messages, like debugging info, should be higher order
45 * (0xF0). During operation you can then set either an explicit mask,
46 * selecting just the levels that you would like to see printed, or set the
47 * mask using the setLevel helper function, which simulates verbosity
48 * levels, enabling every flag lower order than the highest order set bit
49 * passed. I.E. if you had the following enumerated levels:
50 *
51 *@code
52 enum {
53 logError = 0x01,
54 logWarning = 0x02,
55 logInfo = 0x04,
56 logDebug = 0x08
57 };
58 @endcode
59 * And you set the mask with setMask( logInfo ) the only messages you would
60 * see are the ones catagorized logInfo. However, if you used
61 * setLevel( logInfo ) then you would see logInfo, logWarning, and logError
62 * type messages, since they are lower order.
63 */
64 class Logger : public Bu::Singleton<Bu::Logger>
65 {
66 friend class Bu::Singleton<Bu::Logger>;
67 private:
68 Logger();
69 virtual ~Logger();
70
71 public:
72 void log( int nLevel, const char *sFile, const char *sFunction, int nLine, const char *sFormat, ...);
73
74 void setFormat( const Bu::FString &str );
75 void setMask( int n );
76 void setLevel( int n );
77
78 private:
79 Bu::FString sLogFormat;
80 int nLevelMask;
81 };
82}
83
84/**
85 * Use Bu::Logger to log a message at the given level and with the given message
86 * using printf style formatting, and include extra data such as the current
87 * file, line number, and function.
88 */
89#define lineLog( nLevel, sFrmt, ...) \
90 Bu::Logger::getInstance().log( nLevel, __FILE__, __PRETTY_FUNCTION__, __LINE__, sFrmt, ##__VA_ARGS__ )
91
92/**
93 * Set the Bu::Logger logging mask directly. See Bu::Logger::setMask for
94 * details.
95 */
96#define setLogMask( nLevel ) \
97 Bu::Logger::getInstance().setMask( nLevel )
98
99/**
100 * Set the Bu::Logger format. See Bu::Logger::setFormat for details.
101 */
102#define setLogFormat( sFrmt ) \
103 Bu::Logger::getInstance().setFormat( sFrmt )
104
105/**
106 * Set the Bu::Logger logging mask simulating levels. See Bu::Logger::setLevel
107 * for details.
108 */
109#define setLogLevel( nLevel ) \
110 Bu::Logger::getInstance().setLevel( nLevel )
111
112#endif
diff --git a/src/main.dox b/src/main.dox
new file mode 100644
index 0000000..668d2e3
--- /dev/null
+++ b/src/main.dox
@@ -0,0 +1,14 @@
1/**
2 *@mainpage libbu++ utility library
3 *
4 *@section secIntro Introduction
5 *
6 * Libbu++ is a C++ library of general utility classes and functions. They
7 * cover a wide range of topics from streams and sockets to data structures to
8 * data serialization and xml handling to threading.
9 *
10 */
11
12/**
13 *@namespace Bu The core libbu++ namespace, to ensure things don't get muddied.
14 */
diff --git a/src/membuf.cpp b/src/membuf.cpp
new file mode 100644
index 0000000..45ff5bd
--- /dev/null
+++ b/src/membuf.cpp
@@ -0,0 +1,120 @@
1#include "bu/membuf.h"
2
3using namespace Bu;
4
5Bu::MemBuf::MemBuf() :
6 nPos( 0 )
7{
8}
9
10Bu::MemBuf::MemBuf( const Bu::FString &str ) :
11 sBuf( str ),
12 nPos( 0 )
13{
14}
15
16Bu::MemBuf::~MemBuf()
17{
18}
19
20void Bu::MemBuf::close()
21{
22}
23
24size_t Bu::MemBuf::read( void *pBuf, size_t nBytes )
25{
26 if( (size_t)sBuf.getSize()-(size_t)nPos < nBytes )
27 nBytes = sBuf.getSize()-nPos;
28
29 memcpy( pBuf, sBuf.getStr()+nPos, nBytes );
30 nPos += nBytes;
31
32 return nBytes;
33}
34
35size_t Bu::MemBuf::write( const void *pBuf, size_t nBytes )
36{
37 sBuf.append( (const char *)pBuf, nBytes );
38 nPos += nBytes;
39 return nBytes;
40}
41
42long Bu::MemBuf::tell()
43{
44 return nPos;
45}
46
47void Bu::MemBuf::seek( long offset )
48{
49 nPos += offset;
50 if( nPos < 0 ) nPos = 0;
51 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
52}
53
54void Bu::MemBuf::setPos( long pos )
55{
56 nPos = pos;
57 if( nPos < 0 ) nPos = 0;
58 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
59}
60
61void Bu::MemBuf::setPosEnd( long pos )
62{
63 nPos = sBuf.getSize()-pos;
64 if( nPos < 0 ) nPos = 0;
65 else if( nPos > sBuf.getSize() ) nPos = sBuf.getSize();
66}
67
68bool Bu::MemBuf::isEOS()
69{
70 return (nPos == sBuf.getSize());
71}
72
73bool Bu::MemBuf::isOpen()
74{
75 return true;
76}
77
78void Bu::MemBuf::flush()
79{
80}
81
82bool Bu::MemBuf::canRead()
83{
84 return !isEOS();
85}
86
87bool Bu::MemBuf::canWrite()
88{
89 return isEOS();
90}
91
92bool Bu::MemBuf::isReadable()
93{
94 return true;
95}
96
97bool Bu::MemBuf::isWritable()
98{
99 return true;
100}
101
102bool Bu::MemBuf::isSeekable()
103{
104 return true;
105}
106
107bool Bu::MemBuf::isBlocking()
108{
109 return true;
110}
111
112void Bu::MemBuf::setBlocking( bool bBlocking )
113{
114}
115
116Bu::FString &Bu::MemBuf::getString()
117{
118 return sBuf;
119}
120
diff --git a/src/membuf.h b/src/membuf.h
new file mode 100644
index 0000000..8f53d4b
--- /dev/null
+++ b/src/membuf.h
@@ -0,0 +1,53 @@
1#ifndef BU_MEM_BUF_H
2#define BU_MEM_BUF_H
3
4#include <stdint.h>
5
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 * A memory buffer stream.
13 */
14 class MemBuf : public Stream
15 {
16 public:
17 MemBuf();
18 MemBuf( const Bu::FString &str );
19 virtual ~MemBuf();
20
21 virtual void close();
22 virtual size_t read( void *pBuf, size_t nBytes );
23
24 /**
25 *@todo Allow writes at the current position, not just appending to
26 * the current buffer. This is a silly way to do it, but it covers all
27 * of our bases for now.
28 */
29 virtual size_t write( const void *pBuf, size_t nBytes );
30 virtual long tell();
31 virtual void seek( long offset );
32 virtual void setPos( long pos );
33 virtual void setPosEnd( long pos );
34 virtual bool isEOS();
35 virtual bool isOpen();
36 virtual void flush();
37 virtual bool canRead();
38 virtual bool canWrite();
39 virtual bool isReadable();
40 virtual bool isWritable();
41 virtual bool isSeekable();
42 virtual bool isBlocking();
43 virtual void setBlocking( bool bBlocking=true );
44
45 Bu::FString &getString();
46
47 private:
48 Bu::FString sBuf;
49 long nPos;
50 };
51}
52
53#endif
diff --git a/src/cgi.cpp b/src/old/cgi.cpp
index 1fecbbe..1fecbbe 100644
--- a/src/cgi.cpp
+++ b/src/old/cgi.cpp
diff --git a/src/cgi.h b/src/old/cgi.h
index 01142b5..01142b5 100644
--- a/src/cgi.h
+++ b/src/old/cgi.h
diff --git a/src/configmanagerbase.cpp b/src/old/configmanagerbase.cpp
index ac55fe0..ac55fe0 100644
--- a/src/configmanagerbase.cpp
+++ b/src/old/configmanagerbase.cpp
diff --git a/src/configmanagerbase.h b/src/old/configmanagerbase.h
index 381cc1f..381cc1f 100644
--- a/src/configmanagerbase.h
+++ b/src/old/configmanagerbase.h
diff --git a/src/confpair.cpp b/src/old/confpair.cpp
index 4741401..4741401 100644
--- a/src/confpair.cpp
+++ b/src/old/confpair.cpp
diff --git a/src/confpair.h b/src/old/confpair.h
index 56eb06e..56eb06e 100644
--- a/src/confpair.h
+++ b/src/old/confpair.h
diff --git a/src/confpairbase.cpp b/src/old/confpairbase.cpp
index 1203dc0..1203dc0 100644
--- a/src/confpairbase.cpp
+++ b/src/old/confpairbase.cpp
diff --git a/src/confpairbase.h b/src/old/confpairbase.h
index 2530756..2530756 100644
--- a/src/confpairbase.h
+++ b/src/old/confpairbase.h
diff --git a/src/conftree.cpp b/src/old/conftree.cpp
index d9a3a3f..d9a3a3f 100644
--- a/src/conftree.cpp
+++ b/src/old/conftree.cpp
diff --git a/src/conftree.h b/src/old/conftree.h
index 197b1ef..197b1ef 100644
--- a/src/conftree.h
+++ b/src/old/conftree.h
diff --git a/src/connection.cpp b/src/old/connection.cpp
index efef144..efef144 100644
--- a/src/connection.cpp
+++ b/src/old/connection.cpp
diff --git a/src/connection.h b/src/old/connection.h
index 0e991c7..0e991c7 100644
--- a/src/connection.h
+++ b/src/old/connection.h
diff --git a/src/connectionmanager.cpp b/src/old/connectionmanager.cpp
index ea60b2b..ea60b2b 100644
--- a/src/connectionmanager.cpp
+++ b/src/old/connectionmanager.cpp
diff --git a/src/connectionmanager.h b/src/old/connectionmanager.h
index cff036b..cff036b 100644
--- a/src/connectionmanager.h
+++ b/src/old/connectionmanager.h
diff --git a/src/connectionmonitor.cpp b/src/old/connectionmonitor.cpp
index 4f90ee6..4f90ee6 100644
--- a/src/connectionmonitor.cpp
+++ b/src/old/connectionmonitor.cpp
diff --git a/src/connectionmonitor.h b/src/old/connectionmonitor.h
index 9910556..9910556 100644
--- a/src/connectionmonitor.h
+++ b/src/old/connectionmonitor.h
diff --git a/src/flexbuf.cpp b/src/old/flexbuf.cpp
index 6d55294..6d55294 100644
--- a/src/flexbuf.cpp
+++ b/src/old/flexbuf.cpp
diff --git a/src/flexbuf.h b/src/old/flexbuf.h
index 7d7f11a..7d7f11a 100644
--- a/src/flexbuf.h
+++ b/src/old/flexbuf.h
diff --git a/src/formula.cpp b/src/old/formula.cpp
index cf63cf3..cf63cf3 100644
--- a/src/formula.cpp
+++ b/src/old/formula.cpp
diff --git a/src/formula.h b/src/old/formula.h
index 939eb09..939eb09 100644
--- a/src/formula.h
+++ b/src/old/formula.h
diff --git a/src/http.cpp b/src/old/http.cpp
index df7dafe..df7dafe 100644
--- a/src/http.cpp
+++ b/src/old/http.cpp
diff --git a/src/http.h b/src/old/http.h
index 7e9f9a0..7e9f9a0 100644
--- a/src/http.h
+++ b/src/old/http.h
diff --git a/src/httpget.cpp b/src/old/httpget.cpp
index ee1f29c..ee1f29c 100644
--- a/src/httpget.cpp
+++ b/src/old/httpget.cpp
diff --git a/src/httpget.h b/src/old/httpget.h
index 8272641..8272641 100644
--- a/src/httpget.h
+++ b/src/old/httpget.h
diff --git a/src/linkedlist.cpp b/src/old/linkedlist.cpp
index a9902bc..a9902bc 100644
--- a/src/linkedlist.cpp
+++ b/src/old/linkedlist.cpp
diff --git a/src/linkedlist.h b/src/old/linkedlist.h
index e430108..e430108 100644
--- a/src/linkedlist.h
+++ b/src/old/linkedlist.h
diff --git a/src/linkmessenger.cpp b/src/old/linkmessenger.cpp
index 3bd401a..3bd401a 100644
--- a/src/linkmessenger.cpp
+++ b/src/old/linkmessenger.cpp
diff --git a/src/linkmessenger.h b/src/old/linkmessenger.h
index ed52639..ed52639 100644
--- a/src/linkmessenger.h
+++ b/src/old/linkmessenger.h
diff --git a/src/old/list.cpp b/src/old/list.cpp
new file mode 100644
index 0000000..18f1a66
--- /dev/null
+++ b/src/old/list.cpp
@@ -0,0 +1,10 @@
1#include "list.h"
2
3List::List( )
4{
5}
6
7List::~List( )
8{
9}
10
diff --git a/src/old/list.h b/src/old/list.h
new file mode 100644
index 0000000..c71b328
--- /dev/null
+++ b/src/old/list.h
@@ -0,0 +1,101 @@
1#ifndef LIST_H
2#define LIST_H
3
4
5/** The basic List class ADT. This, on it's own, does absolutely nothing, but
6 * does define all standard interface functions to access a list.
7 *@author Mike Buland
8 */
9class List
10{
11public:
12 /**
13 * Construct a list.
14 */
15 List();
16
17 /**
18 * Desconstruct a list.
19 */
20 virtual ~List();
21
22 /** Gets the value at a specified index.
23 *@param nIndex The index of the item to return.
24 *@returns The specified item, or NULL if the index was beyond the range
25 * of the list.
26 *@author Mike Buland
27 */
28 virtual void *getAt( int nIndex ) = 0;
29
30 /** Append the given data to the end of the list. This increases the
31 * size of the list by one.
32 *@param pData The data to append to the list.
33 *@author Mike Buland
34 */
35 virtual void append( void *pData ) = 0;
36
37 /** Inserts an item at the specified position in the list. The
38 * new item takes the index that you specify, and all other items
39 * are moved up one position. The size of the list is increased by
40 * one.
41 *@param pData The value to insert into the list.
42 *@param nPos Where to insert the data into the list.
43 *@author Mike Buland
44 */
45 virtual void insertBefore( void *pData, int nPos = 0 ) = 0;
46
47 /** Determines the size of the list, in elements.
48 *@returns The size of the list.
49 *@author Mike Buland
50 */
51 virtual int getSize( ) = 0;
52
53 /** Determines if the list is empty or not.
54 *@returns True if the list is empty, or false if the list has
55 * data in it (if the size is greater than zero).
56 *@author Mike Buland
57 */
58 virtual bool isEmpty( ) = 0;
59
60 /** Deletes an item at the specified index and moves all other
61 * values down one index. The size of the list is decreased by one.
62 *@param nIndex The index of the item to delete.
63 *@author Mike Buland
64 */
65 virtual void deleteAt( int nIndex ) = 0;
66
67 /** Completely empties the list, and sets the effective size to
68 * zero.
69 *@author Mike Buland
70 */
71 virtual void empty() = 0;
72
73 /** Sets the size of the list. This can be larger or smaller
74 * than what it was previously. If larger, new blank items will
75 * be added to the end of the list. If smaller than the old list
76 * items will be deleted from the end.
77 *@param nNewSize The new size of the list.
78 *@author Mike Buland
79 */
80 virtual void setSize( int nNewSize ) = 0;
81
82 /** Sets a member at a specified location to a new value.
83 * If the member being set is outside of the range of the
84 * current list it should be expanded.
85 *@param nIndex The zero-based index of the item to change.
86 *@param pData The new value for that index.
87 *@author Mike Buland
88 */
89 virtual void setAt( int nIndex, void *pData ) = 0;
90
91 /** Makes the List work like an array. Just say listObj[2] to get
92 * the third element.
93 *@param nIndex The index to access in the list.
94 *@returns A pointer to the data at element index.
95 *@author Mike Buland
96 */
97 void *operator[]( int nIndex ) { return getAt( nIndex ); };
98};
99
100#endif
101
diff --git a/src/md5.cpp b/src/old/md5.cpp
index c0cacdd..c0cacdd 100644
--- a/src/md5.cpp
+++ b/src/old/md5.cpp
diff --git a/src/md5.h b/src/old/md5.h
index 7f77d83..7f77d83 100644
--- a/src/md5.h
+++ b/src/old/md5.h
diff --git a/src/multilog.cpp b/src/old/multilog.cpp
index 143ee89..143ee89 100644
--- a/src/multilog.cpp
+++ b/src/old/multilog.cpp
diff --git a/src/multilog.h b/src/old/multilog.h
index 692095a..692095a 100644
--- a/src/multilog.h
+++ b/src/old/multilog.h
diff --git a/src/multilogchannel.cpp b/src/old/multilogchannel.cpp
index ee4c9bf..ee4c9bf 100644
--- a/src/multilogchannel.cpp
+++ b/src/old/multilogchannel.cpp
diff --git a/src/multilogchannel.h b/src/old/multilogchannel.h
index d891a65..d891a65 100644
--- a/src/multilogchannel.h
+++ b/src/old/multilogchannel.h
diff --git a/src/multilogtext.cpp b/src/old/multilogtext.cpp
index 4337cc9..4337cc9 100644
--- a/src/multilogtext.cpp
+++ b/src/old/multilogtext.cpp
diff --git a/src/multilogtext.h b/src/old/multilogtext.h
index 197aef1..197aef1 100644
--- a/src/multilogtext.h
+++ b/src/old/multilogtext.h
diff --git a/src/ordhash.cpp b/src/old/ordhash.cpp
index 77cbd61..77cbd61 100644
--- a/src/ordhash.cpp
+++ b/src/old/ordhash.cpp
diff --git a/src/ordhash.h b/src/old/ordhash.h
index e946f95..e946f95 100644
--- a/src/ordhash.h
+++ b/src/old/ordhash.h
diff --git a/src/pqueue.cpp b/src/old/pqueue.cpp
index 1f0b8b5..1f0b8b5 100644
--- a/src/pqueue.cpp
+++ b/src/old/pqueue.cpp
diff --git a/src/pqueue.h b/src/old/pqueue.h
index 8307d56..8307d56 100644
--- a/src/pqueue.h
+++ b/src/old/pqueue.h
diff --git a/src/old/protocol.cpp b/src/old/protocol.cpp
new file mode 100644
index 0000000..78b3ee2
--- /dev/null
+++ b/src/old/protocol.cpp
@@ -0,0 +1,20 @@
1#include "protocol.h"
2
3Protocol::Protocol()
4{
5 pConnection = NULL;
6}
7
8Protocol::~Protocol()
9{
10}
11
12void Protocol::setConnection( Connection *pNewConnection )
13{
14 pConnection = pNewConnection;
15}
16
17Connection *Protocol::getConnection()
18{
19 return pConnection;
20}
diff --git a/src/old/protocol.h b/src/old/protocol.h
new file mode 100644
index 0000000..09e1c98
--- /dev/null
+++ b/src/old/protocol.h
@@ -0,0 +1,62 @@
1#ifndef PROTOCOL_H
2#define PROTOCOL_H
3
4#include "connection.h"
5
6/** This is the template for a class that handles specialized input and output
7 * to connections of different types with different protocols.
8 *@author Mike Buland
9 */
10class Protocol
11{
12public:
13 /** Constructor */
14 Protocol();
15 /** Deconstructor */
16 virtual ~Protocol();
17
18 /**
19 * Function is called every time there is new data on the line. This is
20 * called directly from the Connection class to process data. This is not
21 * called whever there is pending data on the input, but every time new data
22 * is added to the input buffer.
23 *@returns True if processing went alright, false if something went wrong,
24 * I suppose. In truth this value is thrown away right now.
25 *@todo Either make a return value of false mean something, or make these
26 * void.
27 */
28 virtual bool onNewData()=0;
29
30 /**
31 * Function is called when there is a new connection. This should only
32 * happen once per Protocol object, but gives each protocol object a
33 * chance to perform connection handshaking and initialization at a point
34 * where they know that they have a handle to an active Connection.
35 *@returns See onNewData
36 */
37 virtual bool onNewConnection()=0;
38
39 virtual void onNewClientConnection(){};
40
41 virtual void poll(){};
42
43 /**
44 * Sets the Protocol's Connection object. This is rather important, and
45 * handled usually by the ConnectionManager.
46 *@param pNewConnection The Connection object that this protocol will use to
47 * deal with the outside world.
48 */
49 void setConnection( class Connection *pNewConnection );
50
51 /**
52 * Get a pointer to this object's Connection object, or NULL if one was
53 * never set. If used with the ConnectionManager that should never happen.
54 *@returns A pointer to the active Connection.
55 */
56 Connection *getConnection();
57
58private:
59 class Connection *pConnection; /**< The pointer to the Connection. */
60};
61
62#endif
diff --git a/src/protocoltelnet.cpp b/src/old/protocoltelnet.cpp
index b169a51..b169a51 100644
--- a/src/protocoltelnet.cpp
+++ b/src/old/protocoltelnet.cpp
diff --git a/src/protocoltelnet.h b/src/old/protocoltelnet.h
index a6d2e49..a6d2e49 100644
--- a/src/protocoltelnet.h
+++ b/src/old/protocoltelnet.h
diff --git a/src/queue.cpp b/src/old/queue.cpp
index 42999fe..42999fe 100644
--- a/src/queue.cpp
+++ b/src/old/queue.cpp
diff --git a/src/queue.h b/src/old/queue.h
index 692f5d8..692f5d8 100644
--- a/src/queue.h
+++ b/src/old/queue.h
diff --git a/src/ringlist.cpp b/src/old/ringlist.cpp
index 9efbbc4..9efbbc4 100644
--- a/src/ringlist.cpp
+++ b/src/old/ringlist.cpp
diff --git a/src/ringlist.h b/src/old/ringlist.h
index bc069f3..bc069f3 100644
--- a/src/ringlist.h
+++ b/src/old/ringlist.h
diff --git a/src/sbuffer.cpp b/src/old/sbuffer.cpp
index f84f8a3..f84f8a3 100644
--- a/src/sbuffer.cpp
+++ b/src/old/sbuffer.cpp
diff --git a/src/sbuffer.h b/src/old/sbuffer.h
index 65feb71..65feb71 100644
--- a/src/sbuffer.h
+++ b/src/old/sbuffer.h
diff --git a/src/serializerbinary.cpp b/src/old/serializerbinary.cpp
index ea7ed93..ea7ed93 100644
--- a/src/serializerbinary.cpp
+++ b/src/old/serializerbinary.cpp
diff --git a/src/serializerbinary.h b/src/old/serializerbinary.h
index 8510fcd..8510fcd 100644
--- a/src/serializerbinary.h
+++ b/src/old/serializerbinary.h
diff --git a/src/serializerbzip2.cpp b/src/old/serializerbzip2.cpp
index bafabc8..bafabc8 100644
--- a/src/serializerbzip2.cpp
+++ b/src/old/serializerbzip2.cpp
diff --git a/src/serializerbzip2.h b/src/old/serializerbzip2.h
index 4aeb22e..4aeb22e 100644
--- a/src/serializerbzip2.h
+++ b/src/old/serializerbzip2.h
diff --git a/src/serializerconnection.cpp b/src/old/serializerconnection.cpp
index 2934c8b..2934c8b 100644
--- a/src/serializerconnection.cpp
+++ b/src/old/serializerconnection.cpp
diff --git a/src/serializerconnection.h b/src/old/serializerconnection.h
index e8d85c6..e8d85c6 100644
--- a/src/serializerconnection.h
+++ b/src/old/serializerconnection.h
diff --git a/src/serializertext.cpp b/src/old/serializertext.cpp
index 9cf4394..9cf4394 100644
--- a/src/serializertext.cpp
+++ b/src/old/serializertext.cpp
diff --git a/src/serializertext.h b/src/old/serializertext.h
index 01b7f7b..01b7f7b 100644
--- a/src/serializertext.h
+++ b/src/old/serializertext.h
diff --git a/src/sha1.cpp b/src/old/sha1.cpp
index 8270c3b..8270c3b 100644
--- a/src/sha1.cpp
+++ b/src/old/sha1.cpp
diff --git a/src/sha1.h b/src/old/sha1.h
index ab6081d..ab6081d 100644
--- a/src/sha1.h
+++ b/src/old/sha1.h
diff --git a/src/stack.cpp b/src/old/stack.cpp
index 8d9565c..8d9565c 100644
--- a/src/stack.cpp
+++ b/src/old/stack.cpp
diff --git a/src/stack.h b/src/old/stack.h
index 30e2a19..30e2a19 100644
--- a/src/stack.h
+++ b/src/old/stack.h
diff --git a/src/staticstring.cpp b/src/old/staticstring.cpp
index 60f130f..60f130f 100644
--- a/src/staticstring.cpp
+++ b/src/old/staticstring.cpp
diff --git a/src/staticstring.h b/src/old/staticstring.h
index 4c3f7b8..4c3f7b8 100644
--- a/src/staticstring.h
+++ b/src/old/staticstring.h
diff --git a/src/stringrep.cpp b/src/old/stringrep.cpp
index a505f8a..a505f8a 100644
--- a/src/stringrep.cpp
+++ b/src/old/stringrep.cpp
diff --git a/src/stringrep.h b/src/old/stringrep.h
index eaa4a12..eaa4a12 100644
--- a/src/stringrep.h
+++ b/src/old/stringrep.h
diff --git a/src/tests/clistress.cpp b/src/old/tests/clistress.cpp
index 6b0ac66..6b0ac66 100644
--- a/src/tests/clistress.cpp
+++ b/src/old/tests/clistress.cpp
diff --git a/src/tests/confpair.cpp b/src/old/tests/confpair.cpp
index fb1b0d3..fb1b0d3 100644
--- a/src/tests/confpair.cpp
+++ b/src/old/tests/confpair.cpp
diff --git a/src/tests/connect.cpp b/src/old/tests/connect.cpp
index a9fca64..a9fca64 100644
--- a/src/tests/connect.cpp
+++ b/src/old/tests/connect.cpp
diff --git a/src/tests/exception.cpp b/src/old/tests/exception.cpp
index 6417692..6417692 100644
--- a/src/tests/exception.cpp
+++ b/src/old/tests/exception.cpp
diff --git a/src/tests/formula.cpp b/src/old/tests/formula.cpp
index 976b039..976b039 100644
--- a/src/tests/formula.cpp
+++ b/src/old/tests/formula.cpp
diff --git a/src/old/tests/hash.cpp b/src/old/tests/hash.cpp
new file mode 100644
index 0000000..2fc6968
--- /dev/null
+++ b/src/old/tests/hash.cpp
@@ -0,0 +1,116 @@
1#include "hash.h"
2#include "staticstring.h"
3
4int main()
5{
6 const char *names[]={
7 "Homer the Great",
8 "And Maggie Makes Three",
9 "Bart's Comet",
10 "Homie The Clown",
11 "Bart Vs Australia",
12 "Homer vs Patty and Selma",
13 "A star is burns",
14 "Lisa's Wedding",
15 "Two Dozen and One Greyhounds",
16 "The PTA Disbands",
17 "Round Springfield",
18 "The Springfield connection",
19 "Lemon of Troy",
20 "Who Shot Mr. Burns (Pt. 1)",
21 "Who Shot Mr. Burns (pt. 2)",
22 "Radioactive Man",
23 "Home Sweet Homediddly-dum-doodly",
24 "Bart Sells His Soul",
25 "Lisa the Vegetarian",
26 "Treehouse of horror VI",
27 "King Size Homer",
28 "Mother Simpson",
29 "Sideshow Bob's Last Gleaming",
30 "The Simpson's 138th Show Spectacular",
31 "Marge Be Not Proud",
32 "Team Homer",
33 "Two Bad Neighbors",
34 "Scenes From the Class Struggle in Springfield",
35 "Bart the Fink",
36 "Lisa the Iconoclast",
37 "Homer the Smithers",
38 "The Day the Violence Died",
39 "A Fish Called Selma",
40 "Bart on the road",
41 "22 Short Films about Springfield",
42 "The Curse of the Flying Hellfish",
43 "Much Apu about Nothing",
44 "Homerpalooza",
45 "The Summer of 4 Ft 2",
46 "Treehouse of Horror VII",
47 "You Only Move Twice",
48 "The Homer They Fall",
49 "Burns Baby Burns",
50 "Bart After Dark",
51 "A Millhouse Divided",
52 "Lisas Date With Destiny",
53 "Hurricane Neddy",
54 "The Mysterious Voyage of Our Homer",
55 "The Springfield Files",
56 "The Twisted World of Marge Simpson",
57 "Mountain of Madness",
58 NULL
59 };
60
61 Hash<const char *, int> sTest;
62
63 printf("Inserting\n-------------------\n\n");
64 for( int j = 0; j < 33; j++ )
65 {
66 sTest[names[j]] = j;
67 }
68
69 printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) );
70
71 sTest.has(std::string("Lemon of Troy").c_str() );
72
73 printf("Getting\n-------------------\n\n");
74
75 sTest.erase("Homer the Great");
76 sTest["Bart's Comet"].erase();
77
78 for( Hash<const char *, int>::iterator i = sTest.begin();
79 i != sTest.end(); i++ )
80 {
81 Hash<const char *, int>::iterator j = i;
82 printf("%d: %s\n", (*j).second, (*j).first );
83 }
84
85 printf("Testing\n-------------------\n\n");
86 for( int j = 0; j < 33; j++ )
87 {
88 if( sTest.has(names[j]) )
89 {
90 if( sTest[names[j]] != j )
91 {
92 printf("'%s' should be %d, is %d\n",
93 names[j], j,
94 sTest[names[j]].value()
95 );
96 }
97 }
98 else
99 {
100 printf("Missing element %d, '%s'\n", j, names[j] );
101 }
102 }
103
104 printf("Clearing\n-------------------\n\n");
105
106 sTest.clear();
107
108 for( Hash<const char *, int>::iterator i = sTest.begin();
109 i != sTest.end(); i++ )
110 {
111 Hash<const char *, int>::iterator j = i;
112 printf("%d: %s\n", (*j).second, (*j).first );
113 }
114
115}
116
diff --git a/src/tests/hashtest.cpp b/src/old/tests/hashtest.cpp
index eaa84a0..eaa84a0 100644
--- a/src/tests/hashtest.cpp
+++ b/src/old/tests/hashtest.cpp
diff --git a/src/tests/hashtest2.cpp b/src/old/tests/hashtest2.cpp
index 74700fd..74700fd 100644
--- a/src/tests/hashtest2.cpp
+++ b/src/old/tests/hashtest2.cpp
diff --git a/src/tests/httpsrv/httpconnectionmonitor.cpp b/src/old/tests/httpsrv/httpconnectionmonitor.cpp
index 51d82f3..51d82f3 100644
--- a/src/tests/httpsrv/httpconnectionmonitor.cpp
+++ b/src/old/tests/httpsrv/httpconnectionmonitor.cpp
diff --git a/src/tests/httpsrv/httpconnectionmonitor.h b/src/old/tests/httpsrv/httpconnectionmonitor.h
index 30c0afd..30c0afd 100644
--- a/src/tests/httpsrv/httpconnectionmonitor.h
+++ b/src/old/tests/httpsrv/httpconnectionmonitor.h
diff --git a/src/tests/httpsrv/main.cpp b/src/old/tests/httpsrv/main.cpp
index 2f1563c..2f1563c 100644
--- a/src/tests/httpsrv/main.cpp
+++ b/src/old/tests/httpsrv/main.cpp
diff --git a/src/tests/log.cpp b/src/old/tests/log.cpp
index d7cfa0b..d7cfa0b 100644
--- a/src/tests/log.cpp
+++ b/src/old/tests/log.cpp
diff --git a/src/tests/md5test.cpp b/src/old/tests/md5test.cpp
index 6f832df..6f832df 100644
--- a/src/tests/md5test.cpp
+++ b/src/old/tests/md5test.cpp
diff --git a/src/tests/ordhash.cpp b/src/old/tests/ordhash.cpp
index f1d96ec..f1d96ec 100644
--- a/src/tests/ordhash.cpp
+++ b/src/old/tests/ordhash.cpp
diff --git a/src/tests/param.cpp b/src/old/tests/param.cpp
index a4d2824..a4d2824 100644
--- a/src/tests/param.cpp
+++ b/src/old/tests/param.cpp
diff --git a/src/tests/param.h b/src/old/tests/param.h
index 2756b69..2756b69 100644
--- a/src/tests/param.h
+++ b/src/old/tests/param.h
diff --git a/src/tests/plugin/main.cpp b/src/old/tests/plugin/main.cpp
index 51c8390..51c8390 100644
--- a/src/tests/plugin/main.cpp
+++ b/src/old/tests/plugin/main.cpp
diff --git a/src/tests/plugin/plugin.cpp b/src/old/tests/plugin/plugin.cpp
index ea558fd..ea558fd 100644
--- a/src/tests/plugin/plugin.cpp
+++ b/src/old/tests/plugin/plugin.cpp
diff --git a/src/tests/plugin/plugin.h b/src/old/tests/plugin/plugin.h
index f726867..f726867 100644
--- a/src/tests/plugin/plugin.h
+++ b/src/old/tests/plugin/plugin.h
diff --git a/src/tests/qsort.cpp b/src/old/tests/qsort.cpp
index 28c6f03..28c6f03 100644
--- a/src/tests/qsort.cpp
+++ b/src/old/tests/qsort.cpp
diff --git a/src/tests/sbuffer.cpp b/src/old/tests/sbuffer.cpp
index 02798cb..02798cb 100644
--- a/src/tests/sbuffer.cpp
+++ b/src/old/tests/sbuffer.cpp
diff --git a/src/tests/serialize.cpp b/src/old/tests/serialize.cpp
index e233704..e233704 100644
--- a/src/tests/serialize.cpp
+++ b/src/old/tests/serialize.cpp
diff --git a/src/tests/serializetext.cpp b/src/old/tests/serializetext.cpp
index f6be7d3..f6be7d3 100644
--- a/src/tests/serializetext.cpp
+++ b/src/old/tests/serializetext.cpp
diff --git a/src/tests/sha1.cpp b/src/old/tests/sha1.cpp
index df3113c..df3113c 100644
--- a/src/tests/sha1.cpp
+++ b/src/old/tests/sha1.cpp
diff --git a/src/tests/sptr.cpp b/src/old/tests/sptr.cpp
index 252463b..38d3675 100644
--- a/src/tests/sptr.cpp
+++ b/src/old/tests/sptr.cpp
@@ -9,12 +9,12 @@ public:
9 printf("Created.\n"); 9 printf("Created.\n");
10 } 10 }
11 11
12 virtual ~Annoy() 12 ~Annoy()
13 { 13 {
14 printf("Destroyed.\n"); 14 printf("Destroyed.\n");
15 } 15 }
16 16
17 virtual void go() 17 void go()
18 { 18 {
19 printf("%d: I'm annoying.\n", ++nCnt); 19 printf("%d: I'm annoying.\n", ++nCnt);
20 } 20 }
@@ -22,22 +22,6 @@ public:
22 int nCnt; 22 int nCnt;
23}; 23};
24 24
25class Annoy2: public Annoy
26{
27public:
28 Annoy2(){};
29 virtual ~Annoy2(){};
30 virtual void go()
31 {
32 printf("{{I'm Annoy2!!}} ");
33 Annoy::go();
34 }
35 virtual void go2()
36 {
37 printf("This is me, on my own...\n");
38 }
39};
40
41void beAnnoying( SPtr<Annoy> bob ) 25void beAnnoying( SPtr<Annoy> bob )
42{ 26{
43 printf("bob-Count: %d\n", bob.count() ); 27 printf("bob-Count: %d\n", bob.count() );
@@ -46,7 +30,7 @@ void beAnnoying( SPtr<Annoy> bob )
46 30
47int main() 31int main()
48{ 32{
49 SPtr<Annoy> pt( new Annoy2 ); 33 SPtr<Annoy> pt( new Annoy );
50 printf("Count: %d\n", pt.count() ); 34 printf("Count: %d\n", pt.count() );
51 pt->go(); 35 pt->go();
52 36
@@ -63,14 +47,6 @@ int main()
63 pt3->go(); 47 pt3->go();
64 48
65 beAnnoying( pt3 ); 49 beAnnoying( pt3 );
66
67 {
68 SPtr<Annoy2> pt4( SPtrCast<Annoy2>( pt3 ) );
69 printf("Count: %d\n", pt4.count() );
70
71 pt4->go2();
72 }
73 printf("Count: %d\n", pt.count() );
74 } 50 }
75 printf("Count: %d\n", pt.count() ); 51 printf("Count: %d\n", pt.count() );
76 } 52 }
diff --git a/src/tests/srvstress.cpp b/src/old/tests/srvstress.cpp
index d9a9a1c..d9a9a1c 100644
--- a/src/tests/srvstress.cpp
+++ b/src/old/tests/srvstress.cpp
diff --git a/src/tests/strhash.cpp b/src/old/tests/strhash.cpp
index f6528ca..f6528ca 100644
--- a/src/tests/strhash.cpp
+++ b/src/old/tests/strhash.cpp
diff --git a/src/tests/teltest/main.cpp b/src/old/tests/teltest/main.cpp
index 5d3ec26..5d3ec26 100644
--- a/src/tests/teltest/main.cpp
+++ b/src/old/tests/teltest/main.cpp
diff --git a/src/tests/teltest/telnetmonitor.cpp b/src/old/tests/teltest/telnetmonitor.cpp
index 65954eb..65954eb 100644
--- a/src/tests/teltest/telnetmonitor.cpp
+++ b/src/old/tests/teltest/telnetmonitor.cpp
diff --git a/src/tests/teltest/telnetmonitor.h b/src/old/tests/teltest/telnetmonitor.h
index ba5761e..ba5761e 100644
--- a/src/tests/teltest/telnetmonitor.h
+++ b/src/old/tests/teltest/telnetmonitor.h
diff --git a/src/tests/xmlreadtest.cpp b/src/old/tests/xmlreadtest.cpp
index d061810..d061810 100644
--- a/src/tests/xmlreadtest.cpp
+++ b/src/old/tests/xmlreadtest.cpp
diff --git a/src/tests/xmlrepltest.cpp b/src/old/tests/xmlrepltest.cpp
index 9667705..9667705 100644
--- a/src/tests/xmlrepltest.cpp
+++ b/src/old/tests/xmlrepltest.cpp
diff --git a/src/tests/xmlwritetest.cpp b/src/old/tests/xmlwritetest.cpp
index a22d19d..a22d19d 100644
--- a/src/tests/xmlwritetest.cpp
+++ b/src/old/tests/xmlwritetest.cpp
diff --git a/src/tokenstring.cpp b/src/old/tokenstring.cpp
index e57ba69..e57ba69 100644
--- a/src/tokenstring.cpp
+++ b/src/old/tokenstring.cpp
diff --git a/src/tokenstring.h b/src/old/tokenstring.h
index 42f7309..42f7309 100644
--- a/src/tokenstring.h
+++ b/src/old/tokenstring.h
diff --git a/src/tqsort.h b/src/old/tqsort.h
index c836b4f..c836b4f 100644
--- a/src/tqsort.h
+++ b/src/old/tqsort.h
diff --git a/src/unit/hashtable/hashtable.cpp b/src/old/unit/hashtable/hashtable.cpp
index b2e1cf5..b2e1cf5 100644
--- a/src/unit/hashtable/hashtable.cpp
+++ b/src/old/unit/hashtable/hashtable.cpp
diff --git a/src/unit/xml/xml.cpp b/src/old/unit/xml/xml.cpp
index e4d779c..e4d779c 100644
--- a/src/unit/xml/xml.cpp
+++ b/src/old/unit/xml/xml.cpp
diff --git a/src/xmldocument.cpp b/src/old/xmldocument.cpp
index d7867d5..95b9788 100644
--- a/src/xmldocument.cpp
+++ b/src/old/xmldocument.cpp
@@ -1,6 +1,6 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmldocument.h"
4 4
5XmlDocument::XmlDocument( XmlNode *pRoot ) 5XmlDocument::XmlDocument( XmlNode *pRoot )
6{ 6{
@@ -17,28 +17,23 @@ XmlDocument::~XmlDocument()
17 } 17 }
18} 18}
19 19
20void XmlDocument::addNode( const char *sName, const char *sContent, bool bClose ) 20void XmlDocument::addNode( const Bu::FString &sName )
21{ 21{
22 if( pRoot == NULL ) 22 if( pRoot == NULL )
23 { 23 {
24 // This is the first node, so ignore position and just insert it. 24 // This is the first node, so ignore position and just insert it.
25 pCurrent = pRoot = new XmlNode( sName, NULL, sContent ); 25 pCurrent = pRoot = new XmlNode( sName );
26 } 26 }
27 else 27 else
28 { 28 {
29 pCurrent = pCurrent->addChild( sName, sContent ); 29 pCurrent = pCurrent->addChild( sName );
30 }
31
32 if( bClose )
33 {
34 closeNode();
35 } 30 }
36} 31}
37 32/*
38void XmlDocument::setName( const char *sName ) 33void XmlDocument::setName( const char *sName )
39{ 34{
40 pCurrent->setName( sName ); 35 pCurrent->setName( sName );
41} 36}*/
42 37
43bool XmlDocument::isCompleted() 38bool XmlDocument::isCompleted()
44{ 39{
@@ -143,7 +138,8 @@ void XmlDocument::setContent( const char *sContent )
143{ 138{
144 if( pCurrent ) 139 if( pCurrent )
145 { 140 {
146 pCurrent->setContent( sContent ); 141 printf("XmlDocument::setContent: not yet implemented.\n");
142 //pCurrent->setContent( sContent );
147 } 143 }
148} 144}
149 145
diff --git a/src/xmldocument.h b/src/old/xmldocument.h
index 6671c41..e0c36eb 100644
--- a/src/xmldocument.h
+++ b/src/old/xmldocument.h
@@ -39,13 +39,7 @@ public:
39 * the node and setting the content and name. If this is set to true the 39 * the node and setting the content and name. If this is set to true the
40 * node is appended, but the context node doesn't change. 40 * node is appended, but the context node doesn't change.
41 */ 41 */
42 void addNode( const char *sName=NULL, const char *sContent=NULL, bool bClose=false ); 42 void addNode( const Bu::FString &sName );
43
44 /**
45 * Set the name of the current node context.
46 *@param sName The new name of the node.
47 */
48 void setName( const char *sName );
49 43
50 /** 44 /**
51 * Close the current node context. This will move the current context to 45 * Close the current node context. This will move the current context to
diff --git a/src/xmlfilereader.cpp b/src/old/xmlfilereader.cpp
index ed674a8..ed674a8 100644
--- a/src/xmlfilereader.cpp
+++ b/src/old/xmlfilereader.cpp
diff --git a/src/xmlfilereader.h b/src/old/xmlfilereader.h
index e3e02c2..e3e02c2 100644
--- a/src/xmlfilereader.h
+++ b/src/old/xmlfilereader.h
diff --git a/src/xmlfilewriter.cpp b/src/old/xmlfilewriter.cpp
index 3c6fb41..3c6fb41 100644
--- a/src/xmlfilewriter.cpp
+++ b/src/old/xmlfilewriter.cpp
diff --git a/src/xmlfilewriter.h b/src/old/xmlfilewriter.h
index e328f96..e328f96 100644
--- a/src/xmlfilewriter.h
+++ b/src/old/xmlfilewriter.h
diff --git a/src/xmlnode.cpp b/src/old/xmlnode.cpp
index b1ed9a9..96d5850 100644
--- a/src/xmlnode.cpp
+++ b/src/old/xmlnode.cpp
@@ -1,53 +1,15 @@
1#include "xmlnode.h" 1#include "xmlnode.h"
2#include "hashfunctionstring.h"
3 2
4XmlNode::XmlNode( const char *sName, XmlNode *pParent, const char *sContent ) : 3XmlNode::XmlNode( const Bu::FString &sName, XmlNode *pParent ) :
5 hProperties( new HashFunctionString(), 53, false ), 4 sName( sName ),
6 hChildren( new HashFunctionString(), 53, true ) 5 pParent( pParent )
7{ 6{
8 this->pParent = pParent;
9 if( sName != NULL )
10 {
11 setName( sName );
12 }
13 if( sContent != NULL )
14 {
15 this->sPreContent = new std::string( sContent );
16 }
17 else
18 {
19 this->sPreContent = NULL;
20 }
21 nCurContent = 0;
22} 7}
23 8
24XmlNode::~XmlNode() 9XmlNode::~XmlNode()
25{ 10{
26 for( int j = 0; j < lChildren.getSize(); j++ )
27 {
28 delete (XmlNode *)lChildren[j];
29 }
30 for( int j = 0; j < lPropNames.getSize(); j++ )
31 {
32 delete (std::string *)lPropNames[j];
33 }
34 for( int j = 0; j < lPropValues.getSize(); j++ )
35 {
36 delete (std::string *)lPropValues[j];
37 }
38 for( int j = 0; j < lPostContent.getSize(); j++ )
39 {
40 if( lPostContent[j] != NULL )
41 {
42 delete (std::string *)lPostContent[j];
43 }
44 }
45 if( sPreContent )
46 {
47 delete sPreContent;
48 }
49} 11}
50 12/*
51void XmlNode::setName( const char *sName ) 13void XmlNode::setName( const char *sName )
52{ 14{
53 if( pParent ) 15 if( pParent )
@@ -120,18 +82,18 @@ const char *XmlNode::getContent( int nIndex )
120 } 82 }
121 83
122 return NULL; 84 return NULL;
123} 85}*/
124 86
125XmlNode *XmlNode::addChild( const char *sName, const char *sContent ) 87XmlNode *XmlNode::addChild( const Bu::FString &sName )
126{ 88{
127 return addChild( new XmlNode( sName, this, sContent ) ); 89 return addChild( new XmlNode( sName, this ) );
128} 90}
129 91
130XmlNode *XmlNode::addChild( XmlNode *pNode ) 92XmlNode *XmlNode::addChild( XmlNode *pNode )
131{ 93{
132 lChildren.append( pNode ); 94 Child c = { typeNode };
133 lPostContent.append( NULL ); 95 c.pNode = pNode;
134 nCurContent++; 96 lChildren.append( c );
135 pNode->pParent = this; 97 pNode->pParent = this;
136 98
137 return pNode; 99 return pNode;
@@ -142,21 +104,16 @@ XmlNode *XmlNode::getParent()
142 return pParent; 104 return pParent;
143} 105}
144 106
145void XmlNode::addProperty( const char *sName, const char *sValue ) 107void XmlNode::addProperty( const Bu::FString &sName, const Bu::FString &sValue )
146{ 108{
147 std::string *pName = new std::string( sName ); 109 hProperties.insert( sName, sValue );
148 std::string *pValue = new std::string( sValue );
149
150 hProperties.insert( pName->c_str(), pValue->c_str() );
151 lPropNames.append( pName );
152 lPropValues.append( pValue );
153} 110}
154 111
155int XmlNode::getNumProperties() 112int XmlNode::getNumProperties()
156{ 113{
157 return lPropNames.getSize(); 114 return hProperties.size();
158} 115}
159 116/*
160const char *XmlNode::getPropertyName( int nIndex ) 117const char *XmlNode::getPropertyName( int nIndex )
161{ 118{
162 std::string *tmp = ((std::string *)lPropNames[nIndex]); 119 std::string *tmp = ((std::string *)lPropNames[nIndex]);
@@ -172,15 +129,12 @@ const char *XmlNode::getProperty( int nIndex )
172 return NULL; 129 return NULL;
173 return tmp->c_str(); 130 return tmp->c_str();
174} 131}
175 132*/
176const char *XmlNode::getProperty( const char *sName ) 133Bu::FString XmlNode::getProperty( const Bu::FString &sName )
177{ 134{
178 const char *tmp = (const char *)hProperties[sName]; 135 return hProperties[sName];
179 if( tmp == NULL )
180 return NULL;
181 return tmp;
182} 136}
183 137/*
184void XmlNode::deleteProperty( int nIndex ) 138void XmlNode::deleteProperty( int nIndex )
185{ 139{
186 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() ); 140 hProperties.del( ((std::string *)lPropNames[nIndex])->c_str() );
@@ -194,29 +148,33 @@ void XmlNode::deleteProperty( int nIndex )
194 148
195bool XmlNode::hasChildren() 149bool XmlNode::hasChildren()
196{ 150{
197 return lChildren.getSize()>0; 151 return hChildren.getSize()>0;
198} 152}*/
199 153
200int XmlNode::getNumChildren() 154int XmlNode::getNumChildren()
201{ 155{
202 return lChildren.getSize(); 156 return lChildren.getSize();
203} 157}
204 158/*
205XmlNode *XmlNode::getChild( int nIndex ) 159XmlNode *XmlNode::getChild( int nIndex )
206{ 160{
207 return (XmlNode *)lChildren[nIndex]; 161 return (XmlNode *)lChildren[nIndex];
208} 162}
209 163*/
210XmlNode *XmlNode::getChild( const char *sName, int nSkip ) 164XmlNode *XmlNode::getChild( const Bu::FString &sName, int nSkip )
211{ 165{
212 return (XmlNode *)hChildren.get( sName, nSkip ); 166 if( !hChildren.has( sName ) )
167 return NULL;
168
169 Bu::List<XmlNode *>::iterator i = hChildren[sName]->begin();
170 return *i;
213} 171}
214 172
215const char *XmlNode::getName() 173Bu::FString XmlNode::getName()
216{ 174{
217 return sName.c_str(); 175 return sName;
218} 176}
219 177/*
220void XmlNode::deleteNode( int nIndex, const char *sReplacementText ) 178void XmlNode::deleteNode( int nIndex, const char *sReplacementText )
221{ 179{
222 XmlNode *xRet = detatchNode( nIndex, sReplacementText ); 180 XmlNode *xRet = detatchNode( nIndex, sReplacementText );
@@ -442,4 +400,4 @@ void XmlNode::deleteNodeKeepChildren( int nIndex )
442void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ) 400void XmlNode::replaceNodeWithChildren( int nIndex, XmlNode *pNewNode )
443{ 401{
444} 402}
445 403*/
diff --git a/src/xmlnode.h b/src/old/xmlnode.h
index 7525306..c895cd8 100644
--- a/src/xmlnode.h
+++ b/src/old/xmlnode.h
@@ -2,8 +2,9 @@
2#define XMLNODE 2#define XMLNODE
3 3
4#include <iostream> 4#include <iostream>
5#include "linkedlist.h" 5#include "bu/list.h"
6#include "hashtable.h" 6#include "bu/hash.h"
7#include "bu/fstring.h"
7 8
8/** 9/**
9 * Maintains all data pertient to an XML node, including sub-nodes and content. 10 * Maintains all data pertient to an XML node, including sub-nodes and content.
@@ -25,9 +26,8 @@ public:
25 *@param sContent The initial content string. 26 *@param sContent The initial content string.
26 */ 27 */
27 XmlNode( 28 XmlNode(
28 const char *sName=NULL, 29 const Bu::FString &sName,
29 XmlNode *pParent = NULL, 30 XmlNode *pParent=NULL
30 const char *sContent=NULL
31 ); 31 );
32 32
33 /** 33 /**
@@ -39,7 +39,7 @@ public:
39 * Change the name of the node. 39 * Change the name of the node.
40 *@param sName The new name of the node. 40 *@param sName The new name of the node.
41 */ 41 */
42 void setName( const char *sName ); 42 //void setName( const char *sName );
43 43
44 /** 44 /**
45 * Construct a new node and add it as a child to this node, also return a 45 * Construct a new node and add it as a child to this node, also return a
@@ -48,7 +48,7 @@ public:
48 *@param sContent The initial content of the new node. 48 *@param sContent The initial content of the new node.
49 *@returns A pointer to the newly created child node. 49 *@returns A pointer to the newly created child node.
50 */ 50 */
51 XmlNode *addChild( const char *sName, const char *sContent=NULL ); 51 XmlNode *addChild( const Bu::FString &sName );
52 52
53 /** 53 /**
54 * Add an already created XmlNode as a child to this node. The new child 54 * Add an already created XmlNode as a child to this node. The new child
@@ -65,7 +65,7 @@ public:
65 * in use will overwrite that property. 65 * in use will overwrite that property.
66 *@param sValue The textual value of the property. 66 *@param sValue The textual value of the property.
67 */ 67 */
68 void addProperty( const char *sName, const char *sValue ); 68 void addProperty( const Bu::FString &sName, const Bu::FString &sValue );
69 69
70 /** 70 /**
71 * Get a pointer to the parent node, if any. 71 * Get a pointer to the parent node, if any.
@@ -86,14 +86,6 @@ public:
86 int getNumChildren(); 86 int getNumChildren();
87 87
88 /** 88 /**
89 * Get a child node at a specific index.
90 *@param nIndex The zero-based index of the child to retreive.
91 *@returns A pointer to the child, or NULL if you requested an invalid
92 * index.
93 */
94 XmlNode *getChild( int nIndex );
95
96 /**
97 * Get a child with the specified name, and possibly skip value. For an 89 * Get a child with the specified name, and possibly skip value. For an
98 * explination of skip values see the HashTable. 90 * explination of skip values see the HashTable.
99 *@param sName The name of the child to find. 91 *@param sName The name of the child to find.
@@ -101,14 +93,14 @@ public:
101 *@returns A pointer to the child, or NULL if no child with that name was 93 *@returns A pointer to the child, or NULL if no child with that name was
102 * found. 94 * found.
103 */ 95 */
104 XmlNode *getChild( const char *sName, int nSkip=0 ); 96 XmlNode *getChild( const Bu::FString &sName, int nSkip=0 );
105 97
106 /** 98 /**
107 * Get a pointer to the name of this node. Do not change this, use setName 99 * Get a pointer to the name of this node. Do not change this, use setName
108 * instead. 100 * instead.
109 *@returns A pointer to the name of this node. 101 *@returns A pointer to the name of this node.
110 */ 102 */
111 const char *getName(); 103 Bu::FString getName();
112 104
113 /** 105 /**
114 * Set the content of this node, optionally at a specific index. Using the 106 * Set the content of this node, optionally at a specific index. Using the
@@ -116,14 +108,7 @@ public:
116 *@param sContent The content string to use. 108 *@param sContent The content string to use.
117 *@param nIndex The index of the content. 109 *@param nIndex The index of the content.
118 */ 110 */
119 void setContent( const char *sContent, int nIndex=-1 ); 111 //void setContent( const char *sContent, int nIndex=-1 );
120
121 /**
122 * Get the content string at a given index, or zero for initial content.
123 *@param nIndex The index of the content.
124 *@returns A pointer to the content at that location.
125 */
126 const char *getContent( int nIndex = 0 );
127 112
128 /** 113 /**
129 * Get the number of properties in this node. 114 * Get the number of properties in this node.
@@ -132,36 +117,12 @@ public:
132 int getNumProperties(); 117 int getNumProperties();
133 118
134 /** 119 /**
135 * Get a property's name by index.
136 *@param nIndex The index of the property to examine.
137 *@returns A pointer to the name of the property specified, or NULL if none
138 * found.
139 */
140 const char *getPropertyName( int nIndex );
141
142 /**
143 * Get a proprty's value by index.
144 *@param nIndex The index of the property to examine.
145 *@returns A pointer to the value of the property specified, or NULL if none
146 * found.
147 */
148 const char *getProperty( int nIndex );
149
150 /**
151 * Get a propery's value by name. 120 * Get a propery's value by name.
152 *@param sName The name of the property to examine. 121 *@param sName The name of the property to examine.
153 *@returns A pointer to the value of the property specified, or NULL if none 122 *@returns A pointer to the value of the property specified, or NULL if none
154 * found. 123 * found.
155 */ 124 */
156 const char *getProperty( const char *sName ); 125 Bu::FString getProperty( const Bu::FString &sName );
157
158 /**
159 * Delete a property by index.
160 *@param nIndex The index of the property to delete.
161 *@returns True if the property was found and deleted, false if it wasn't
162 * found.
163 */
164 void deleteProperty( int nIndex );
165 126
166 /** 127 /**
167 * Delete a child node, possibly replacing it with some text. This actually 128 * Delete a child node, possibly replacing it with some text. This actually
@@ -171,7 +132,7 @@ public:
171 *@returns True of the node was found, and deleted, false if it wasn't 132 *@returns True of the node was found, and deleted, false if it wasn't
172 * found. 133 * found.
173 */ 134 */
174 void deleteNode( int nIndex, const char *sReplacementText = NULL ); 135 //void deleteNode( int nIndex, const char *sReplacementText = NULL );
175 136
176 /** 137 /**
177 * Delete a given node, but move all of it's children and content up to 138 * Delete a given node, but move all of it's children and content up to
@@ -180,7 +141,7 @@ public:
180 *@param nIndex The node to delete. 141 *@param nIndex The node to delete.
181 *@returns True if the node was found and deleted, false if it wasn't. 142 *@returns True if the node was found and deleted, false if it wasn't.
182 */ 143 */
183 void deleteNodeKeepChildren( int nIndex ); 144 //void deleteNodeKeepChildren( int nIndex );
184 145
185 /** 146 /**
186 * Detatch a given child node from this node. This effectively works just 147 * Detatch a given child node from this node. This effectively works just
@@ -192,7 +153,7 @@ public:
192 *@returns A pointer to the newly detatched node, which then passes 153 *@returns A pointer to the newly detatched node, which then passes
193 * ownership to the caller. 154 * ownership to the caller.
194 */ 155 */
195 XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL ); 156 //XmlNode *detatchNode( int nIndex, const char *sReplacementText = NULL );
196 157
197 /** 158 /**
198 * Replace a given node with a different node that is not currently owned by 159 * Replace a given node with a different node that is not currently owned by
@@ -201,7 +162,7 @@ public:
201 *@param pNewNode The new node to replace the old node with. 162 *@param pNewNode The new node to replace the old node with.
202 *@returns True if the node was found and replaced, false if it wasn't. 163 *@returns True if the node was found and replaced, false if it wasn't.
203 */ 164 */
204 void replaceNode( int nIndex, XmlNode *pNewNode ); 165 //void replaceNode( int nIndex, XmlNode *pNewNode );
205 166
206 /** 167 /**
207 * Replace a given node with the children and content of a given node. 168 * Replace a given node with the children and content of a given node.
@@ -210,24 +171,34 @@ public:
210 * replace the node specified by nIndex. 171 * replace the node specified by nIndex.
211 *@returns True if the node was found and replaced, false if it wasn't. 172 *@returns True if the node was found and replaced, false if it wasn't.
212 */ 173 */
213 void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode ); 174 //void replaceNodeWithChildren( int nIndex, XmlNode *pNewNode );
214 175
215 /** 176 /**
216 * Get a copy of this node and all children. getCopy is recursive, so 177 * Get a copy of this node and all children. getCopy is recursive, so
217 * beware copying large trees of xml. 178 * beware copying large trees of xml.
218 *@returns A newly created copy of this node and all of it's children. 179 *@returns A newly created copy of this node and all of it's children.
219 */ 180 */
220 XmlNode *getCopy(); 181 //XmlNode *getCopy();
182
183 enum ChildType
184 {
185 typeNode,
186 typeContent
187 };
221 188
222private: 189private:
223 std::string sName; /**< The name of the node. */ 190 typedef struct
224 std::string *sPreContent; /**< The content that goes before any node. */ 191 {
225 LinkedList lChildren; /**< The children. */ 192 uint8_t nType;
226 LinkedList lPostContent; /**< The content that comes after children. */ 193 union {
227 HashTable hProperties; /**< Property hashtable. */ 194 XmlNode *pNode;
228 HashTable hChildren; /**< Children hashtable. */ 195 Bu::FString *pContent;
229 LinkedList lPropNames; /**< List of property names. */ 196 };
230 LinkedList lPropValues; /**< List of property values. */ 197 } Child;
198 Bu::FString sName; /**< The name of the node. */
199 Bu::List<Child> lChildren; /**< The children. */
200 Bu::Hash<Bu::FString, Bu::FString> hProperties; /**< Property hashtable. */
201 Bu::Hash<Bu::FString, Bu::List<XmlNode *> > hChildren; /**< Children hashtable. */
231 XmlNode *pParent; /**< A pointer to the parent of this node. */ 202 XmlNode *pParent; /**< A pointer to the parent of this node. */
232 int nCurContent; /**< The current content we're on, for using the -1 on 203 int nCurContent; /**< The current content we're on, for using the -1 on
233 setContent. */ 204 setContent. */
diff --git a/src/xmlreader.cpp b/src/old/xmlreader.cpp
index 18df69c..38cad5f 100644
--- a/src/xmlreader.cpp
+++ b/src/old/xmlreader.cpp
@@ -1,32 +1,49 @@
1#include "xmlreader.h" 1#include "bu/xmlreader.h"
2#include "exceptions.h" 2#include "bu/exceptions.h"
3#include <string.h> 3#include <string.h>
4#include "hashfunctionstring.h"
5 4
6XmlReader::XmlReader( bool bStrip ) : 5XmlReader::XmlReader( Bu::Stream &sIn, bool bStrip ) :
7 bStrip( bStrip ), 6 sIn( sIn ),
8 htEntity( new HashFunctionString(), 11 ) 7 bStrip( bStrip )
9{ 8{
9 buildDoc();
10} 10}
11 11
12XmlReader::~XmlReader() 12XmlReader::~XmlReader()
13{ 13{
14 void *i = htEntity.getFirstItemPos(); 14}
15 while( (i = htEntity.getNextItemPos( i ) ) ) 15
16char XmlReader::getChar( int nIndex )
17{
18 if( sBuf.getSize() <= nIndex )
16 { 19 {
17 free( (char *)(htEntity.getItemID( i )) ); 20 int nInc = nIndex-sBuf.getSize()+1;
18 delete (StaticString *)htEntity.getItemData( i ); 21 char *buf = new char[nInc];
22 sIn.read( buf, nInc );
23 sBuf.append( buf, nInc );
24 delete[] buf;
19 } 25 }
26
27 return sBuf[nIndex];
20} 28}
21 29
22void XmlReader::addEntity( const char *name, const char *value ) 30void XmlReader::usedChar( int nAmnt )
23{ 31{
24 if( htEntity[name] ) return; 32 if( nAmnt >= sBuf.getSize() )
25 33 {
26 char *sName = strdup( name ); 34 sBuf.clear();
27 StaticString *sValue = new StaticString( value ); 35 }
36 else
37 {
38 char *s = sBuf.getStr();
39 memcpy( s, s+nAmnt, sBuf.getSize()-nAmnt );
40 sBuf.resize( sBuf.getSize()-nAmnt );
41 }
42}
28 43
29 htEntity.insert( sName, sValue ); 44void XmlReader::addEntity( const Bu::FString &name, const Bu::FString &value )
45{
46 htEntity[name] = value;
30} 47}
31 48
32#define gcall( x ) if( x == false ) return false; 49#define gcall( x ) if( x == false ) return false;
@@ -99,7 +116,7 @@ void XmlReader::entity()
99 { 116 {
100 usedChar( 2 ); 117 usedChar( 2 );
101 ws(); 118 ws();
102 std::string buf; 119 Bu::FString buf;
103 for(;;) 120 for(;;)
104 { 121 {
105 char chr = getChar(); 122 char chr = getChar();
@@ -111,7 +128,7 @@ void XmlReader::entity()
111 if( strcmp( buf.c_str(), "ENTITY") == 0 ) 128 if( strcmp( buf.c_str(), "ENTITY") == 0 )
112 { 129 {
113 ws(); 130 ws();
114 std::string name; 131 Bu::FString name;
115 for(;;) 132 for(;;)
116 { 133 {
117 char chr = getChar(); 134 char chr = getChar();
@@ -124,21 +141,19 @@ void XmlReader::entity()
124 usedChar(); 141 usedChar();
125 if( quot != '\'' && quot != '\"' ) 142 if( quot != '\'' && quot != '\"' )
126 { 143 {
127 throw XmlException( 144 throw Bu::XmlException(
128 "Only quoted entity values are supported." 145 "Only quoted entity values are supported."
129 ); 146 );
130 } 147 }
131 std::string value; 148 Bu::FString value;
132 for(;;) 149 for(;;)
133 { 150 {
134 char chr = getChar(); 151 char chr = getChar();
135 usedChar(); 152 usedChar();
136 if( chr == '&' ) 153 if( chr == '&' )
137 { 154 {
138 StaticString *tmp = getEscape(); 155 Bu::FString tmp = getEscape();
139 if( tmp == NULL ) throw XmlException("Entity thing"); 156 value += tmp;
140 value += tmp->getString();
141 delete tmp;
142 } 157 }
143 else if( chr == quot ) 158 else if( chr == quot )
144 { 159 {
@@ -158,7 +173,7 @@ void XmlReader::entity()
158 } 173 }
159 else 174 else
160 { 175 {
161 throw XmlException( 176 throw Bu::XmlException(
162 "Malformed ENTITY: unexpected '%c' found.", 177 "Malformed ENTITY: unexpected '%c' found.",
163 getChar() 178 getChar()
164 ); 179 );
@@ -166,7 +181,7 @@ void XmlReader::entity()
166 } 181 }
167 else 182 else
168 { 183 {
169 throw XmlException( 184 throw Bu::XmlException(
170 "Unsupported header symbol: %s", 185 "Unsupported header symbol: %s",
171 buf.c_str() 186 buf.c_str()
172 ); 187 );
@@ -203,12 +218,12 @@ bool XmlReader::node()
203 } 218 }
204 else 219 else
205 { 220 {
206 throw XmlException("Close node in singleNode malformed!"); 221 throw Bu::XmlException("Close node in singleNode malformed!");
207 } 222 }
208 } 223 }
209 else 224 else
210 { 225 {
211 throw XmlException("Close node expected, but not found."); 226 throw Bu::XmlException("Close node expected, but not found.");
212 return false; 227 return false;
213 } 228 }
214 229
@@ -224,7 +239,7 @@ bool XmlReader::startNode()
224 if( getChar() == '/' ) 239 if( getChar() == '/' )
225 { 240 {
226 // Heh, it's actually a close node, go figure 241 // Heh, it's actually a close node, go figure
227 FlexBuf fbName; 242 Bu::FString sName;
228 usedChar(); 243 usedChar();
229 gcall( ws() ); 244 gcall( ws() );
230 245
@@ -235,19 +250,19 @@ bool XmlReader::startNode()
235 { 250 {
236 // Here we actually compare the name we got to the name 251 // Here we actually compare the name we got to the name
237 // we already set, they have to match exactly. 252 // we already set, they have to match exactly.
238 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 253 if( getCurrent()->getName() == sName )
239 { 254 {
240 closeNode(); 255 closeNode();
241 break; 256 break;
242 } 257 }
243 else 258 else
244 { 259 {
245 throw XmlException("Got a mismatched node close tag."); 260 throw Bu::XmlException("Got a mismatched node close tag.");
246 } 261 }
247 } 262 }
248 else 263 else
249 { 264 {
250 fbName.appendData( chr ); 265 sName += chr;
251 usedChar(); 266 usedChar();
252 } 267 }
253 } 268 }
@@ -260,13 +275,13 @@ bool XmlReader::startNode()
260 } 275 }
261 else 276 else
262 { 277 {
263 throw XmlException("Got extra junk data instead of node close tag."); 278 throw Bu::XmlException("Got extra junk data instead of node close tag.");
264 } 279 }
265 } 280 }
266 else 281 else
267 { 282 {
268 // We're good, format is consistant 283 // We're good, format is consistant
269 addNode(); 284 //addNode();
270 285
271 // Skip extra whitespace 286 // Skip extra whitespace
272 gcall( ws() ); 287 gcall( ws() );
@@ -278,7 +293,7 @@ bool XmlReader::startNode()
278 } 293 }
279 else 294 else
280 { 295 {
281 throw XmlException("Expected to find node opening char, '<'."); 296 throw Bu::XmlException("Expected to find node opening char, '<'.");
282 } 297 }
283 298
284 return true; 299 return true;
@@ -286,19 +301,19 @@ bool XmlReader::startNode()
286 301
287bool XmlReader::name() 302bool XmlReader::name()
288{ 303{
289 FlexBuf fbName; 304 Bu::FString sName;
290 305
291 while( true ) 306 while( true )
292 { 307 {
293 char chr = getChar(); 308 char chr = getChar();
294 if( isws( chr ) || chr == '>' || chr == '/' ) 309 if( isws( chr ) || chr == '>' || chr == '/' )
295 { 310 {
296 setName( fbName.getData() ); 311 addNode( sName );
297 return true; 312 return true;
298 } 313 }
299 else 314 else
300 { 315 {
301 fbName.appendData( chr ); 316 sName += chr;
302 usedChar(); 317 usedChar();
303 } 318 }
304 } 319 }
@@ -325,7 +340,7 @@ bool XmlReader::paramlist()
325 return true; 340 return true;
326} 341}
327 342
328StaticString *XmlReader::getEscape() 343Bu::FString XmlReader::getEscape()
329{ 344{
330 if( getChar( 1 ) == '#' ) 345 if( getChar( 1 ) == '#' )
331 { 346 {
@@ -349,12 +364,12 @@ StaticString *XmlReader::getEscape()
349 buf[0] = (char)strtol( buf, (char **)NULL, base ); 364 buf[0] = (char)strtol( buf, (char **)NULL, base );
350 buf[1] = '\0'; 365 buf[1] = '\0';
351 366
352 return new StaticString( buf ); 367 return buf;
353 } 368 }
354 else 369 else
355 { 370 {
356 // ...otherwise replace with the appropriate string... 371 // ...otherwise replace with the appropriate string...
357 std::string buf; 372 Bu::FString buf;
358 usedChar(); 373 usedChar();
359 for(;;) 374 for(;;)
360 { 375 {
@@ -364,18 +379,14 @@ StaticString *XmlReader::getEscape()
364 buf += cbuf; 379 buf += cbuf;
365 } 380 }
366 381
367 StaticString *tmp = (StaticString *)htEntity[buf.c_str()]; 382 return htEntity[buf];
368 if( tmp == NULL ) return NULL;
369
370 StaticString *ret = new StaticString( *tmp );
371 return ret;
372 } 383 }
373} 384}
374 385
375bool XmlReader::param() 386bool XmlReader::param()
376{ 387{
377 FlexBuf fbName; 388 Bu::FString sName;
378 FlexBuf fbValue; 389 Bu::FString sValue;
379 390
380 while( true ) 391 while( true )
381 { 392 {
@@ -386,7 +397,7 @@ bool XmlReader::param()
386 } 397 }
387 else 398 else
388 { 399 {
389 fbName.appendData( chr ); 400 sName.append( chr );
390 usedChar(); 401 usedChar();
391 } 402 }
392 } 403 }
@@ -411,21 +422,18 @@ bool XmlReader::param()
411 if( chr == '"' ) 422 if( chr == '"' )
412 { 423 {
413 usedChar(); 424 usedChar();
414 addProperty( fbName.getData(), fbValue.getData() ); 425 addProperty( sName.getStr(), sValue.getStr() );
415 return true; 426 return true;
416 } 427 }
417 else 428 else
418 { 429 {
419 if( chr == '&' ) 430 if( chr == '&' )
420 { 431 {
421 StaticString *tmp = getEscape(); 432 sValue += getEscape();
422 if( tmp == NULL ) return false;
423 fbValue.appendData( tmp->getString() );
424 delete tmp;
425 } 433 }
426 else 434 else
427 { 435 {
428 fbValue.appendData( chr ); 436 sValue += chr;
429 usedChar(); 437 usedChar();
430 } 438 }
431 } 439 }
@@ -439,21 +447,18 @@ bool XmlReader::param()
439 chr = getChar(); 447 chr = getChar();
440 if( isws( chr ) || chr == '/' || chr == '>' ) 448 if( isws( chr ) || chr == '/' || chr == '>' )
441 { 449 {
442 addProperty( fbName.getData(), fbValue.getData() ); 450 addProperty( sName.getStr(), sValue.getStr() );
443 return true; 451 return true;
444 } 452 }
445 else 453 else
446 { 454 {
447 if( chr == '&' ) 455 if( chr == '&' )
448 { 456 {
449 StaticString *tmp = getEscape(); 457 sValue += getEscape();
450 if( tmp == NULL ) return false;
451 fbValue.appendData( tmp->getString() );
452 delete tmp;
453 } 458 }
454 else 459 else
455 { 460 {
456 fbValue.appendData( chr ); 461 sValue += chr;
457 usedChar(); 462 usedChar();
458 } 463 }
459 } 464 }
@@ -462,7 +467,7 @@ bool XmlReader::param()
462 } 467 }
463 else 468 else
464 { 469 {
465 throw XmlException("Expected an equals to seperate the params."); 470 throw Bu::XmlException("Expected an equals to seperate the params.");
466 return false; 471 return false;
467 } 472 }
468 473
@@ -471,7 +476,7 @@ bool XmlReader::param()
471 476
472bool XmlReader::content() 477bool XmlReader::content()
473{ 478{
474 FlexBuf fbContent; 479 Bu::FString sContent;
475 480
476 if( bStrip ) gcall( ws() ); 481 if( bStrip ) gcall( ws() );
477 482
@@ -482,37 +487,37 @@ bool XmlReader::content()
482 { 487 {
483 if( getChar(1) == '/' ) 488 if( getChar(1) == '/' )
484 { 489 {
485 if( fbContent.getLength() > 0 ) 490 if( sContent.getSize() > 0 )
486 { 491 {
487 if( bStrip ) 492 if( bStrip )
488 { 493 {
489 int j; 494 int j;
490 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 495 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
491 ((char *)fbContent.getData())[j+1] = '\0'; 496 sContent[j+1] = '\0';
492 } 497 }
493 setContent( fbContent.getData() ); 498 setContent( sContent.getStr() );
494 } 499 }
495 usedChar( 2 ); 500 usedChar( 2 );
496 gcall( ws() ); 501 gcall( ws() );
497 FlexBuf fbName; 502 Bu::FString sName;
498 while( true ) 503 while( true )
499 { 504 {
500 chr = getChar(); 505 chr = getChar();
501 if( isws( chr ) || chr == '>' ) 506 if( isws( chr ) || chr == '>' )
502 { 507 {
503 if( !strcasecmp( getCurrent()->getName(), fbName.getData() ) ) 508 if( !strcasecmp( getCurrent()->getName().getStr(), sName.getStr() ) )
504 { 509 {
505 closeNode(); 510 closeNode();
506 break; 511 break;
507 } 512 }
508 else 513 else
509 { 514 {
510 throw XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName(), fbName.getData() ); 515 throw Bu::XmlException("Mismatched close tag found: <%s> to <%s>.", getCurrent()->getName().getStr(), sName.getStr() );
511 } 516 }
512 } 517 }
513 else 518 else
514 { 519 {
515 fbName.appendData( chr ); 520 sName += chr;
516 usedChar(); 521 usedChar();
517 } 522 }
518 } 523 }
@@ -524,7 +529,7 @@ bool XmlReader::content()
524 } 529 }
525 else 530 else
526 { 531 {
527 throw XmlException("Malformed close tag."); 532 throw Bu::XmlException("Malformed close tag.");
528 } 533 }
529 } 534 }
530 else if( getChar(1) == '!' ) 535 else if( getChar(1) == '!' )
@@ -534,7 +539,7 @@ bool XmlReader::content()
534 getChar(3) != '-' ) 539 getChar(3) != '-' )
535 { 540 {
536 // Not a valid XML comment 541 // Not a valid XML comment
537 throw XmlException("Malformed comment start tag found."); 542 throw Bu::XmlException("Malformed comment start tag found.");
538 } 543 }
539 544
540 usedChar( 4 ); 545 usedChar( 4 );
@@ -549,7 +554,7 @@ bool XmlReader::content()
549 // The next one has to be a '>' now 554 // The next one has to be a '>' now
550 if( getChar( 2 ) != '>' ) 555 if( getChar( 2 ) != '>' )
551 { 556 {
552 throw XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment."); 557 throw Bu::XmlException("Malformed comment close tag found. You cannot have a '--' that isn't followed by a '>' in a comment.");
553 } 558 }
554 usedChar( 3 ); 559 usedChar( 3 );
555 break; 560 break;
@@ -569,16 +574,16 @@ bool XmlReader::content()
569 } 574 }
570 else 575 else
571 { 576 {
572 if( fbContent.getLength() > 0 ) 577 if( sContent.getSize() > 0 )
573 { 578 {
574 if( bStrip ) 579 if( bStrip )
575 { 580 {
576 int j; 581 int j;
577 for( j = fbContent.getLength()-1; isws(fbContent.getData()[j]); j-- ); 582 for( j = sContent.getSize()-1; isws(sContent[j]); j-- );
578 ((char *)fbContent.getData())[j+1] = '\0'; 583 sContent[j+1] = '\0';
579 } 584 }
580 setContent( fbContent.getData() ); 585 setContent( sContent.getStr() );
581 fbContent.clearData(); 586 sContent.clear();
582 } 587 }
583 gcall( node() ); 588 gcall( node() );
584 } 589 }
@@ -587,14 +592,11 @@ bool XmlReader::content()
587 } 592 }
588 else if( chr == '&' ) 593 else if( chr == '&' )
589 { 594 {
590 StaticString *tmp = getEscape(); 595 sContent += getEscape();
591 if( tmp == NULL ) return false;
592 fbContent.appendData( tmp->getString() );
593 delete tmp;
594 } 596 }
595 else 597 else
596 { 598 {
597 fbContent.appendData( chr ); 599 sContent += chr;
598 usedChar(); 600 usedChar();
599 } 601 }
600 } 602 }
diff --git a/src/xmlreader.h b/src/old/xmlreader.h
index c8f7202..7c85ddb 100644
--- a/src/xmlreader.h
+++ b/src/old/xmlreader.h
@@ -2,10 +2,10 @@
2#define XMLREADER 2#define XMLREADER
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include "xmldocument.h" 5#include "bu/xmldocument.h"
6#include "flexbuf.h" 6#include "bu/hash.h"
7#include "hashtable.h" 7#include "bu/fstring.h"
8#include "staticstring.h" 8#include "bu/stream.h"
9 9
10/** 10/**
11 * Takes care of reading in xml formatted data from a file. This could/should 11 * Takes care of reading in xml formatted data from a file. This could/should
@@ -32,7 +32,7 @@ public:
32 * in content, a-la html. 32 * in content, a-la html.
33 *@param bStrip Strip out leading and trailing whitespace? 33 *@param bStrip Strip out leading and trailing whitespace?
34 */ 34 */
35 XmlReader( bool bStrip=false ); 35 XmlReader( Bu::Stream &sIn, bool bStrip=false );
36 36
37 /** 37 /**
38 * Destroy this XmlReader. 38 * Destroy this XmlReader.
@@ -54,12 +54,12 @@ private:
54 *@returns A single character at the requested position, or 0 for end of 54 *@returns A single character at the requested position, or 0 for end of
55 * stream. 55 * stream.
56 */ 56 */
57 virtual char getChar( int nIndex = 0 ) = 0; 57 virtual char getChar( int nIndex = 0 );
58 58
59 /** 59 /**
60 * Called to increment the current stream position by a single character. 60 * Called to increment the current stream position by a single character.
61 */ 61 */
62 virtual void usedChar( int nAmnt = 1) = 0; 62 virtual void usedChar( int nAmnt = 1 );
63 63
64 /** 64 /**
65 * Automoton function: is whitespace. 65 * Automoton function: is whitespace.
@@ -108,9 +108,9 @@ private:
108 *@param name The name of the entity 108 *@param name The name of the entity
109 *@param value The value of the entity 109 *@param value The value of the entity
110 */ 110 */
111 void addEntity( const char *name, const char *value ); 111 void addEntity( const Bu::FString &name, const Bu::FString &value );
112 112
113 StaticString *getEscape(); 113 Bu::FString getEscape();
114 114
115 /** 115 /**
116 * Automoton function: paramlist. Processes a list of node params. 116 * Automoton function: paramlist. Processes a list of node params.
@@ -130,12 +130,15 @@ private:
130 */ 130 */
131 bool content(); 131 bool content();
132 132
133 FlexBuf fbContent; /**< buffer for the current node's content. */ 133 Bu::FString sContent; /**< buffer for the current node's content. */
134 FlexBuf fbParamName; /**< buffer for the current param's name. */ 134 Bu::FString sParamName; /**< buffer for the current param's name. */
135 FlexBuf fbParamValue; /**< buffer for the current param's value. */ 135 Bu::FString sParamValue; /**< buffer for the current param's value. */
136 bool bStrip; /**< Are we stripping whitespace? */ 136 Bu::Stream &sIn;
137 bool bStrip; /**< Are we stripping whitespace? */
137 138
138 HashTable htEntity; /**< Entity type definitions. */ 139 Bu::Hash<Bu::FString,Bu::FString> htEntity; /**< Entity type definitions. */
140
141 Bu::FString sBuf;
139}; 142};
140 143
141#endif 144#endif
diff --git a/src/xmlstringreader.cpp b/src/old/xmlstringreader.cpp
index 3956ff3..3956ff3 100644
--- a/src/xmlstringreader.cpp
+++ b/src/old/xmlstringreader.cpp
diff --git a/src/xmlstringreader.h b/src/old/xmlstringreader.h
index 1239ef4..1239ef4 100644
--- a/src/xmlstringreader.h
+++ b/src/old/xmlstringreader.h
diff --git a/src/xmlstringwriter.cpp b/src/old/xmlstringwriter.cpp
index adeed6a..adeed6a 100644
--- a/src/xmlstringwriter.cpp
+++ b/src/old/xmlstringwriter.cpp
diff --git a/src/xmlstringwriter.h b/src/old/xmlstringwriter.h
index 0d567b9..0d567b9 100644
--- a/src/xmlstringwriter.h
+++ b/src/old/xmlstringwriter.h
diff --git a/src/xmlwriter.cpp b/src/old/xmlwriter.cpp
index 56880b6..7dc6ca9 100644
--- a/src/xmlwriter.cpp
+++ b/src/old/xmlwriter.cpp
@@ -2,17 +2,10 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include "xmlwriter.h" 3#include "xmlwriter.h"
4 4
5XmlWriter::XmlWriter( const char *sIndent, XmlNode *pRoot ) : 5XmlWriter::XmlWriter( const Bu::FString &sIndent, XmlNode *pRoot ) :
6 XmlDocument( pRoot ) 6 XmlDocument( pRoot ),
7 sIndent( sIndent )
7{ 8{
8 if( sIndent == NULL )
9 {
10 this->sIndent = "";
11 }
12 else
13 {
14 this->sIndent = sIndent;
15 }
16} 9}
17 10
18XmlWriter::~XmlWriter() 11XmlWriter::~XmlWriter()
@@ -24,7 +17,7 @@ void XmlWriter::write()
24 write( getRoot(), sIndent.c_str() ); 17 write( getRoot(), sIndent.c_str() );
25} 18}
26 19
27void XmlWriter::write( XmlNode *pRoot, const char *sIndent ) 20void XmlWriter::write( XmlNode *pRoot, const Bu::FString &sIndent )
28{ 21{
29 writeNode( pRoot, 0, sIndent ); 22 writeNode( pRoot, 0, sIndent );
30} 23}
@@ -39,7 +32,7 @@ void XmlWriter::closeNode()
39 } 32 }
40} 33}
41 34
42void XmlWriter::writeIndent( int nIndent, const char *sIndent ) 35void XmlWriter::writeIndent( int nIndent, const Bu::FString &sIndent )
43{ 36{
44 if( sIndent == NULL ) return; 37 if( sIndent == NULL ) return;
45 for( int j = 0; j < nIndent; j++ ) 38 for( int j = 0; j < nIndent; j++ )
@@ -48,26 +41,27 @@ void XmlWriter::writeIndent( int nIndent, const char *sIndent )
48 } 41 }
49} 42}
50 43
51std::string XmlWriter::escape( std::string sIn ) 44Bu::FString XmlWriter::escape( const Bu::FString &sIn )
52{ 45{
53 std::string sOut; 46 Bu::FString sOut;
54 47
55 std::string::const_iterator i; 48 int nMax = sIn.getSize();
56 for( i = sIn.begin(); i != sIn.end(); i++ ) 49 for( int j = 0; j < nMax; j++ )
57 { 50 {
58 if( ((*i >= ' ' && *i <= '9') || 51 char c = sIn[j];
59 (*i >= 'a' && *i <= 'z') || 52 if( ((c >= ' ' && c <= '9') ||
60 (*i >= 'A' && *i <= 'Z') ) && 53 (c >= 'a' && c <= 'z') ||
61 (*i != '\"' && *i != '\'' && *i != '&') 54 (c >= 'A' && c <= 'Z') ) &&
55 (c != '\"' && c != '\'' && c != '&')
62 ) 56 )
63 { 57 {
64 sOut += *i; 58 sOut += c;
65 } 59 }
66 else 60 else
67 { 61 {
68 sOut += "&#"; 62 sOut += "&#";
69 char buf[4]; 63 char buf[4];
70 sprintf( buf, "%u", (unsigned char)*i ); 64 sprintf( buf, "%u", (unsigned char)c );
71 sOut += buf; 65 sOut += buf;
72 sOut += ';'; 66 sOut += ';';
73 } 67 }
@@ -76,19 +70,19 @@ std::string XmlWriter::escape( std::string sIn )
76 return sOut; 70 return sOut;
77} 71}
78 72
79void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ) 73void XmlWriter::writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
80{ 74{
81 for( int j = 0; j < pNode->getNumProperties(); j++ ) 75 for( int j = 0; j < pNode->getNumProperties(); j++ )
82 { 76 {
83 writeString(" "); 77 writeString(" ");
84 writeString( pNode->getPropertyName( j ) ); 78 //writeString( pNode->getPropertyName( j ) );
85 writeString("=\""); 79 writeString("=\"");
86 writeString( escape( pNode->getProperty( j ) ).c_str() ); 80 //writeString( escape( pNode->getProperty( j ) ).c_str() );
87 writeString("\""); 81 writeString("\"");
88 } 82 }
89} 83}
90 84
91void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent ) 85void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent )
92{ 86{
93 if( pNode->hasChildren() ) 87 if( pNode->hasChildren() )
94 { 88 {
@@ -96,15 +90,15 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
96 writeString("<"); 90 writeString("<");
97 writeString( pNode->getName() ); 91 writeString( pNode->getName() );
98 writeNodeProps( pNode, nIndent, sIndent ); 92 writeNodeProps( pNode, nIndent, sIndent );
99 if( sIndent ) 93 if( sIndent != "" )
100 writeString(">\n"); 94 writeString(">\n");
101 else 95 else
102 writeString(">"); 96 writeString(">");
103 97/*
104 if( pNode->getContent( 0 ) ) 98 if( pNode->getContent( 0 ) )
105 { 99 {
106 writeIndent( nIndent+1, sIndent ); 100 writeIndent( nIndent+1, sIndent );
107 if( sIndent ) 101 if( sIndent != "" )
108 { 102 {
109 writeString( pNode->getContent( 0 ) ); 103 writeString( pNode->getContent( 0 ) );
110 writeString("\n"); 104 writeString("\n");
@@ -129,9 +123,9 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
129 writeString( pNode->getContent( j+1 ) ); 123 writeString( pNode->getContent( j+1 ) );
130 } 124 }
131 } 125 }
132 126*/
133 writeIndent( nIndent, sIndent ); 127 writeIndent( nIndent, sIndent );
134 if( sIndent ) 128 if( sIndent != "" )
135 { 129 {
136 writeString("</"); 130 writeString("</");
137 writeString( pNode->getName() ); 131 writeString( pNode->getName() );
@@ -143,7 +137,7 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
143 writeString( pNode->getName() ); 137 writeString( pNode->getName() );
144 writeString(">"); 138 writeString(">");
145 } 139 }
146 } 140 }/*
147 else if( pNode->getContent() ) 141 else if( pNode->getContent() )
148 { 142 {
149 writeIndent( nIndent, sIndent ); 143 writeIndent( nIndent, sIndent );
@@ -157,14 +151,14 @@ void XmlWriter::writeNode( XmlNode *pNode, int nIndent, const char *sIndent )
157 writeString(">"); 151 writeString(">");
158 if( sIndent ) 152 if( sIndent )
159 writeString("\n"); 153 writeString("\n");
160 } 154 }*/
161 else 155 else
162 { 156 {
163 writeIndent( nIndent, sIndent ); 157 writeIndent( nIndent, sIndent );
164 writeString("<"); 158 writeString("<");
165 writeString( pNode->getName() ); 159 writeString( pNode->getName() );
166 writeNodeProps( pNode, nIndent, sIndent ); 160 writeNodeProps( pNode, nIndent, sIndent );
167 if( sIndent ) 161 if( sIndent != "" )
168 writeString("/>\n"); 162 writeString("/>\n");
169 else 163 else
170 writeString("/>"); 164 writeString("/>");
diff --git a/src/xmlwriter.h b/src/old/xmlwriter.h
index c48e810..7e3c876 100644
--- a/src/xmlwriter.h
+++ b/src/old/xmlwriter.h
@@ -31,7 +31,7 @@ public:
31 * this to a tab or some spaces it will never effect the content of your 31 * this to a tab or some spaces it will never effect the content of your
32 * file. 32 * file.
33 */ 33 */
34 XmlWriter( const char *sIndent=NULL, XmlNode *pRoot=NULL ); 34 XmlWriter( const Bu::FString &sIndent="", XmlNode *pRoot=NULL );
35 35
36 /** 36 /**
37 * Destroy the writer. 37 * Destroy the writer.
@@ -49,16 +49,16 @@ public:
49 void write(); 49 void write();
50 50
51private: 51private:
52 std::string sIndent; /**< The indent string */ 52 Bu::FString sIndent; /**< The indent string */
53 53
54 std::string escape( std::string sIn ); 54 Bu::FString escape( const Bu::FString &sIn );
55 55
56 /** 56 /**
57 * Write the file. 57 * Write the file.
58 *@param pNode The root node 58 *@param pNode The root node
59 *@param sIndent The indent text. 59 *@param sIndent The indent text.
60 */ 60 */
61 void write( XmlNode *pNode, const char *sIndent=NULL ); 61 void write( XmlNode *pNode, const Bu::FString &sIndent );
62 62
63 /** 63 /**
64 * Write a node in the file, including children. 64 * Write a node in the file, including children.
@@ -66,7 +66,7 @@ private:
66 *@param nIndent The indent level (the number of times to include sIndent) 66 *@param nIndent The indent level (the number of times to include sIndent)
67 *@param sIndent The indent text. 67 *@param sIndent The indent text.
68 */ 68 */
69 void writeNode( XmlNode *pNode, int nIndent, const char *sIndent ); 69 void writeNode( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
70 70
71 /** 71 /**
72 * Write the properties of a node. 72 * Write the properties of a node.
@@ -74,14 +74,14 @@ private:
74 *@param nIndent The indent level of the containing node 74 *@param nIndent The indent level of the containing node
75 *@param sIndent The indent text. 75 *@param sIndent The indent text.
76 */ 76 */
77 void writeNodeProps( XmlNode *pNode, int nIndent, const char *sIndent ); 77 void writeNodeProps( XmlNode *pNode, int nIndent, const Bu::FString &sIndent );
78 78
79 /** 79 /**
80 * Called to write the actual indent. 80 * Called to write the actual indent.
81 *@param nIndent The indent level. 81 *@param nIndent The indent level.
82 *@param sIndent The indent text. 82 *@param sIndent The indent text.
83 */ 83 */
84 void writeIndent( int nIndent, const char *sIndent ); 84 void writeIndent( int nIndent, const Bu::FString &sIndent );
85 85
86 /** 86 /**
87 * This is the function that must be overridden in order to use this class. 87 * This is the function that must be overridden in order to use this class.
@@ -90,7 +90,7 @@ private:
90 * will break the XML formatting. 90 * will break the XML formatting.
91 *@param sString The string data to write to the output. 91 *@param sString The string data to write to the output.
92 */ 92 */
93 virtual void writeString( const char *sString ) = 0; 93 virtual void writeString( const Bu::FString &sString ) = 0;
94}; 94};
95 95
96#endif 96#endif
diff --git a/src/paramproc.cpp b/src/paramproc.cpp
index a352e66..34e973e 100644
--- a/src/paramproc.cpp
+++ b/src/paramproc.cpp
@@ -2,10 +2,10 @@
2#include <stdio.h> 2#include <stdio.h>
3 3
4#define ptrtype( iitype, iiname ) \ 4#define ptrtype( iitype, iiname ) \
5 ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ 5 Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \
6 type( vt ##iiname ) { val.iiname = iiname; } 6 type( vt ##iiname ) { val.iiname = iiname; }
7 7
8ParamProc::ParamPtr::ParamPtr() 8Bu::ParamProc::ParamPtr::ParamPtr()
9{ 9{
10 val.str = NULL; 10 val.str = NULL;
11 type = vtunset; 11 type = vtunset;
@@ -25,7 +25,7 @@ ptrtype( double, float64 );
25ptrtype( long double, float96 ); 25ptrtype( long double, float96 );
26ptrtype( bool, bln ); 26ptrtype( bool, bln );
27 27
28ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) 28Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr )
29{ 29{
30 val = ptr.val; 30 val = ptr.val;
31 type = ptr.type; 31 type = ptr.type;
@@ -33,12 +33,12 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr )
33 return *this; 33 return *this;
34} 34}
35 35
36bool ParamProc::ParamPtr::isSet() 36bool Bu::ParamProc::ParamPtr::isSet()
37{ 37{
38 return type != vtunset; 38 return type != vtunset;
39} 39}
40 40
41ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str ) 41Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str )
42{ 42{
43 if( !isSet() ) return *this; 43 if( !isSet() ) return *this;
44 switch( type ) 44 switch( type )
@@ -107,11 +107,11 @@ ParamProc::ParamPtr &ParamProc::ParamPtr::operator=( const char *str )
107 return *this; 107 return *this;
108} 108}
109 109
110ParamProc::ParamProc() 110Bu::ParamProc::ParamProc()
111{ 111{
112} 112}
113 113
114ParamProc::~ParamProc() 114Bu::ParamProc::~ParamProc()
115{ 115{
116 for( std::list<ArgSpec *>::iterator i = lArg.begin(); 116 for( std::list<ArgSpec *>::iterator i = lArg.begin();
117 i != lArg.end(); i++ ) 117 i != lArg.end(); i++ )
@@ -127,14 +127,14 @@ ParamProc::~ParamProc()
127 127
128} 128}
129/* 129/*
130void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) 130void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val )
131{ 131{
132 printf("Calling callback...\n"); 132 printf("Calling callback...\n");
133 val = "Hello there, this is set in the ParamProc"; 133 val = "Hello there, this is set in the ParamProc";
134 (this->*proc)(); 134 (this->*proc)();
135}*/ 135}*/
136 136
137void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, 137void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
138 ParamPtr val, const char *lpDesc, const char *lpExtra, 138 ParamPtr val, const char *lpDesc, const char *lpExtra,
139 const char *lpValue ) 139 const char *lpValue )
140{ 140{
@@ -161,63 +161,63 @@ void ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
161 } 161 }
162} 162}
163 163
164void ParamProc::addParam( const char *lpWord, char cChar, Proc proc, 164void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc,
165 const char *lpDesc, const char *lpExtra, 165 const char *lpDesc, const char *lpExtra,
166 const char *lpValue ) 166 const char *lpValue )
167{ 167{
168 addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 168 addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue );
169} 169}
170 170
171void ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, 171void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val,
172 const char *lpDesc, const char *lpExtra, 172 const char *lpDesc, const char *lpExtra,
173 const char *lpValue ) 173 const char *lpValue )
174{ 174{
175 addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); 175 addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue );
176} 176}
177 177
178void ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, 178void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val,
179 const char *lpDesc, const char *lpExtra, 179 const char *lpDesc, const char *lpExtra,
180 const char *lpValue ) 180 const char *lpValue )
181{ 181{
182 addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); 182 addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue );
183} 183}
184 184
185void ParamProc::addParam( const char *lpWord, Proc proc, 185void Bu::ParamProc::addParam( const char *lpWord, Proc proc,
186 const char *lpDesc, const char *lpExtra, 186 const char *lpDesc, const char *lpExtra,
187 const char *lpValue ) 187 const char *lpValue )
188{ 188{
189 addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 189 addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue );
190} 190}
191 191
192void ParamProc::addParam( const char *lpWord, ParamPtr val, 192void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val,
193 const char *lpDesc, const char *lpExtra, 193 const char *lpDesc, const char *lpExtra,
194 const char *lpValue ) 194 const char *lpValue )
195{ 195{
196 addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); 196 addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue );
197} 197}
198 198
199void ParamProc::addParam( char cChar, Proc proc, ParamPtr val, 199void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val,
200 const char *lpDesc, const char *lpExtra, 200 const char *lpDesc, const char *lpExtra,
201 const char *lpValue ) 201 const char *lpValue )
202{ 202{
203 addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); 203 addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue );
204} 204}
205 205
206void ParamProc::addParam( char cChar, Proc proc, 206void Bu::ParamProc::addParam( char cChar, Proc proc,
207 const char *lpDesc, const char *lpExtra, 207 const char *lpDesc, const char *lpExtra,
208 const char *lpValue ) 208 const char *lpValue )
209{ 209{
210 addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); 210 addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue );
211} 211}
212 212
213void ParamProc::addParam( char cChar, ParamPtr val, 213void Bu::ParamProc::addParam( char cChar, ParamPtr val,
214 const char *lpDesc, const char *lpExtra, 214 const char *lpDesc, const char *lpExtra,
215 const char *lpValue ) 215 const char *lpValue )
216{ 216{
217 addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); 217 addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue );
218} 218}
219 219
220void ParamProc::process( int argc, char *argv[] ) 220void Bu::ParamProc::process( int argc, char *argv[] )
221{ 221{
222 for( int arg = 1; arg < argc; arg++ ) 222 for( int arg = 1; arg < argc; arg++ )
223 { 223 {
@@ -229,23 +229,23 @@ void ParamProc::process( int argc, char *argv[] )
229 ArgSpec *s = checkWord( argv[arg]+2 ); 229 ArgSpec *s = checkWord( argv[arg]+2 );
230 if( s ) 230 if( s )
231 { 231 {
232 if( argv[arg][s->sWord.getLength()+2] == '=' ) 232 if( argv[arg][s->sWord.getSize()+2] == '=' )
233 { 233 {
234 if( s->val.isSet() ) 234 if( s->val.isSet() )
235 { 235 {
236 if( s->sValue.getString() == NULL ) 236 if( s->sValue.getStr() == NULL )
237 { 237 {
238 s->val = argv[arg]+s->sWord.getLength()+3; 238 s->val = argv[arg]+s->sWord.getSize()+3;
239 } 239 }
240 else 240 else
241 { 241 {
242 s->val = s->sValue.getString(); 242 s->val = s->sValue.getStr();
243 } 243 }
244 } 244 }
245 if( s->proc ) 245 if( s->proc )
246 { 246 {
247 char **tmp = new char*[argc-arg]; 247 char **tmp = new char*[argc-arg];
248 tmp[0] = argv[arg]+s->sWord.getLength()+3; 248 tmp[0] = argv[arg]+s->sWord.getSize()+3;
249 for( int k = 1; k < argc-arg; k++ ) 249 for( int k = 1; k < argc-arg; k++ )
250 tmp[k] = argv[arg+k]; 250 tmp[k] = argv[arg+k];
251 int ret = (this->*s->proc)( argc-arg, tmp ); 251 int ret = (this->*s->proc)( argc-arg, tmp );
@@ -261,7 +261,7 @@ void ParamProc::process( int argc, char *argv[] )
261 int add = 0; 261 int add = 0;
262 if( s->val.isSet() ) 262 if( s->val.isSet() )
263 { 263 {
264 if( s->sValue.getString() == NULL ) 264 if( s->sValue.getStr() == NULL )
265 { 265 {
266 if( arg+1 >= argc ) 266 if( arg+1 >= argc )
267 { 267 {
@@ -272,7 +272,7 @@ void ParamProc::process( int argc, char *argv[] )
272 } 272 }
273 else 273 else
274 { 274 {
275 s->val = s->sValue.getString(); 275 s->val = s->sValue.getStr();
276 } 276 }
277 } 277 }
278 if( s->proc ) 278 if( s->proc )
@@ -307,14 +307,14 @@ void ParamProc::process( int argc, char *argv[] )
307 bool bUsed = false; 307 bool bUsed = false;
308 if( s->val.isSet() ) 308 if( s->val.isSet() )
309 { 309 {
310 if( s->sValue.getString() == NULL ) 310 if( s->sValue.getStr() == NULL )
311 { 311 {
312 s->val = argv[arg]+chr+1; 312 s->val = argv[arg]+chr+1;
313 bUsed = true; 313 bUsed = true;
314 } 314 }
315 else 315 else
316 { 316 {
317 s->val = s->sValue.getString(); 317 s->val = s->sValue.getStr();
318 } 318 }
319 } 319 }
320 if( s->proc ) 320 if( s->proc )
@@ -342,14 +342,14 @@ void ParamProc::process( int argc, char *argv[] )
342 bool bUsed = false; 342 bool bUsed = false;
343 if( s->val.isSet() ) 343 if( s->val.isSet() )
344 { 344 {
345 if( s->sValue.getString() == NULL ) 345 if( s->sValue.getStr() == NULL )
346 { 346 {
347 s->val = argv[arg+1]; 347 s->val = argv[arg+1];
348 bUsed = true; 348 bUsed = true;
349 } 349 }
350 else 350 else
351 { 351 {
352 s->val = s->sValue.getString(); 352 s->val = s->sValue.getStr();
353 } 353 }
354 } 354 }
355 if( s->proc ) 355 if( s->proc )
@@ -384,22 +384,22 @@ void ParamProc::process( int argc, char *argv[] )
384 } 384 }
385} 385}
386 386
387ParamProc::ArgSpec *ParamProc::checkWord( const char *arg ) 387Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg )
388{ 388{
389 //printf("Checking \"%s\"...\n", arg ); 389 //printf("Checking \"%s\"...\n", arg );
390 std::list<ArgSpec *>::const_iterator i; 390 std::list<ArgSpec *>::const_iterator i;
391 for( i = lArg.begin(); i != lArg.end(); i++ ) 391 for( i = lArg.begin(); i != lArg.end(); i++ )
392 { 392 {
393 if( (*i)->sWord.getString() == NULL ) 393 if( (*i)->sWord.getStr() == NULL )
394 continue; 394 continue;
395 395
396 if( !strcmp( (*i)->sWord, arg ) ) 396 if( !strcmp( (*i)->sWord.getStr(), arg ) )
397 return *i; 397 return *i;
398 398
399 if( (*i)->val.isSet() ) 399 if( (*i)->val.isSet() )
400 { 400 {
401 if( !strncmp( (*i)->sWord, arg, (*i)->sWord.getLength() ) && 401 if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) &&
402 arg[(*i)->sWord.getLength()] == '=' ) 402 arg[(*i)->sWord.getSize()] == '=' )
403 { 403 {
404 return *i; 404 return *i;
405 } 405 }
@@ -409,7 +409,7 @@ ParamProc::ArgSpec *ParamProc::checkWord( const char *arg )
409 return NULL; 409 return NULL;
410} 410}
411 411
412ParamProc::ArgSpec *ParamProc::checkLetr( const char arg ) 412Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg )
413{ 413{
414 //printf("Checking \'%c\'...\n", arg ); 414 //printf("Checking \'%c\'...\n", arg );
415 std::list<ArgSpec *>::const_iterator i; 415 std::list<ArgSpec *>::const_iterator i;
@@ -427,27 +427,27 @@ ParamProc::ArgSpec *ParamProc::checkLetr( const char arg )
427 return NULL; 427 return NULL;
428} 428}
429 429
430int ParamProc::cmdParam( int argc, char *argv[] ) 430int Bu::ParamProc::cmdParam( int argc, char *argv[] )
431{ 431{
432 printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); 432 printf("Unhandled command parameter \"%s\" found!\n", argv[0] );
433 return 0; 433 return 0;
434} 434}
435 435
436int ParamProc::unknownParam( int argc, char *argv[] ) 436int Bu::ParamProc::unknownParam( int argc, char *argv[] )
437{ 437{
438 printf("Unknown parameter \"%s\" found!\n", argv[0] ); 438 printf("Unknown parameter \"%s\" found!\n", argv[0] );
439 return 0; 439 return 0;
440} 440}
441 441
442int ParamProc::help( int argc, char *argv[] ) 442int Bu::ParamProc::help( int argc, char *argv[] )
443{ 443{
444 std::list<Banner *>::const_iterator b = lBan.begin(); 444 std::list<Banner *>::const_iterator b = lBan.begin();
445 std::list<ArgSpec *>::const_iterator i; 445 std::list<ArgSpec *>::const_iterator i;
446 int len=0; 446 int len=0;
447 for( i = lArg.begin(); i != lArg.end(); i++ ) 447 for( i = lArg.begin(); i != lArg.end(); i++ )
448 { 448 {
449 if( len < (*i)->sWord.getLength() + (*i)->sExtra.getLength() ) 449 if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() )
450 len = (*i)->sWord.getLength() + (*i)->sExtra.getLength(); 450 len = (*i)->sWord.getSize() + (*i)->sExtra.getSize();
451 } 451 }
452 char fmt[10]; 452 char fmt[10];
453 sprintf( fmt, "%%-%ds ", len ); 453 sprintf( fmt, "%%-%ds ", len );
@@ -458,14 +458,14 @@ int ParamProc::help( int argc, char *argv[] )
458 { 458 {
459 if( (*b)->pBefore == (*i) ) 459 if( (*b)->pBefore == (*i) )
460 { 460 {
461 printf( (*b)->sBanner.getString() ); 461 printf( (*b)->sBanner.getStr() );
462 b++; 462 b++;
463 } 463 }
464 } 464 }
465 printf(" "); 465 printf(" ");
466 if( (*i)->cChar ) 466 if( (*i)->cChar )
467 { 467 {
468 if( (*i)->sWord.getString() ) 468 if( (*i)->sWord.getStr() )
469 { 469 {
470 printf("-%c, ", (*i)->cChar ); 470 printf("-%c, ", (*i)->cChar );
471 } 471 }
@@ -478,12 +478,12 @@ int ParamProc::help( int argc, char *argv[] )
478 { 478 {
479 printf(" "); 479 printf(" ");
480 } 480 }
481 if( (*i)->sWord.getString() ) 481 if( (*i)->sWord.getStr() )
482 { 482 {
483 printf("--"); 483 printf("--");
484 std::string sTmp = (*i)->sWord.getString(); 484 std::string sTmp = (*i)->sWord.getStr();
485 if( (*i)->sExtra.getString() ) 485 if( (*i)->sExtra.getStr() )
486 sTmp += (*i)->sExtra.getString(); 486 sTmp += (*i)->sExtra.getStr();
487 printf( fmt, sTmp.c_str() ); 487 printf( fmt, sTmp.c_str() );
488 } 488 }
489 else 489 else
@@ -491,20 +491,20 @@ int ParamProc::help( int argc, char *argv[] )
491 printf(" "); 491 printf(" ");
492 printf(fmt, "" ); 492 printf(fmt, "" );
493 } 493 }
494 printf("%s\n", (*i)->sDesc.getString() ); 494 printf("%s\n", (*i)->sDesc.getStr() );
495 } 495 }
496 if( b != lBan.end() ) 496 if( b != lBan.end() )
497 { 497 {
498 if( (*b)->pBefore == NULL ) 498 if( (*b)->pBefore == NULL )
499 { 499 {
500 printf( (*b)->sBanner.getString() ); 500 printf( (*b)->sBanner.getStr() );
501 } 501 }
502 } 502 }
503 503
504 exit( 0 ); 504 exit( 0 );
505} 505}
506 506
507void ParamProc::addHelpBanner( const char *sHelpBanner ) 507void Bu::ParamProc::addHelpBanner( const char *sHelpBanner )
508{ 508{
509 Banner *pBan = new Banner; 509 Banner *pBan = new Banner;
510 pBan->sBanner = sHelpBanner; 510 pBan->sBanner = sHelpBanner;
diff --git a/src/paramproc.h b/src/paramproc.h
index d857193..2bca588 100644
--- a/src/paramproc.h
+++ b/src/paramproc.h
@@ -1,153 +1,156 @@
1#ifndef PARAM_PROC_H 1#ifndef BU_PARAM_PROC_H
2#define PARAM_PROC_H 2#define BU_PARAM_PROC_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <string> 5#include <string>
6#include <list> 6#include <list>
7#include "staticstring.h" 7#include "bu/fstring.h"
8 8
9class ParamProc 9namespace Bu
10{ 10{
11public: 11 class ParamProc
12 class ParamPtr
13 { 12 {
14 public: 13 public:
15 ParamPtr(); 14 class ParamPtr
16 ParamPtr( std::string *str );
17 ParamPtr( uint64_t *uint64 );
18 ParamPtr( uint32_t *uint32 );
19 ParamPtr( uint16_t *uint16 );
20 ParamPtr( uint8_t *uint8 );
21 ParamPtr( int64_t *int64 );
22 ParamPtr( int32_t *int32 );
23 ParamPtr( int16_t *int16 );
24 ParamPtr( int8_t *int8 );
25 ParamPtr( float *float32 );
26 ParamPtr( double *float64 );
27 ParamPtr( long double *float96 );
28 ParamPtr( bool *bln );
29
30 enum
31 { 15 {
32 vtunset, 16 public:
33 vtstr, 17 ParamPtr();
34 vtuint64, 18 ParamPtr( std::string *str );
35 vtuint32, 19 ParamPtr( uint64_t *uint64 );
36 vtuint16, 20 ParamPtr( uint32_t *uint32 );
37 vtuint8, 21 ParamPtr( uint16_t *uint16 );
38 vtint64, 22 ParamPtr( uint8_t *uint8 );
39 vtint32, 23 ParamPtr( int64_t *int64 );
40 vtint16, 24 ParamPtr( int32_t *int32 );
41 vtint8, 25 ParamPtr( int16_t *int16 );
42 vtfloat32, 26 ParamPtr( int8_t *int8 );
43 vtfloat64, 27 ParamPtr( float *float32 );
44 vtfloat96, 28 ParamPtr( double *float64 );
45 vtbln, 29 ParamPtr( long double *float96 );
46 }; 30 ParamPtr( bool *bln );
47 ParamPtr &operator=( ParamPtr &ptr );
48 ParamPtr &operator=( const char *str );
49 31
50 bool isSet(); 32 enum
33 {
34 vtunset,
35 vtstr,
36 vtuint64,
37 vtuint32,
38 vtuint16,
39 vtuint8,
40 vtint64,
41 vtint32,
42 vtint16,
43 vtint8,
44 vtfloat32,
45 vtfloat64,
46 vtfloat96,
47 vtbln,
48 };
49 ParamPtr &operator=( ParamPtr &ptr );
50 ParamPtr &operator=( const char *str );
51 51
52 private: 52 bool isSet();
53 int type; 53
54 union 54 private:
55 { 55 int type;
56 std::string *str; 56 union
57 uint64_t *uint64; 57 {
58 uint32_t *uint32; 58 std::string *str;
59 uint16_t *uint16; 59 uint64_t *uint64;
60 uint8_t *uint8; 60 uint32_t *uint32;
61 int64_t *int64; 61 uint16_t *uint16;
62 int32_t *int32; 62 uint8_t *uint8;
63 int16_t *int16; 63 int64_t *int64;
64 int8_t *int8; 64 int32_t *int32;
65 float *float32; 65 int16_t *int16;
66 double *float64; 66 int8_t *int8;
67 long double *float96; 67 float *float32;
68 bool *bln; 68 double *float64;
69 } val; 69 long double *float96;
70 }; 70 bool *bln;
71 } val;
72 };
71 73
72 typedef int (ParamProc::*Proc)( int, char *[] ); 74 typedef int (ParamProc::*Proc)( int, char *[] );
73 75
74 typedef struct ArgSpec 76 typedef struct ArgSpec
75 { 77 {
76 uint8_t nFlags; 78 uint8_t nFlags;
77 StaticString sWord; 79 Bu::FString sWord;
78 char cChar; 80 char cChar;
79 Proc proc; 81 Proc proc;
80 ParamProc::ParamPtr val; 82 ParamProc::ParamPtr val;
81 StaticString sExtra; 83 Bu::FString sExtra;
82 StaticString sDesc; 84 Bu::FString sDesc;
83 StaticString sValue; 85 Bu::FString sValue;
84 } ArgSpec; 86 } ArgSpec;
85 87
86public: 88 public:
87 ParamProc(); 89 ParamProc();
88 virtual ~ParamProc(); 90 virtual ~ParamProc();
89 91
90 void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, 92 void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val,
91 const char *lpDesc=NULL, const char *lpExtra=NULL, 93 const char *lpDesc=NULL, const char *lpExtra=NULL,
92 const char *lpValue=NULL 94 const char *lpValue=NULL
93 ); 95 );
94 void addParam( const char *lpWord, char cChar, Proc proc, 96 void addParam( const char *lpWord, char cChar, Proc proc,
95 const char *lpDesc=NULL, const char *lpExtra=NULL, 97 const char *lpDesc=NULL, const char *lpExtra=NULL,
96 const char *lpValue=NULL 98 const char *lpValue=NULL
97 ); 99 );
98 void addParam( const char *lpWord, char cChar, ParamPtr val, 100 void addParam( const char *lpWord, char cChar, ParamPtr val,
99 const char *lpDesc=NULL, const char *lpExtra=NULL, 101 const char *lpDesc=NULL, const char *lpExtra=NULL,
100 const char *lpValue=NULL 102 const char *lpValue=NULL
101 ); 103 );
102 104
103 void addParam( const char *lpWord, Proc proc, ParamPtr val, 105 void addParam( const char *lpWord, Proc proc, ParamPtr val,
104 const char *lpDesc=NULL, const char *lpExtra=NULL, 106 const char *lpDesc=NULL, const char *lpExtra=NULL,
105 const char *lpValue=NULL 107 const char *lpValue=NULL
106 ); 108 );
107 void addParam( const char *lpWord, Proc proc, 109 void addParam( const char *lpWord, Proc proc,
108 const char *lpDesc=NULL, const char *lpExtra=NULL, 110 const char *lpDesc=NULL, const char *lpExtra=NULL,
109 const char *lpValue=NULL 111 const char *lpValue=NULL
110 ); 112 );
111 void addParam( const char *lpWord, ParamPtr val, 113 void addParam( const char *lpWord, ParamPtr val,
112 const char *lpDesc=NULL, const char *lpExtra=NULL, 114 const char *lpDesc=NULL, const char *lpExtra=NULL,
113 const char *lpValue=NULL 115 const char *lpValue=NULL
114 ); 116 );
115 117
116 void addParam( char cChar, Proc proc, ParamPtr val, 118 void addParam( char cChar, Proc proc, ParamPtr val,
117 const char *lpDesc=NULL, const char *lpExtra=NULL, 119 const char *lpDesc=NULL, const char *lpExtra=NULL,
118 const char *lpValue=NULL 120 const char *lpValue=NULL
119 ); 121 );
120 void addParam( char cChar, Proc proc, 122 void addParam( char cChar, Proc proc,
121 const char *lpDesc=NULL, const char *lpExtra=NULL, 123 const char *lpDesc=NULL, const char *lpExtra=NULL,
122 const char *lpValue=NULL 124 const char *lpValue=NULL
123 ); 125 );
124 void addParam( char cChar, ParamPtr val, 126 void addParam( char cChar, ParamPtr val,
125 const char *lpDesc=NULL, const char *lpExtra=NULL, 127 const char *lpDesc=NULL, const char *lpExtra=NULL,
126 const char *lpValue=NULL 128 const char *lpValue=NULL
127 ); 129 );
128 130
129 void process( int argc, char *argv[] ); 131 void process( int argc, char *argv[] );
130 void addHelpBanner( const char *sHelpBanner ); 132 void addHelpBanner( const char *sHelpBanner );
131 133
132private: 134 private:
133 ArgSpec *checkWord( const char *arg ); 135 ArgSpec *checkWord( const char *arg );
134 ArgSpec *checkLetr( const char arg ); 136 ArgSpec *checkLetr( const char arg );
135 137
136public: 138 public:
137 virtual int cmdParam( int argc, char *argv[] ); 139 virtual int cmdParam( int argc, char *argv[] );
138 virtual int unknownParam( int argc, char *argv[] ); 140 virtual int unknownParam( int argc, char *argv[] );
139 virtual int help( int argc, char *argv[] ); 141 virtual int help( int argc, char *argv[] );
140 142
141private: 143 private:
142 typedef struct Banner 144 typedef struct Banner
143 { 145 {
144 StaticString sBanner; 146 Bu::FString sBanner;
145 ArgSpec *pBefore; 147 ArgSpec *pBefore;
146 } Banner; 148 } Banner;
147 std::list<Banner *> lBan; 149 std::list<Banner *> lBan;
148 std::list<ArgSpec *> lArg; 150 std::list<ArgSpec *> lArg;
149}; 151 };
152}
150 153
151#define mkproc( cls ) static_cast<int (ParamProc::*)( int, char *[])>(&cls) 154#define mkproc( cls ) static_cast<int (Bu::ParamProc::*)( int, char *[])>(&cls)
152 155
153#endif 156#endif
diff --git a/src/plugger.h b/src/plugger.h
index d92f194..2124b7a 100644
--- a/src/plugger.h
+++ b/src/plugger.h
@@ -1,198 +1,198 @@
1#ifndef PLUGGER_H 1#ifndef BU_PLUGGER_H
2#define PLUGGER_H 2#define BU_PLUGGER_H
3 3
4 4
5#include "hashtable.h" 5#include "bu/hash.h"
6#include "list" 6#include "bu/list.h"
7#include "hashfunctionstring.h" 7#include <dlfcn.h>
8#include "hashfunctionint.h" 8#include "bu/exceptions.h"
9#include "dlfcn.h" 9#include "bu/fstring.h"
10#include "exceptions.h"
11 10
12typedef struct PluginInfo 11namespace Bu
13{ 12{
14 const char *sID; 13 typedef struct PluginInfo
15 const char *sAuthor; 14 {
16 unsigned short nVersion; 15 const char *sID;
17 unsigned short nRevision; 16 const char *sAuthor;
18 void *(*createPlugin)(); 17 unsigned short nVersion;
19 void (*destroyPlugin)( void * ); 18 unsigned short nRevision;
20} PluginInfo; 19 void *(*createPlugin)();
21 20 void (*destroyPlugin)( void * );
22typedef struct PluginReg 21 } PluginInfo;
23{ 22
24 bool bBuiltin; 23 typedef struct PluginReg
25 void *dlHandle; 24 {
26 PluginInfo *pInfo; 25 bool bBuiltin;
27} PluginReg; 26 void *dlHandle;
27 PluginInfo *pInfo;
28 } PluginReg;
28 29
29#define PluginInterface( classname, baseclass, name, ver, rev ) \ 30#define PluginInterface( classname, baseclass, name, ver, rev ) \
30extern "C" { \ 31 extern "C" { \
31 baseclass *create ##classname() \ 32 baseclass *create ##classname() \
32 { \ 33 { \
33 return new classname(); \ 34 return new classname(); \
34 } \ 35 } \
35 void destroy ##classname( baseclass *pCls ) \ 36 void destroy ##classname( baseclass *pCls ) \
36 { \ 37 { \
37 delete pCls; \ 38 delete pCls; \
38 } \ 39 } \
39 PluginInfo classname = { \ 40 Bu::PluginInfo classname = { \
40 #classname, name, ver, rev, \ 41 #classname, name, ver, rev, \
41 create ##classname, destroy ##classname }; \ 42 create ##classname, destroy ##classname }; \
42} 43 }
43 44
44#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ 45#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \
45extern "C" { \ 46 extern "C" { \
46 baseclass *create ##classname() \ 47 baseclass *create ##classname() \
47 { \ 48 { \
48 return new classname(); \ 49 return new classname(); \
49 } \ 50 } \
50 void destroy ##classname( baseclass *pCls ) \ 51 void destroy ##classname( baseclass *pCls ) \
51 { \ 52 { \
52 delete pCls; \ 53 delete pCls; \
53 } \ 54 } \
54 PluginInfo pluginname = { \ 55 Bu::PluginInfo pluginname = { \
55 #pluginname, name, ver, rev, \ 56 #pluginname, name, ver, rev, \
56 (void *(*)())(create ##classname), \ 57 (void *(*)())(create ##classname), \
57 (void (*)( void * ))(destroy ##classname) }; \ 58 (void (*)( void * ))(destroy ##classname) }; \
58} 59 }
59 60
60#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ 61#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
61extern "C" { \ 62 extern "C" { \
62 baseclass *create ##classname() \ 63 baseclass *create ##classname() \
63 { \ 64 { \
64 return new classname(); \ 65 return new classname(); \
65 } \ 66 } \
66 void destroy ##classname( baseclass *pCls ) \ 67 void destroy ##classname( baseclass *pCls ) \
67 { \ 68 { \
68 delete pCls; \ 69 delete pCls; \
69 } \ 70 } \
70 PluginInfo structname = { \ 71 Bu::PluginInfo structname = { \
71 #pluginname, name, ver, rev, \ 72 #pluginname, name, ver, rev, \
72 (void *(*)())(create ##classname), \ 73 (void *(*)())(create ##classname), \
73 (void (*)( void * ))(destroy ##classname) }; \ 74 (void (*)( void * ))(destroy ##classname) }; \
74}
75
76template<class T>
77class Plugger
78{
79public:
80
81public:
82 Plugger() :
83 hPlugin( new HashFunctionString(), 11 ),
84 hObj( new HashFunctionInt(), 11 )
85 {
86 } 75 }
87 76
88 virtual ~Plugger() 77 template<class T>
78 class Plugger
89 { 79 {
90 void *pos = hObj.getFirstItemPos(); 80 public:
91 while( (pos = hObj.getNextItemPos( pos )) ) 81 typedef Bu::Hash<Bu::FString, PluginReg *> PluginHash;
82 typedef Bu::Hash<int, void *> InstHash;
83
84 public:
85 Plugger()
92 { 86 {
93 T *pPlug = (T *)hObj.getItemID( pos );
94 PluginReg *pReg = (PluginReg *)hObj.getItemData( pos );
95 pReg->pInfo->destroyPlugin( pPlug );
96 } 87 }
97 88
98 std::list<PluginReg *>::iterator i; 89 virtual ~Plugger()
99 for( i = lPlugin.begin(); i != lPlugin.end(); i++ )
100 { 90 {
101 if( (*i)->bBuiltin == false ) 91 for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ )
102 { 92 {
103 dlclose( (*i)->dlHandle ); 93 T *pPlug = (T *)i.getKey();
94 PluginReg *pReg = (PluginReg *)*i;
95 pReg->pInfo->destroyPlugin( pPlug );
104 } 96 }
105 delete (*i);
106 }
107 }
108 97
109 void registerBuiltinPlugin( PluginInfo *pInfo ) 98 for( PluginHash::iterator i = hPlugin.begin();
110 { 99 i != hPlugin.end(); i++ )
111 PluginReg *pReg = new PluginReg; 100 {
112 pReg->bBuiltin = true; 101 if( (*i)->bBuiltin == false )
113 pReg->pInfo = pInfo; 102 {
114 lPlugin.insert( lPlugin.end(), pReg ); 103 dlclose( (*i)->dlHandle );
115 hPlugin.insert( pInfo->sID, pReg ); 104 }
116 } 105 delete (*i);
106 }
107 }
117 108
118 void registerExternalPlugin( const char *sFName, const char *sPluginName ) 109 void registerBuiltinPlugin( PluginInfo *pInfo )
119 {
120 PluginReg *pReg = (PluginReg *)hPlugin[sPluginName];
121 if( pReg != NULL )
122 { 110 {
123 hPlugin.del( sPluginName ); 111 PluginReg *pReg = new PluginReg;
124 dlclose( pReg->dlHandle ); 112 pReg->bBuiltin = true;
125 delete pReg; 113 pReg->pInfo = pInfo;
126 pReg = NULL; 114 hPlugin.insert( pInfo->sID, pReg );
127 } 115 }
128 116
129 pReg = new PluginReg; 117 void registerExternalPlugin( const char *sFName, const char *sPluginName )
130
131 pReg->bBuiltin = false;
132 pReg->dlHandle = dlopen( sFName, RTLD_NOW );
133 if( pReg->dlHandle == NULL )
134 { 118 {
135 throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); 119 PluginReg *pReg;
120 try {
121 pReg = (PluginReg *)hPlugin[sPluginName];
122 hPlugin.erase( sPluginName );
123 dlclose( pReg->dlHandle );
124 delete pReg;
125 pReg = NULL;
126 } catch( Bu::HashException &e )
127 {
128 }
129
130 pReg = new PluginReg;
131
132 pReg->bBuiltin = false;
133 pReg->dlHandle = dlopen( sFName, RTLD_NOW );
134 if( pReg->dlHandle == NULL )
135 {
136 throw PluginException( 1, "Error on %s: %s", sFName, dlerror() );
137 }
138 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName );
139 if( pReg->pInfo == NULL )
140 {
141 throw PluginException( 2, "Error on %s: %s", sFName, dlerror() );
142 }
143 hPlugin.insert( pReg->pInfo->sID, pReg );
136 } 144 }
137 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); 145
138 if( pReg->pInfo == NULL ) 146 T *instantiate( const char *lpName )
139 { 147 {
140 throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); 148 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
149 if( pReg == NULL )
150 return NULL;
151
152 T *p = (T *)pReg->pInfo->createPlugin();
153 hObj.insert( (int )p, pReg );
154 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
155
156 return p;
141 } 157 }
142 hPlugin.insert( pReg->pInfo->sID, pReg );
143 lPlugin.insert( lPlugin.end(), pReg );
144 }
145
146 T *instantiate( const char *lpName )
147 {
148 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
149 if( pReg == NULL )
150 return NULL;
151
152 T *p = (T *)pReg->pInfo->createPlugin();
153 hObj.insert( p, pReg );
154 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
155
156 return p;
157 }
158 158
159 bool hasPlugin( const char *lpName ) 159 bool hasPlugin( const char *lpName )
160 { 160 {
161 if( hPlugin[lpName] == NULL ) 161 if( hPlugin[lpName] == NULL )
162 return false; 162 return false;
163 return true; 163 return true;
164 } 164 }
165 165
166 void destroy( T *pPlug ) 166 void destroy( T *pPlug )
167 { 167 {
168 PluginReg *pReg = (PluginReg *)hObj[pPlug]; 168 PluginReg *pReg = (PluginReg *)hObj.get((int)pPlug);
169 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); 169 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug );
170 if( pReg == NULL ) 170 if( pReg == NULL )
171 return; 171 return;
172 172
173 pReg->pInfo->destroyPlugin( pPlug ); 173 pReg->pInfo->destroyPlugin( pPlug );
174 174
175 hObj.del( pPlug ); 175 hObj.erase( (int)pPlug );
176 } 176 }
177 177
178 void unloadAll() 178 void unloadAll()
179 {
180 std::list<PluginReg *>::iterator i;
181 for( i = lPlugin.begin(); i != lPlugin.end(); i++ )
182 { 179 {
183 if( (*i)->bBuiltin == false ) 180 for( PluginHash::iterator i = hPlugin.begin();
181 i != hPlugin.end(); i++ )
184 { 182 {
185 dlclose( (*i)->dlHandle ); 183 if( (*i)->bBuiltin == false )
184 {
185 dlclose( (*i)->dlHandle );
186 }
187 delete (*i);
186 } 188 }
187 delete (*i); 189 hPlugin.clear();
188 } 190 }
189 hPlugin.clear();
190 }
191 191
192private: 192 private:
193 std::list<PluginReg *> lPlugin; 193 PluginHash hPlugin;
194 HashTable hPlugin; 194 InstHash hObj;
195 HashTable hObj; 195 };
196}; 196}
197 197
198#endif 198#endif
diff --git a/src/programchain.cpp b/src/programchain.cpp
index 6120d58..0bb7a77 100644
--- a/src/programchain.cpp
+++ b/src/programchain.cpp
@@ -1,17 +1,18 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include "programchain.h" 2#include "bu/programchain.h"
3#include "bu/programlink.h"
3 4
4ProgramChain::ProgramChain() : 5using namespace Bu;
5 xLog( MultiLog::getInstance() ) 6
7Bu::ProgramChain::ProgramChain()
6{ 8{
7 xLog.LineLog( MultiLog::LStatus, "Program Chain Initialized." );
8} 9}
9 10
10ProgramChain::~ProgramChain() 11Bu::ProgramChain::~ProgramChain()
11{ 12{
12} 13}
13 14
14bool ProgramChain::addLink( ProgramLink *pLink ) 15bool Bu::ProgramChain::addLink( ProgramLink *pLink )
15{ 16{
16 if( pLink->init() == false ) 17 if( pLink->init() == false )
17 { 18 {
@@ -26,26 +27,25 @@ bool ProgramChain::addLink( ProgramLink *pLink )
26 return true; 27 return true;
27} 28}
28 29
29ProgramLink *ProgramChain::getLink( const char *lpName ) 30ProgramLink *Bu::ProgramChain::getLink( const char *lpName )
30{ 31{
31 char a; 32 char a;
32 a = lpName[0]; 33 a = lpName[0];
33 return NULL; 34 return NULL;
34} 35}
35 36
36ProgramLink *ProgramChain::getBaseLink() 37ProgramLink *Bu::ProgramChain::getBaseLink()
37{ 38{
38 return NULL; 39 return NULL;
39} 40}
40 41
41bool ProgramChain::execChainOnce() 42bool Bu::ProgramChain::execChainOnce()
42{ 43{
43 int nLen = lLink.getSize(); 44 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
44 for( int j = 0; j < nLen; j++ ) 45 i != lLink.end(); i++ )
45 { 46 {
46 if( ((ProgramLink *)lLink[j])->timeSlice() == false ) 47 if( (*i)->timeSlice() == false )
47 { 48 {
48 xLog.LineLog( MultiLog::LInfo, "Shutting down due to signal from link #%d", j );
49 emergencyShutdown(); 49 emergencyShutdown();
50 return false; 50 return false;
51 } 51 }
@@ -54,7 +54,7 @@ bool ProgramChain::execChainOnce()
54 return true; 54 return true;
55} 55}
56 56
57bool ProgramChain::enterChainLoop() 57bool Bu::ProgramChain::enterChainLoop()
58{ 58{
59 for(;;) 59 for(;;)
60 { 60 {
@@ -67,23 +67,23 @@ bool ProgramChain::enterChainLoop()
67 return true; 67 return true;
68} 68}
69 69
70void ProgramChain::emergencyShutdown() 70void Bu::ProgramChain::emergencyShutdown()
71{ 71{
72 int nLen = lLink.getSize(); 72 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
73 for( int j = 0; j < nLen; j++ ) 73 i != lLink.end(); i++ )
74 { 74 {
75 ((ProgramLink *)lLink[j])->deInit(); 75 (*i)->deInit();
76 delete (ProgramLink *)lLink[j]; 76 delete *i;
77 } 77 }
78 lLink.empty(); 78 lLink.clear();
79} 79}
80 80
81LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ) 81LinkMessage *Bu::ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender )
82{ 82{
83 int nLen = lLink.getSize(); 83 for( Bu::List<Bu::ProgramLink *>::iterator i = lLink.begin();
84 for( int j = 0; j < nLen; j++ ) 84 i != lLink.end(); i++ )
85 { 85 {
86 LinkMessage *pMsg = ((ProgramLink *)lLink[j])->processIRM( pMsgOut ); 86 LinkMessage *pMsg = (*i)->processIRM( pMsgOut );
87 if( pMsg != NULL ) 87 if( pMsg != NULL )
88 { 88 {
89 delete pMsgOut; 89 delete pMsgOut;
@@ -94,3 +94,4 @@ LinkMessage *ProgramChain::broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSen
94 delete pMsgOut; 94 delete pMsgOut;
95 return NULL; 95 return NULL;
96} 96}
97
diff --git a/src/programchain.h b/src/programchain.h
index 2bdfeee..336a9f1 100644
--- a/src/programchain.h
+++ b/src/programchain.h
@@ -1,95 +1,98 @@
1#ifndef PROGRAMCHAIN_H 1#ifndef BU_PROGRAMCHAIN_H
2#define PROGRAMCHAIN_H 2#define BU_PROGRAMCHAIN_H
3 3
4#include "linkedlist.h" 4#include "bu/list.h"
5#include "multilog.h" 5#include "bu/linkmessage.h"
6#include "programlink.h"
7 6
8/** 7namespace Bu
9 * The Program Chain links together program "chunks" to more easily facilitate
10 * a generalized program loop with modular extensions.
11 *@author Mike Buland
12 */
13class ProgramChain
14{ 8{
15public: 9 class ProgramLink;
16 /** 10 /**
17 * Construct an empty chain. 11 * The Program Chain links together program "chunks" to more easily facilitate
12 * a generalized program loop with modular extensions.
13 *@author Mike Buland
18 */ 14 */
19 ProgramChain(); 15 class ProgramChain
16 {
17 public:
18 /**
19 * Construct an empty chain.
20 */
21 ProgramChain();
20 22
21 /** 23 /**
22 * Destroy your chain. 24 * Destroy your chain.
23 */ 25 */
24 virtual ~ProgramChain(); 26 virtual ~ProgramChain();
25 27
26 /** 28 /**
27 * Adds a link to the end of the chain. 29 * Adds a link to the end of the chain.
28 *@param pLink A pointer to the link to add to the chain. 30 *@param pLink A pointer to the link to add to the chain.
29 *@returns True if adding the link was successful, otherwise false 31 *@returns True if adding the link was successful, otherwise false
30 *@author Mike Buland 32 *@author Mike Buland
31 */ 33 */
32 bool addLink( ProgramLink *pLink ); 34 bool addLink( Bu::ProgramLink *pLink );
33 35
34 /** 36 /**
35 * Gets a link by name. 37 * Gets a link by name.
36 *@param lpName The name of the link you're looking for. Every link has a 38 *@param lpName The name of the link you're looking for. Every link has a
37 * name, apparently. 39 * name, apparently.
38 *@returns A pointer to the specified ProgramLink, or NULL if none were 40 *@returns A pointer to the specified ProgramLink, or NULL if none were
39 * found matching your criteria. 41 * found matching your criteria.
40 *@author Mike Buland 42 *@author Mike Buland
41 */ 43 */
42 class ProgramLink *getLink( const char *lpName ); 44 class ProgramLink *getLink( const char *lpName );
43 45
44 /** 46 /**
45 * Gets the very first link in the chain. 47 * Gets the very first link in the chain.
46 *@returns A pointer to the first link in the chain. 48 *@returns A pointer to the first link in the chain.
47 *@author Mike Buland 49 *@author Mike Buland
48 */ 50 */
49 class ProgramLink *getBaseLink(); 51 class ProgramLink *getBaseLink();
50 52
51 /** 53 /**
52 * Runs through the chain once. Useful if you want to have more control 54 * Runs through the chain once. Useful if you want to have more control
53 * over the operation of the chain. 55 * over the operation of the chain.
54 *@returns true if every link returned true. If at least one link returns 56 *@returns true if every link returned true. If at least one link returns
55 * false, then returns false. 57 * false, then returns false.
56 *@author Mike Buland 58 *@author Mike Buland
57 */ 59 */
58 bool execChainOnce(); 60 bool execChainOnce();
59 61
60 /** 62 /**
61 * Enters the master chain loop, looping over the entire chain and 63 * Enters the master chain loop, looping over the entire chain and
62 * executing every link's TimeSlice routine in order, over and over, until 64 * executing every link's TimeSlice routine in order, over and over, until
63 * a link returns a false value. 65 * a link returns a false value.
64 *@returns False, always. It returns true unless a link returned false, 66 *@returns False, always. It returns true unless a link returned false,
65 * but loops until a link does return false. 67 * but loops until a link does return false.
66 *@author Mike Buland 68 *@author Mike Buland
67 **/ 69 **/
68 bool enterChainLoop(); 70 bool enterChainLoop();
69 71
70 /** 72 /**
71 * Broadcasts an Immediate Response Message to all active links, save the 73 * Broadcasts an Immediate Response Message to all active links, save the
72 * sender. Whatever link first responds with a non-null response message 74 * sender. Whatever link first responds with a non-null response message
73 * will have it's messages sent back to the broadcasting link as the returns 75 * will have it's messages sent back to the broadcasting link as the returns
74 * of this function call. Therefore it is very important that all message 76 * of this function call. Therefore it is very important that all message
75 * processing code is handled in a fairly timely fasion. 77 * processing code is handled in a fairly timely fasion.
76 *@param pMsgOut The message to broadcast in hopes of a response. 78 *@param pMsgOut The message to broadcast in hopes of a response.
77 *@param pSender The message that sent out the message and doesn't want to 79 *@param pSender The message that sent out the message and doesn't want to
78 * receive it's own message. This should always just be "this". 80 * receive it's own message. This should always just be "this".
79 *@returns The message that was returned by the first link to return a 81 *@returns The message that was returned by the first link to return a
80 * non-null response. If all messages return null responses then this also 82 * non-null response. If all messages return null responses then this also
81 * returns null. Please note that whoever calls this will be responsible 83 * returns null. Please note that whoever calls this will be responsible
82 * for deleting the message returned by it, if non-null. 84 * for deleting the message returned by it, if non-null.
83 */ 85 */
84 class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender ); 86 class LinkMessage *broadcastIRM( LinkMessage *pMsgOut, ProgramLink *pSender );
87
88 private:
89 /**
90 * Shuts down all operation no matter what point in the operation we were.
91 */
92 void emergencyShutdown();
93 Bu::List<Bu::ProgramLink *> lLink; /**< The linked list that contains all of the links. */
94 };
95}
85 96
86private:
87 /**
88 * Shuts down all operation no matter what point in the operation we were.
89 */
90 void emergencyShutdown();
91 MultiLog &xLog; /**< A reference to the log. */
92 LinkedList lLink; /**< The linked list that contains all of the links. */
93};
94 97
95#endif 98#endif
diff --git a/src/programlink.cpp b/src/programlink.cpp
index 21c6fe4..e5c624c 100644
--- a/src/programlink.cpp
+++ b/src/programlink.cpp
@@ -1,20 +1,22 @@
1#include "programlink.h" 1#include "bu/programlink.h"
2#include "programchain.h" 2#include "bu/programchain.h"
3 3
4ProgramLink::ProgramLink() 4using namespace Bu;
5
6Bu::ProgramLink::ProgramLink()
5{ 7{
6} 8}
7 9
8ProgramLink::~ProgramLink() 10Bu::ProgramLink::~ProgramLink()
9{ 11{
10} 12}
11 13
12LinkMessage *ProgramLink::sendIRM( LinkMessage *pMsgOut ) 14LinkMessage *Bu::ProgramLink::sendIRM( LinkMessage *pMsgOut )
13{ 15{
14 return pChain->broadcastIRM( pMsgOut, this ); 16 return pChain->broadcastIRM( pMsgOut, this );
15} 17}
16 18
17void ProgramLink::setChain( ProgramChain *pNewChain ) 19void Bu::ProgramLink::setChain( ProgramChain *pNewChain )
18{ 20{
19 pChain = pNewChain; 21 pChain = pNewChain;
20} 22}
diff --git a/src/programlink.h b/src/programlink.h
index f93edcc..07d7489 100644
--- a/src/programlink.h
+++ b/src/programlink.h
@@ -1,99 +1,100 @@
1#ifndef PROGRAMLINK_H 1#ifndef BU_PROGRAMLINK_H
2#define PROGRAMLINK_H 2#define BU_PROGRAMLINK_H
3 3
4class ProgramLink; 4#include "bu/linkmessage.h"
5#include "queue.h" 5#include "bu/programchain.h"
6#include "linkmessage.h"
7#include "programchain.h"
8 6
9/** 7namespace Bu
10 * Program Link is the base class for any object that will be a piece of the
11 * main program chain loop.
12 *@author Mike Buland
13 */
14class ProgramLink
15{ 8{
16friend class ProgramChain;
17public:
18 /** 9 /**
19 * Construct a program link. 10 * Program Link is the base class for any object that will be a piece of the
11 * main program chain loop.
12 *@author Mike Buland
20 */ 13 */
21 ProgramLink(); 14 class ProgramLink
15 {
16 friend class Bu::ProgramChain;
17 public:
18 /**
19 * Construct a program link.
20 */
21 ProgramLink();
22 22
23 /** 23 /**
24 * Deconstruct. 24 * Deconstruct.
25 */ 25 */
26 virtual ~ProgramLink(); 26 virtual ~ProgramLink();
27 27
28 /** 28 /**
29 * Initialization code required for a link that wasn't performed in the 29 * Initialization code required for a link that wasn't performed in the
30 * constructor. 30 * constructor.
31 *@returns true if initialization was successful. A false value will halt 31 *@returns true if initialization was successful. A false value will halt
32 * the chain. 32 * the chain.
33 */ 33 */
34 virtual bool init()=0; 34 virtual bool init()=0;
35 35
36 /** 36 /**
37 * DeInitialization code that should happen, but doesn't belong in the 37 * DeInitialization code that should happen, but doesn't belong in the
38 * destructor. 38 * destructor.
39 *@returns true means everything worked, false means failure, but is 39 *@returns true means everything worked, false means failure, but is
40 * meaningless. 40 * meaningless.
41 */ 41 */
42 virtual bool deInit()=0; 42 virtual bool deInit()=0;
43 43
44 /** 44 /**
45 * Executed once per link per chain pass. Contains the guts of the program. 45 * Executed once per link per chain pass. Contains the guts of the program.
46 *@returns true if everything went well. A false value will halt the chain. 46 *@returns true if everything went well. A false value will halt the chain.
47 */ 47 */
48 virtual bool timeSlice()=0; 48 virtual bool timeSlice()=0;
49 49
50 /** 50 /**
51 * This must be handled in order to process Instant Response Messages. 51 * This must be handled in order to process Instant Response Messages.
52 * This function should return null on all messages that it doesn't 52 * This function should return null on all messages that it doesn't
53 * understand how to handle, and construct new messages to return to sender 53 * understand how to handle, and construct new messages to return to sender
54 * in the cases where it does understand. 54 * in the cases where it does understand.
55 *@param pMsgIn The message that must be processed. 55 *@param pMsgIn The message that must be processed.
56 *@returns Either a new message in cases where a response is required, 56 *@returns Either a new message in cases where a response is required,
57 * or null if nothing needs to be done by this link. 57 * or null if nothing needs to be done by this link.
58 */ 58 */
59 virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0; 59 virtual LinkMessage *processIRM( LinkMessage *pMsgIn ) = 0;
60 60
61 /** 61 /**
62 * Broadcast a LinkMessage to all other links in the system. Each other 62 * Broadcast a LinkMessage to all other links in the system. Each other
63 * link will get a call of their processIRM function. If the message gets 63 * link will get a call of their processIRM function. If the message gets
64 * a response then you will regain control immediately, otherwise the system 64 * a response then you will regain control immediately, otherwise the system
65 * will give all other Links a chance to respond before returning NULL. 65 * will give all other Links a chance to respond before returning NULL.
66 *@param pMsgOut The message to broadcast. 66 *@param pMsgOut The message to broadcast.
67 *@returns The message response, or NULL if no Link understood your message. 67 *@returns The message response, or NULL if no Link understood your message.
68 */ 68 */
69 LinkMessage *sendIRM( LinkMessage *pMsgOut ); 69 LinkMessage *sendIRM( LinkMessage *pMsgOut );
70 70
71private: 71 private:
72 /** 72 /**
73 * Set which chain we're assosiated with. This is how IRM messages make 73 * Set which chain we're assosiated with. This is how IRM messages make
74 * it out to the rest of the world. 74 * it out to the rest of the world.
75 *@param pNewChain A pointer to the containing program chain. 75 *@param pNewChain A pointer to the containing program chain.
76 */ 76 */
77 void setChain( class ProgramChain *pNewChain ); 77 void setChain( class ProgramChain *pNewChain );
78 78
79 /** 79 /**
80 * The pointer to the containing chain. 80 * The pointer to the containing chain.
81 */ 81 */
82 class ProgramChain *pChain; 82 class ProgramChain *pChain;
83/* 83 /*
84 void postMessage( LinkMessage *pMsg, int nLvl ); 84 void postMessage( LinkMessage *pMsg, int nLvl );
85 LinkMessage *getMessage( int nLvl ); 85 LinkMessage *getMessage( int nLvl );
86 86
87 enum 87 enum
88 { 88 {
89 msgToChain, 89 msgToChain,
90 msgToLink 90 msgToLink
91 }; 91 };
92 92
93private: 93 private:
94 Queue qMsgToChain; 94 Queue qMsgToChain;
95 Queue qMsgToLink; 95 Queue qMsgToLink;
96*/ 96 */
97}; 97 };
98}
98 99
99#endif 100#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 78b3ee2..0976b3b 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,20 +1,12 @@
1#include "protocol.h" 1#include "bu/protocol.h"
2 2
3Protocol::Protocol() 3using namespace Bu;
4{
5 pConnection = NULL;
6}
7 4
8Protocol::~Protocol() 5Bu::Protocol::Protocol()
9{ 6{
10} 7}
11 8
12void Protocol::setConnection( Connection *pNewConnection ) 9Bu::Protocol::~Protocol()
13{ 10{
14 pConnection = pNewConnection;
15} 11}
16 12
17Connection *Protocol::getConnection()
18{
19 return pConnection;
20}
diff --git a/src/protocol.h b/src/protocol.h
index 09e1c98..bca337f 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,62 +1,27 @@
1#ifndef PROTOCOL_H 1#ifndef BU_PROTOCOL_H
2#define PROTOCOL_H 2#define BU_PROTOCOL_H
3 3
4#include "connection.h" 4#include <stdint.h>
5 5
6/** This is the template for a class that handles specialized input and output 6namespace Bu
7 * to connections of different types with different protocols.
8 *@author Mike Buland
9 */
10class Protocol
11{ 7{
12public: 8 class Client;
13 /** Constructor */
14 Protocol();
15 /** Deconstructor */
16 virtual ~Protocol();
17 9
18 /** 10 /**
19 * Function is called every time there is new data on the line. This is 11 *
20 * called directly from the Connection class to process data. This is not
21 * called whever there is pending data on the input, but every time new data
22 * is added to the input buffer.
23 *@returns True if processing went alright, false if something went wrong,
24 * I suppose. In truth this value is thrown away right now.
25 *@todo Either make a return value of false mean something, or make these
26 * void.
27 */ 12 */
28 virtual bool onNewData()=0; 13 class Protocol
14 {
15 public:
16 Protocol();
17 virtual ~Protocol();
29 18
30 /** 19 virtual void onNewConnection( Bu::Client *pClient )=0;
31 * Function is called when there is a new connection. This should only 20 virtual void onNewData( Bu::Client *pClient )=0;
32 * happen once per Protocol object, but gives each protocol object a
33 * chance to perform connection handshaking and initialization at a point
34 * where they know that they have a handle to an active Connection.
35 *@returns See onNewData
36 */
37 virtual bool onNewConnection()=0;
38
39 virtual void onNewClientConnection(){};
40 21
41 virtual void poll(){}; 22 private:
42
43 /**
44 * Sets the Protocol's Connection object. This is rather important, and
45 * handled usually by the ConnectionManager.
46 *@param pNewConnection The Connection object that this protocol will use to
47 * deal with the outside world.
48 */
49 void setConnection( class Connection *pNewConnection );
50
51 /**
52 * Get a pointer to this object's Connection object, or NULL if one was
53 * never set. If used with the ConnectionManager that should never happen.
54 *@returns A pointer to the active Connection.
55 */
56 Connection *getConnection();
57 23
58private: 24 };
59 class Connection *pConnection; /**< The pointer to the Connection. */ 25}
60};
61 26
62#endif 27#endif
diff --git a/src/ringbuffer.cpp b/src/ringbuffer.cpp
new file mode 100644
index 0000000..feb9bc7
--- /dev/null
+++ b/src/ringbuffer.cpp
@@ -0,0 +1,2 @@
1#include "bu/ringbuffer.h"
2
diff --git a/src/ringbuffer.h b/src/ringbuffer.h
new file mode 100644
index 0000000..be80e2f
--- /dev/null
+++ b/src/ringbuffer.h
@@ -0,0 +1,97 @@
1#ifndef BU_RING_BUFFER_H
2#define BU_RING_BUFFER_H
3
4#include <memory>
5#include "bu/exceptionbase.h"
6
7namespace Bu
8{
9 template<typename value, typename valuealloc=std::allocator<value> >
10 class RingBuffer
11 {
12 public:
13 RingBuffer( int nCapacity ) :
14 nCapacity( nCapacity ),
15 nStart( -1 ),
16 nEnd( -2 )
17 {
18 aData = va.allocate( nCapacity );
19 }
20
21 virtual ~RingBuffer()
22 {
23 for( int j = nStart; j < nEnd; j=(j+1%nCapacity) )
24 {
25 va.destroy( &aData[j] );
26 }
27 va.deallocate( aData, nCapacity );
28 }
29
30 int getCapacity()
31 {
32 return nCapacity;
33 }
34
35 bool isFilled()
36 {
37 return (nStart == nEnd);
38 }
39
40 bool isEmpty()
41 {
42 return (nStart == -1);
43 }
44
45 void enqueue( const value &v )
46 {
47 if( nStart == -1 )
48 {
49 nStart = 0;
50 nEnd = 1;
51 va.construct( &aData[0], v );
52 }
53 else if( nStart == nEnd )
54 {
55 throw ExceptionBase("Hey, it's full!");
56 }
57 else
58 {
59 va.construct( &aData[nEnd], v );
60 nEnd = (nEnd+1)%nCapacity;
61 }
62 }
63
64 value dequeue()
65 {
66 if( nStart == -1 )
67 {
68 throw ExceptionBase("No data");
69 }
70 else
71 {
72 value &v = aData[nStart];
73 va.destroy( &aData[nStart] );
74 nStart = (nStart+1)%nCapacity;
75 if( nStart == nEnd )
76 {
77 nStart = -1;
78 nEnd = -2;
79 }
80 return v;
81 }
82 }
83
84 value &operator[]( int nIndex )
85 {
86 return aData[(nIndex+nStart)%nCapacity];
87 }
88
89 private:
90 int nCapacity;
91 value *aData;
92 valuealloc va;
93 int nStart, nEnd;
94 };
95}
96
97#endif
diff --git a/src/serializable.cpp b/src/serializable.cpp
deleted file mode 100644
index fd50943..0000000
--- a/src/serializable.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
1#include "serializable.h"
2
3Serializable::Serializable()
4{
5}
6Serializable::~Serializable()
7{
8}
diff --git a/src/serializable.h b/src/serializable.h
deleted file mode 100644
index 06def29..0000000
--- a/src/serializable.h
+++ /dev/null
@@ -1,34 +0,0 @@
1#ifndef SERIALIZER_H
2#define SERIALIZER_H
3
4//#include "serializer.h"
5
6/**
7 * The base class for any class you want to serialize. Simply include this as
8 * a base class, implement the purely virtual serialize function and you've got
9 * an easily serializable class.
10 */
11class Serializable
12{
13public:
14 /**
15 * Does nothing, here for completeness.
16 */
17 Serializable();
18
19 /**
20 * Here to ensure the deconstructor is virtual.
21 */
22 virtual ~Serializable();
23
24 /**
25 * This is the main workhorse of the serialization system, just override and
26 * you've got a serializable class. A reference to the Serializer archive
27 * used is passed in as your only parameter, query it to discover if you are
28 * loading or saving.
29 * @param ar A reference to the Serializer object to use.
30 */
31 virtual void serialize( class Serializer &ar )=0;
32};
33
34#endif
diff --git a/src/serializer.cpp b/src/serializer.cpp
deleted file mode 100644
index 636224e..0000000
--- a/src/serializer.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
1#include "serializer.h"
2#include "serializable.h"
3#include <list>
4
5Serializer::Serializer(bool bLoading):
6 bLoading(bLoading)
7{
8}
9Serializer::~Serializer()
10{
11}
12
13bool Serializer::isLoading()
14{
15 return bLoading;
16}
17Serializer &Serializer::operator<<(bool p)
18{
19 write( &p, sizeof(p) );
20 return *this;
21}
22Serializer &Serializer::operator<<(int8_t p)
23{
24 write( &p, sizeof(p) );
25 return *this;
26}
27Serializer &Serializer::operator<<(int16_t p)
28{
29 write( &p, sizeof(p) );
30 return *this;
31}
32Serializer &Serializer::operator<<(int32_t p)
33{
34 write( &p, sizeof(p) );
35 return *this;
36}
37Serializer &Serializer::operator<<(int64_t p)
38{
39 write( &p, sizeof(p) );
40 return *this;
41}
42Serializer &Serializer::operator<<(uint8_t p)
43{
44 write( &p, sizeof(p) );
45 return *this;
46}
47Serializer &Serializer::operator<<(uint16_t p)
48{
49 write( &p, sizeof(p) );
50 return *this;
51}
52Serializer &Serializer::operator<<(uint32_t p)
53{
54 write( &p, sizeof(p) );
55 return *this;
56}
57Serializer &Serializer::operator<<(uint64_t p)
58{
59 write( &p, sizeof(p) );
60 return *this;
61}
62Serializer &Serializer::operator<<(long p)
63{
64 write( &p, sizeof(p) );
65 return *this;
66}
67Serializer &Serializer::operator<<(float p)
68{
69 write( &p, sizeof(p) );
70 return *this;
71}
72Serializer &Serializer::operator<<(double p)
73{
74 write( &p, sizeof(p) );
75 return *this;
76}
77Serializer &Serializer::operator<<(long double p)
78{
79 write( &p, sizeof(p) );
80 return *this;
81}
82
83Serializer &Serializer::operator>>(bool &p)
84{
85 read( &p, sizeof(p) );
86 return *this;
87}
88Serializer &Serializer::operator>>(int8_t &p)
89{
90 read( &p, sizeof(p) );
91 return *this;
92}
93Serializer &Serializer::operator>>(int16_t &p)
94{
95 read( &p, sizeof(p) );
96 return *this;
97}
98Serializer &Serializer::operator>>(int32_t &p)
99{
100 read( &p, sizeof(p) );
101 return *this;
102}
103Serializer &Serializer::operator>>(int64_t &p)
104{
105 read( &p, sizeof(p) );
106 return *this;
107}
108Serializer &Serializer::operator>>(uint8_t &p)
109{
110 read( &p, sizeof(p) );
111 return *this;
112}
113Serializer &Serializer::operator>>(uint16_t &p)
114{
115 read( &p, sizeof(p) );
116 return *this;
117}
118Serializer &Serializer::operator>>(uint32_t &p)
119{
120 read( &p, sizeof(p) );
121 return *this;
122}
123Serializer &Serializer::operator>>(uint64_t &p)
124{
125 read( &p, sizeof(p) );
126 return *this;
127}
128Serializer &Serializer::operator>>(long &p)
129{
130 read( &p, sizeof(p) );
131 return *this;
132}
133Serializer &Serializer::operator>>(float &p)
134{
135 read( &p, sizeof(p) );
136 return *this;
137}
138Serializer &Serializer::operator>>(double &p)
139{
140 read( &p, sizeof(p) );
141 return *this;
142}
143Serializer &Serializer::operator>>(long double &p)
144{
145 read( &p, sizeof(p) );
146 return *this;
147}
148
149Serializer &Serializer::operator&&(bool &p)
150{
151 if (bLoading)
152 {
153 return *this >> p;
154 }
155 else
156 {
157 return *this << p;
158 }
159}
160
161Serializer &Serializer::operator&&(int8_t &p)
162{
163 if (bLoading)
164 {
165 return *this >> p;
166 }
167 else
168 {
169 return *this << p;
170 }
171}
172
173Serializer &Serializer::operator&&(int16_t &p)
174{
175 if (bLoading)
176 {
177 return *this >> p;
178 }
179 else
180 {
181 return *this << p;
182 }
183}
184
185Serializer &Serializer::operator&&(int32_t &p)
186{
187 if (bLoading)
188 {
189 return *this >> p;
190 }
191 else
192 {
193 return *this << p;
194 }
195}
196
197Serializer &Serializer::operator&&(int64_t &p)
198{
199 if (bLoading)
200 {
201 return *this >> p;
202 }
203 else
204 {
205 return *this << p;
206 }
207}
208
209Serializer &Serializer::operator&&(uint8_t &p)
210{
211 if (bLoading)
212 {
213 return *this >> p;
214 }
215 else
216 {
217 return *this << p;
218 }
219}
220
221Serializer &Serializer::operator&&(uint16_t &p)
222{
223 if (bLoading)
224 {
225 return *this >> p;
226 }
227 else
228 {
229 return *this << p;
230 }
231}
232
233Serializer &Serializer::operator&&(uint32_t &p)
234{
235 if (bLoading)
236 {
237 return *this >> p;
238 }
239 else
240 {
241 return *this << p;
242 }
243}
244
245Serializer &Serializer::operator&&(uint64_t &p)
246{
247 if (bLoading)
248 {
249 return *this >> p;
250 }
251 else
252 {
253 return *this << p;
254 }
255}
256
257Serializer &Serializer::operator&&(float &p)
258{
259 if (bLoading)
260 {
261 return *this >> p;
262 }
263 else
264 {
265 return *this << p;
266 }
267}
268
269Serializer &Serializer::operator&&(double &p)
270{
271 if (bLoading)
272 {
273 return *this >> p;
274 }
275 else
276 {
277 return *this << p;
278 }
279}
280
281Serializer &Serializer::operator&&(long double &p)
282{
283 if (bLoading)
284 {
285 return *this >> p;
286 }
287 else
288 {
289 return *this << p;
290 }
291}
292
293
294Serializer &operator<<(Serializer &s, Serializable &p)
295{
296 p.serialize( s );
297 return s;
298}
299
300Serializer &operator>>(Serializer &s, Serializable &p)
301{
302 p.serialize( s );
303 return s;
304}
305
306Serializer &operator&&(Serializer &s, Serializable &p)
307{
308 if (s.isLoading())
309 {
310 return s >> p;
311 }
312 else
313 {
314 return s << p;
315 }
316}
317
318Serializer &operator<<( Serializer &ar, std::string &s )
319{
320 ar << (uint32_t)s.length();
321 ar.write( s.c_str(), s.length() );
322
323 return ar;
324}
325
326Serializer &operator>>( Serializer &ar, std::string &s )
327{
328 uint32_t l;
329 ar >> l;
330 char *tmp = new char[l+1];
331 tmp[l] = '\0';
332 ar.read( tmp, l );
333 s = tmp;
334 delete[] tmp;
335
336 return ar;
337}
338
diff --git a/src/serializer.h b/src/serializer.h
deleted file mode 100644
index 3af489c..0000000
--- a/src/serializer.h
+++ /dev/null
@@ -1,80 +0,0 @@
1#ifndef SERIALIZABLE_H
2#define SERIALIZABLE_H
3
4#include <stdint.h>
5#include <string>
6#include <list>
7//#include "serializable.h"
8
9class Serializer
10{
11private:
12 bool bLoading;
13public:
14 bool isLoading();
15
16 enum
17 {
18 load = true,
19 save = false
20 };
21
22 Serializer(bool bLoading);
23 virtual ~Serializer();
24 virtual void close()=0;
25
26 virtual void write(const void *, int32_t)=0;
27 virtual void read(void *, int32_t)=0;
28
29 virtual Serializer &operator<<(bool);
30 virtual Serializer &operator<<(int8_t);
31 virtual Serializer &operator<<(int16_t);
32 virtual Serializer &operator<<(int32_t);
33 virtual Serializer &operator<<(int64_t);
34 virtual Serializer &operator<<(uint8_t);
35 virtual Serializer &operator<<(uint16_t);
36 virtual Serializer &operator<<(uint32_t);
37 virtual Serializer &operator<<(uint64_t);
38 virtual Serializer &operator<<(long);
39 virtual Serializer &operator<<(float);
40 virtual Serializer &operator<<(double);
41 virtual Serializer &operator<<(long double);
42
43 virtual Serializer &operator>>(bool &);
44 virtual Serializer &operator>>(int8_t &);
45 virtual Serializer &operator>>(int16_t &);
46 virtual Serializer &operator>>(int32_t &);
47 virtual Serializer &operator>>(int64_t &);
48 virtual Serializer &operator>>(uint8_t &);
49 virtual Serializer &operator>>(uint16_t &);
50 virtual Serializer &operator>>(uint32_t &);
51 virtual Serializer &operator>>(uint64_t &);
52 virtual Serializer &operator>>(long &);
53 virtual Serializer &operator>>(float &);
54 virtual Serializer &operator>>(double &);
55 virtual Serializer &operator>>(long double &);
56
57 virtual Serializer &operator&&(bool &);
58 virtual Serializer &operator&&(int8_t &);
59 virtual Serializer &operator&&(int16_t &);
60 virtual Serializer &operator&&(int32_t &);
61 virtual Serializer &operator&&(int64_t &);
62 virtual Serializer &operator&&(uint8_t &);
63 virtual Serializer &operator&&(uint16_t &);
64 virtual Serializer &operator&&(uint32_t &);
65 virtual Serializer &operator&&(uint64_t &);
66 virtual Serializer &operator&&(float &);
67 virtual Serializer &operator&&(double &);
68 virtual Serializer &operator&&(long double &);
69
70 //virtual Serializer &operator&(Serializable &);
71};
72
73Serializer &operator<<(Serializer &, class Serializable &);
74Serializer &operator>>(Serializer &, class Serializable &);
75Serializer &operator&&(Serializer &s, class Serializable &p);
76
77Serializer &operator<<(Serializer &, std::string &);
78Serializer &operator>>(Serializer &, std::string &);
79
80#endif
diff --git a/src/server.cpp b/src/server.cpp
new file mode 100644
index 0000000..d07a597
--- /dev/null
+++ b/src/server.cpp
@@ -0,0 +1,96 @@
1#include "bu/server.h"
2#include <errno.h>
3#include "bu/serversocket.h"
4#include "bu/client.h"
5#include "bu/socket.h"
6
7Bu::Server::Server() :
8 nTimeoutSec( 0 ),
9 nTimeoutUSec( 0 )
10{
11 FD_ZERO( &fdActive );
12}
13
14Bu::Server::~Server()
15{
16}
17
18void Bu::Server::addPort( int nPort, int nPoolSize )
19{
20 ServerSocket *s = new ServerSocket( nPort, nPoolSize );
21 int nSocket = s->getSocket();
22 FD_SET( nSocket, &fdActive );
23 hServers.insert( nSocket, s );
24}
25
26void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize )
27{
28 ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize );
29 int nSocket = s->getSocket();
30 FD_SET( nSocket, &fdActive );
31 hServers.insert( nSocket, s );
32}
33
34void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec )
35{
36 this->nTimeoutSec = nTimeoutSec;
37 this->nTimeoutUSec = nTimeoutUSec;
38}
39
40void Bu::Server::scan()
41{
42 struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec };
43
44 fd_set fdRead = fdActive;
45 fd_set fdWrite = fdActive;
46 fd_set fdException = fdActive;
47
48 if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, &fdRead, NULL, &fdException, &xTimeout ) ) < 0 )
49 {
50 throw ExceptionBase("Error attempting to scan open connections.");
51 }
52
53 for( int j = 0; j < FD_SETSIZE; j++ )
54 {
55 if( FD_ISSET( j, &fdRead ) )
56 {
57 if( hServers.has( j ) )
58 {
59 ServerSocket *pSrv = hServers.get( j );
60 addClient( pSrv->accept(), pSrv->getPort() );
61 }
62 else
63 {
64 Client *pClient = hClients.get( j );
65 pClient->processInput();
66 if( !pClient->isOpen() )
67 {
68 onClosedConnection( pClient );
69 hClients.erase( j );
70 FD_CLR( j, &fdActive );
71 }
72 }
73 }
74 }
75
76 // Now we just try to write all the pending data on all the sockets.
77 // this could be done better eventually, if we care about the socket
78 // wanting to accept writes (using a select).
79 for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ )
80 {
81 (*i)->processOutput();
82 }
83}
84
85void Bu::Server::addClient( int nSocket, int nPort )
86{
87 FD_SET( nSocket, &fdActive );
88
89 Client *c = new Client(
90 new Bu::Socket( nSocket )
91 );
92 hClients.insert( nSocket, c );
93
94 onNewConnection( c, nPort );
95}
96
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..302b6e3
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,61 @@
1#ifndef BU_SERVER_H
2#define BU_SERVER_H
3
4#include <stdint.h>
5
6#include "bu/fstring.h"
7#include "bu/list.h"
8
9namespace Bu
10{
11 class ServerSocket;
12 class Socket;
13 class Client;
14
15 /**
16 * Core of a network server. This class is distinct from a ServerSocket in
17 * that a ServerSocket is one listening socket, nothing more. Socket will
18 * manage a pool of both ServerSockets and connected Sockets along with
19 * their protocols and buffers.
20 *
21 * To start serving on a new port, use the addPort functions. Each call to
22 * addPort creates a new ServerSocket, starts it listening, and adds it to
23 * the server pool.
24 *
25 * All of the real work is done by scan, which will wait for up
26 * to the timeout set by setTimeout before returning if there is no data
27 * pending. scan should probably be called in some sort of tight
28 * loop, possibly in it's own thread, or in the main control loop.
29 *
30 * In order to use a Server you must subclass it and implement the pure
31 * virtual functions. These allow you to receive notification of events
32 * happening within the server itself, and actually makes it useful.
33 */
34 class Server
35 {
36 public:
37 Server();
38 virtual ~Server();
39
40 void addPort( int nPort, int nPoolSize=40 );
41 void addPort( const FString &sAddr, int nPort, int nPoolSize=40 );
42
43 void scan();
44 void setTimeout( int nTimeoutSec, int nTimeoutUSec=0 );
45
46 void addClient( int nSocket, int nPort );
47
48 virtual void onNewConnection( Client *pClient, int nPort )=0;
49 virtual void onClosedConnection( Client *pClient )=0;
50
51 private:
52 int nTimeoutSec;
53 int nTimeoutUSec;
54 fd_set fdActive;
55 Hash<int,ServerSocket *> hServers;
56 typedef Hash<int,Client *> ClientHash;
57 ClientHash hClients;
58 };
59}
60
61#endif
diff --git a/src/serversocket.cpp b/src/serversocket.cpp
new file mode 100644
index 0000000..1424630
--- /dev/null
+++ b/src/serversocket.cpp
@@ -0,0 +1,158 @@
1#include <time.h>
2#include <string.h>
3#include <stdio.h>
4#include <errno.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <termios.h>
10#include <netinet/in.h>
11#include <netdb.h>
12#include <arpa/inet.h>
13#include <fcntl.h>
14#include "serversocket.h"
15#include "exceptions.h"
16
17Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) :
18 nPort( nPort )
19{
20 /* Create the socket and set it up to accept connections. */
21 struct sockaddr_in name;
22
23 /* Give the socket a name. */
24 name.sin_family = AF_INET;
25 name.sin_port = htons( nPort );
26
27 // I think this specifies who we will accept connections from,
28 // a good thing to make configurable later on
29 name.sin_addr.s_addr = htonl( INADDR_ANY );
30
31 startServer( name, nPoolSize );
32}
33
34Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) :
35 nPort( nPort )
36{
37 /* Create the socket and set it up to accept connections. */
38 struct sockaddr_in name;
39
40 /* Give the socket a name. */
41 name.sin_family = AF_INET;
42 name.sin_port = htons( nPort );
43
44 inet_aton( sAddr.getStr(), &name.sin_addr );
45
46 startServer( name, nPoolSize );
47}
48
49Bu::ServerSocket::~ServerSocket()
50{
51}
52
53void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize )
54{
55 /* Create the socket. */
56 nServer = socket( PF_INET, SOCK_STREAM, 0 );
57 if( nServer < 0 )
58 {
59 throw Bu::SocketException("Couldn't create a listen socket.");
60 }
61
62 int opt = 1;
63 setsockopt(
64 nServer,
65 SOL_SOCKET,
66 SO_REUSEADDR,
67 (char *)&opt,
68 sizeof( opt )
69 );
70
71 if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 )
72 {
73 throw Bu::SocketException("Couldn't bind to the listen socket.");
74 }
75
76 if( listen( nServer, nPoolSize ) < 0 )
77 {
78 throw Bu::SocketException(
79 "Couldn't begin listening to the server socket."
80 );
81 }
82
83 FD_ZERO( &fdActive );
84 /* Initialize the set of active sockets. */
85 FD_SET( nServer, &fdActive );
86}
87
88int Bu::ServerSocket::getSocket()
89{
90 return nServer;
91}
92
93int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec )
94{
95 fd_set fdRead = fdActive;
96
97 struct timeval xT;
98
99 xT.tv_sec = nTimeoutSec;
100 xT.tv_usec = nTimeoutUSec;
101
102 if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 )
103 {
104 throw SocketException(
105 "Error scanning for new connections: %s", strerror( errno )
106 );
107 }
108
109 if( FD_ISSET( nServer, &fdRead ) )
110 {
111 struct sockaddr_in clientname;
112 size_t size;
113 int nClient;
114
115 size = sizeof( clientname );
116#ifdef __CYGWIN__
117 nClient = ::accept( nServer, (struct sockaddr *)&clientname,
118 (int *)&size
119 );
120#else
121 nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size );
122#endif
123 if( nClient < 0 )
124 {
125 throw SocketException(
126 "Error accepting a new connection: %s", strerror( errno )
127 );
128 }
129 char tmpa[20];
130 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
131 //"New connection from host %s, port %hd.",
132 // tmpa, ntohs (clientname.sin_port) );
133
134 {
135 int flags;
136
137 flags = fcntl( nClient, F_GETFL, 0 );
138 flags |= O_NONBLOCK;
139 if( fcntl( nClient, F_SETFL, flags ) < 0)
140 {
141 throw SocketException(
142 "Error setting option on client socket: %s",
143 strerror( errno )
144 );
145 }
146 }
147
148 return nClient;
149 }
150
151 return -1;
152}
153
154int Bu::ServerSocket::getPort()
155{
156 return nPort;
157}
158
diff --git a/src/serversocket.h b/src/serversocket.h
new file mode 100644
index 0000000..b4ee247
--- /dev/null
+++ b/src/serversocket.h
@@ -0,0 +1,39 @@
1#ifndef BU_SERVER_SOCKET_H
2#define BU_SERVER_SOCKET_H
3
4#include <stdint.h>
5#include "bu/fstring.h"
6
7namespace Bu
8{
9 /**
10 * A single tcp/ip server socket. When created the server socket will bind
11 * to the specified interface and port, and immediately begin listening for
12 * connections. When connections come in they are pooled by the networking
13 * drivers in the kernel until they are accepted, this means that failure
14 * to keep space in the connection pool will result in connection refusals.
15 *
16 * Although the accept function returns an integral file descriptor, it is
17 * designed to be used with the Socket class.
18 */
19 class ServerSocket
20 {
21 public:
22 ServerSocket( int nPort, int nPoolSize=40 );
23 ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 );
24 virtual ~ServerSocket();
25
26 int accept( int nTimeoutSec=0, int nTimeoutUSec=0 );
27 int getSocket();
28 int getPort();
29
30 private:
31 void startServer( struct sockaddr_in &name, int nPoolSize );
32
33 fd_set fdActive;
34 int nServer;
35 int nPort;
36 };
37}
38
39#endif
diff --git a/src/sfile.cpp b/src/sfile.cpp
deleted file mode 100644
index f1de03c..0000000
--- a/src/sfile.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
1#include "sfile.h"
2#include "exceptions.h"
3
4SFile::SFile( const char *sName, const char *sFlags )
5{
6 fh = fopen( sName, sFlags );
7}
8
9SFile::~SFile()
10{
11}
12
13void SFile::close()
14{
15 if( fh )
16 {
17 fclose( fh );
18 fh = NULL;
19 }
20}
21
22size_t SFile::read( char *pBuf, size_t nBytes )
23{
24 if( !fh )
25 throw FileException("File not open.");
26
27 return fread( pBuf, 1, nBytes, fh );
28}
29
30size_t SFile::write( const char *pBuf, size_t nBytes )
31{
32 if( !fh )
33 throw FileException("File not open.");
34
35 return fwrite( pBuf, 1, nBytes, fh );
36}
37
38long SFile::tell()
39{
40 if( !fh )
41 throw FileException("File not open.");
42
43 return ftell( fh );
44}
45
46void SFile::seek( long offset )
47{
48 if( !fh )
49 throw FileException("File not open.");
50
51 fseek( fh, offset, SEEK_CUR );
52}
53
54void SFile::setPos( long pos )
55{
56 if( !fh )
57 throw FileException("File not open.");
58
59 fseek( fh, pos, SEEK_SET );
60}
61
62void SFile::setPosEnd( long pos )
63{
64 if( !fh )
65 throw FileException("File not open.");
66
67 fseek( fh, pos, SEEK_END );
68}
69
70bool SFile::isEOS()
71{
72 return feof( fh );
73}
74
diff --git a/src/sfile.h b/src/sfile.h
deleted file mode 100644
index b51e5bc..0000000
--- a/src/sfile.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef SFILE_H
2#define SFILE_H
3
4#include <stdint.h>
5
6#include "stream.h"
7
8class SFile : public Stream
9{
10public:
11 SFile( const char *sName, const char *sFlags );
12 virtual ~SFile();
13
14 virtual void close();
15 virtual size_t read( char *pBuf, size_t nBytes );
16 virtual size_t write( const char *pBuf, size_t nBytes );
17
18 virtual long tell();
19 virtual void seek( long offset );
20 virtual void setPos( long pos );
21 virtual void setPosEnd( long pos );
22 virtual bool isEOS();
23
24private:
25 FILE *fh;
26
27};
28
29#endif
diff --git a/src/singleton.h b/src/singleton.h
index 47adbd5..c43d71b 100644
--- a/src/singleton.h
+++ b/src/singleton.h
@@ -1,59 +1,62 @@
1#ifndef SINGLETON_H 1#ifndef BU_SINGLETON_H
2#define SINGLETON_H 2#define BU_SINGLETON_H
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6/** 6namespace Bu
7 * Provides singleton functionality in a modular sort of way. Make this the
8 * base class of any other class and you immediately gain singleton
9 * functionality. Be sure to make your constructor and various functions use
10 * intellegent scoping. Cleanup and instantiation are performed automatically
11 * for you at first use and program exit. There are two things that you must
12 * do when using this template, first is to inherit from it with the name of
13 * your class filling in for T and then make this class a friend of your class.
14 *@code
15 * // Making the Single Singleton:
16 * class Single : public Singleton<Single>
17 * {
18 * friend class Singleton<Single>;
19 * protected:
20 * Single();
21 * ...
22 * };
23 @endcode
24 * You can still add public functions and variables to your new Singleton child
25 * class, but your constructor should be protected (hence the need for the
26 * friend decleration).
27 *@author Mike Buland
28 */
29template <class T>
30class Singleton
31{ 7{
32protected:
33 /** 8 /**
34 * Private constructor. This constructor is empty but has a body so that 9 * Provides singleton functionality in a modular sort of way. Make this the
35 * you can make your own override of it. Be sure that you're override is 10 * base class of any other class and you immediately gain singleton
36 * also protected. 11 * functionality. Be sure to make your constructor and various functions use
12 * intellegent scoping. Cleanup and instantiation are performed automatically
13 * for you at first use and program exit. There are two things that you must
14 * do when using this template, first is to inherit from it with the name of
15 * your class filling in for T and then make this class a friend of your class.
16 *@code
17 * // Making the Single Singleton:
18 * class Single : public Singleton<Single>
19 * {
20 * friend class Singleton<Single>;
21 * protected:
22 * Single();
23 * ...
24 * };
25 @endcode
26 * You can still add public functions and variables to your new Singleton child
27 * class, but your constructor should be protected (hence the need for the
28 * friend decleration).
29 *@author Mike Buland
37 */ 30 */
38 Singleton() {}; 31 template <class T>
32 class Singleton
33 {
34 protected:
35 /**
36 * Private constructor. This constructor is empty but has a body so that
37 * you can make your own override of it. Be sure that you're override is
38 * also protected.
39 */
40 Singleton() {};
39 41
40private: 42 private:
41 /** 43 /**
42 * Copy constructor, defined so that you could write your own as well. 44 * Copy constructor, defined so that you could write your own as well.
43 */ 45 */
44 Singleton( const Singleton& ); 46 Singleton( const Singleton& );
45 47
46public: 48 public:
47 /** 49 /**
48 * Get a handle to the contained instance of the contained class. It is 50 * Get a handle to the contained instance of the contained class. It is
49 * a reference. 51 * a reference.
50 *@returns A reference to the contained object. 52 *@returns A reference to the contained object.
51 */ 53 */
52 static T &getInstance() 54 static T &getInstance()
53 { 55 {
54 static T i; 56 static T i;
55 return i; 57 return i;
56 } 58 }
57}; 59 };
60}
58 61
59#endif 62#endif
diff --git a/src/socket.cpp b/src/socket.cpp
new file mode 100644
index 0000000..e567061
--- /dev/null
+++ b/src/socket.cpp
@@ -0,0 +1,294 @@
1#include <string.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <sys/time.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include <errno.h>
13#include <fcntl.h>
14#include "socket.h"
15#include "exceptions.h"
16
17#define RBS (1024*2)
18
19Bu::Socket::Socket( int nSocket ) :
20 nSocket( nSocket ),
21 bActive( true )
22{
23}
24
25Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout )
26{
27 struct sockaddr_in xServerName;
28 bActive = false;
29
30 /* Create the socket. */
31 nSocket = socket( PF_INET, SOCK_STREAM, 0 );
32
33 if( nSocket < 0 )
34 {
35 throw ExceptionBase("Couldn't create socket.\n");
36 }
37
38 // These lines set the socket to non-blocking, a good thing?
39 int flags;
40 flags = fcntl(nSocket, F_GETFL, 0);
41 flags |= O_NONBLOCK;
42 if (fcntl(nSocket, F_SETFL, flags) < 0)
43 {
44 throw ExceptionBase("Couldn't set socket options.\n");
45 }
46
47 /* Connect to the server. */
48 //printf("Resolving hostname (%s)...\n", sAddr );
49 {
50 struct hostent *hostinfo;
51
52 xServerName.sin_family = AF_INET;
53 xServerName.sin_port = htons( nPort );
54 hostinfo = gethostbyname( sAddr.getStr() );
55 if (hostinfo == NULL)
56 {
57 throw ExceptionBase("Couldn't resolve hostname.\n");
58 }
59 xServerName.sin_addr = *(struct in_addr *) hostinfo->h_addr;
60 }
61
62 //printf("Making actual connection...");
63 //fflush( stdout );
64 connect(
65 nSocket,
66 (struct sockaddr *)&xServerName,
67 sizeof(xServerName)
68 );
69 //printf("Connected.\n");
70
71 bActive = true;
72
73 if( nTimeout > 0 )
74 {
75 fd_set rfds, wfds, efds;
76 int retval;
77
78 FD_ZERO(&rfds);
79 FD_SET(nSocket, &rfds);
80 FD_ZERO(&wfds);
81 FD_SET(nSocket, &wfds);
82 FD_ZERO(&efds);
83 FD_SET(nSocket, &efds);
84
85 struct timeval tv;
86 tv.tv_sec = nTimeout;
87 tv.tv_usec = 0;
88
89 retval = select( nSocket+1, &rfds, &wfds, &efds, &tv );
90
91 if( retval == 0 )
92 {
93 close();
94 throw ExceptionBase("Connection timeout.\n");
95 }
96
97 }
98}
99
100Bu::Socket::~Socket()
101{
102}
103
104void Bu::Socket::close()
105{
106 if( bActive )
107 {
108 fsync( nSocket );
109 ::close( nSocket );
110 }
111 bActive = false;
112}
113
114/*
115void Bu::Socket::read()
116{
117 char buffer[RBS];
118 int nbytes;
119 int nTotalRead=0;
120
121 for(;;)
122 {
123 //memset( buffer, 0, RBS );
124
125 nbytes = ::read( nSocket, buffer, RBS );
126 if( nbytes < 0 && errno != 0 && errno != EAGAIN )
127 {
128 //printf("errno: %d, %s\n", errno, strerror( errno ) );
129 //perror("readInput");
130 throw ConnectionException(
131 excodeReadError,
132 "Read error: %s",
133 strerror( errno )
134 );
135 }
136 else
137 {
138 if( nbytes <= 0 )
139 break;
140 nTotalRead += nbytes;
141 sReadBuf.append( buffer, nbytes );
142 if( nbytes < RBS )
143 {
144 break;
145 }
146
147 // New test, if data is divisible by RBS bytes on some libs the
148 // read could block, this keeps it from happening.
149 {
150 fd_set rfds;
151 FD_ZERO(&rfds);
152 FD_SET(nSocket, &rfds);
153 struct timeval tv = { 0, 0 };
154 int retval = select( nSocket+1, &rfds, NULL, NULL, &tv );
155 if( retval == -1 )
156 throw ConnectionException(
157 excodeBadReadError,
158 "Bad Read error"
159 );
160 if( !FD_ISSET( nSocket, &rfds ) )
161 break;
162 }
163 }
164 }
165}*/
166
167size_t Bu::Socket::read( void *pBuf, size_t nBytes )
168{
169 int nRead = TEMP_FAILURE_RETRY( ::read( nSocket, pBuf, nBytes ) );
170 if( nRead < 0 )
171 {
172 throw ConnectionException( excodeReadError, strerror(errno) );
173 }
174 return nRead;
175}
176
177//size_t Bu::Socket::read( void *pBuf, size_t nBytes, uint32_t nTimeout )
178//{
179//}
180
181size_t Bu::Socket::write( const void *pBuf, size_t nBytes )
182{
183 int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) );
184 if( nWrote < 0 )
185 {
186 throw ConnectionException( excodeWriteError, strerror(errno) );
187 }
188 return nWrote;
189}
190
191long Bu::Socket::tell()
192{
193 throw UnsupportedException();
194}
195
196void Bu::Socket::seek( long offset )
197{
198 throw UnsupportedException();
199}
200
201void Bu::Socket::setPos( long pos )
202{
203 throw UnsupportedException();
204}
205
206void Bu::Socket::setPosEnd( long pos )
207{
208 throw UnsupportedException();
209}
210
211bool Bu::Socket::isEOS()
212{
213 return !bActive;
214}
215
216bool Bu::Socket::canRead()
217{
218 fd_set rfds;
219 FD_ZERO(&rfds);
220 FD_SET(nSocket, &rfds);
221 struct timeval tv = { 0, 0 };
222 int retval = select( nSocket+1, &rfds, NULL, NULL, &tv );
223 if( retval == -1 )
224 throw ConnectionException(
225 excodeBadReadError,
226 "Bad Read error"
227 );
228 if( !FD_ISSET( nSocket, &rfds ) )
229 return false;
230 return true;
231}
232
233bool Bu::Socket::canWrite()
234{
235 fd_set wfds;
236 FD_ZERO(&wfds);
237 FD_SET(nSocket, &wfds);
238 struct timeval tv = { 0, 0 };
239 int retval = select( nSocket+1, NULL, &wfds, NULL, &tv );
240 if( retval == -1 )
241 throw ConnectionException(
242 excodeBadReadError,
243 "Bad Read error"
244 );
245 if( !FD_ISSET( nSocket, &wfds ) )
246 return false;
247 return true;
248}
249
250bool Bu::Socket::isReadable()
251{
252 return true;
253}
254
255bool Bu::Socket::isWritable()
256{
257 return true;
258}
259
260bool Bu::Socket::isSeekable()
261{
262 return false;
263}
264
265bool Bu::Socket::isBlocking()
266{
267 return false;
268}
269
270void Bu::Socket::setBlocking( bool bBlocking )
271{
272}
273
274void Bu::Socket::flush()
275{
276}
277
278bool Bu::Socket::isOpen()
279{
280 return bActive;
281}
282
283Bu::FString Bu::Socket::getAddress() const
284{
285 struct sockaddr_in addr;
286 socklen_t len = sizeof(addr);
287 addr.sin_family = AF_INET;
288 getsockname( nSocket, (sockaddr *)(&addr), &len );
289 char buf[150];
290 sprintf( buf, "%s", inet_ntoa( addr.sin_addr ) );
291
292 return buf;
293}
294
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..c291549
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,55 @@
1#ifndef BU_SOCKET_H
2#define BU_SOCKET_H
3
4#include <stdint.h>
5
6#include "stream.h"
7#include "fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class Socket : public Stream
15 {
16 public:
17 Socket( int nSocket );
18 Socket( const FString &sAddr, int nPort, int nTimeout=30 );
19 virtual ~Socket();
20
21 virtual void close();
22 //virtual void read();
23 virtual size_t read( void *pBuf, size_t nBytes );
24 virtual size_t read( void *pBuf, size_t nBytes, uint32_t nTimeout );
25 virtual size_t write( const void *pBuf, size_t nBytes );
26
27 virtual long tell();
28 virtual void seek( long offset );
29 virtual void setPos( long pos );
30 virtual void setPosEnd( long pos );
31 virtual bool isEOS();
32 virtual bool isOpen();
33
34 virtual void flush();
35
36 virtual bool canRead();
37 virtual bool canWrite();
38
39 virtual bool isReadable();
40 virtual bool isWritable();
41 virtual bool isSeekable();
42
43 virtual bool isBlocking();
44 virtual void setBlocking( bool bBlocking=true );
45
46 Bu::FString getAddress() const;
47
48 private:
49 int nSocket;
50 bool bActive;
51 FString sReadBuf;
52 };
53}
54
55#endif
diff --git a/src/sptr.cpp b/src/sptr.cpp
index 7f5e894..8ea7f8f 100644
--- a/src/sptr.cpp
+++ b/src/sptr.cpp
@@ -1 +1 @@
#include "sptr.h" #include "bu/sptr.h"
diff --git a/src/sptr.h b/src/sptr.h
index a3e6dc7..75851a6 100644
--- a/src/sptr.h
+++ b/src/sptr.h
@@ -1,144 +1,192 @@
1#ifndef SPTR_H 1#ifndef BU_SPTR_H
2#define SPTR_H 2#define BU_SPTR_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7template<typename T> class SPtr; 7namespace Bu
8template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src );
9
10template<typename T>
11class SPtr
12{ 8{
13 template<typename Tb, typename Ta> 9 template<typename T> class SPtr;
14 friend SPtr<Tb> SPtrCast( SPtr<Ta> pt ); 10 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src );
15public: 11
16 SPtr() : 12 template<typename T>
17 pRefCnt( NULL ), 13 class SPtr
18 pData( NULL ) 14 {
19 { 15 template<typename Tb, typename Ta>
20 } 16 friend SPtr<Tb> SPtrCast( SPtr<Ta> pt );
17 public:
18 SPtr() :
19 pRefCnt( NULL ),
20 pData( NULL )
21 {
22 }
21 23
22 ~SPtr() 24 ~SPtr()
23 { 25 {
24 decCount(); 26 decCount();
25 } 27 }
26 28
27 SPtr( const SPtr<T> &src ) : 29 SPtr( const SPtr<T> &src ) :
28 pRefCnt( src.pRefCnt ), 30 pRefCnt( src.pRefCnt ),
29 pData( src.pData ) 31 pData( src.pData )
30 { 32 {
31 if( pRefCnt ) 33 if( pRefCnt )
32 (*pRefCnt) += 1; 34 (*pRefCnt) += 1;
33 } 35 }
34 36
35 SPtr( T *pSrc ) : 37 SPtr( T *pSrc ) :
36 pRefCnt( NULL ), 38 pRefCnt( NULL ),
37 pData( pSrc ) 39 pData( pSrc )
38 {
39 if( pData )
40 { 40 {
41 pRefCnt = new int32_t; 41 if( pData )
42 (*pRefCnt) = 1; 42 {
43 pRefCnt = new int32_t;
44 (*pRefCnt) = 1;
45 }
43 } 46 }
44 }
45 47
46 int32_t count() const 48 /**
47 { 49 * Get the number of references to this pointer.
48 return *pRefCnt; 50 *@returns (int32_t) The number of references to this pointer.
49 } 51 */
52 int32_t count() const
53 {
54 return *pRefCnt;
55 }
50 56
51 const T *operator->() const 57 /**
52 { 58 * Pointer access operator.
53 return pData; 59 *@returns (const T *)
54 } 60 */
61 const T *operator->() const
62 {
63 return pData;
64 }
55 65
56 const T &operator*() const 66 /**
57 { 67 * Dereference operator.
58 return *pData; 68 *@returns (const T &) The value at the end of the pointer.
59 } 69 */
60 70 const T &operator*() const
61 T *operator->() 71 {
62 { 72 return *pData;
63 return pData; 73 }
64 } 74
75 /**
76 * Pointer access operator.
77 *@returns (T *)
78 */
79 T *operator->()
80 {
81 return pData;
82 }
65 83
66 T &operator*() 84 /**
67 { 85 * Dereference operator.
68 return *pData; 86 *@returns (T &) The value at the end of the pointer.
69 } 87 */
88 T &operator*()
89 {
90 return *pData;
91 }
70 92
71 SPtr<T> operator=( const SPtr<T> &src ) 93 /**
72 { 94 * Assignment operator.
73 decCount(); 95 *@param src (const SPtr<T> &)
74 pRefCnt = src.pRefCnt; 96 */
75 pData = src.pData; 97 SPtr<T> operator=( const SPtr<T> &src )
76 if( pRefCnt ) 98 {
77 (*pRefCnt) += 1; 99 decCount();
100 pRefCnt = src.pRefCnt;
101 pData = src.pData;
102 if( pRefCnt )
103 (*pRefCnt) += 1;
78 104
79 return *this; 105 return *this;
80 } 106 }
81 107
82 const SPtr<T> operator=( const SPtr<T> &src ) const 108 /**
83 { 109 * Assignment operator.
84 decCount(); 110 *@param src (const SPtr<T> &)
85 pRefCnt = src.pRefCnt; 111 */
86 pData = src.pData; 112 const SPtr<T> operator=( const SPtr<T> &src ) const
87 if( pRefCnt ) 113 {
88 (*pRefCnt) += 1; 114 decCount();
115 pRefCnt = src.pRefCnt;
116 pData = src.pData;
117 if( pRefCnt )
118 (*pRefCnt) += 1;
89 119
90 return *this; 120 return *this;
91 } 121 }
92 122
93 bool operator==( const SPtr<T> &src ) const 123 /**
94 { 124 * Equals comparison operator.
95 return pData == src.pData; 125 *@param src (const SPtr<T> &) The SPtr to compare to.
96 } 126 *@returns (bool) Are the equal?
127 */
128 bool operator==( const SPtr<T> &src ) const
129 {
130 return pData == src.pData;
131 }
97 132
98 bool operator==( const T *src ) const 133 /**
99 { 134 * Equals comparison operator.
100 return pData == src; 135 *@param src (const T *) The pointer to compare to.
101 } 136 *@returns (bool) Are the equal?
137 */
138 bool operator==( const T *src ) const
139 {
140 return pData == src;
141 }
102 142
103 operator bool() const 143 /**
104 { 144 * Boolean cast operator. Do we have a pointer?
105 return pRefCnt != NULL; 145 */
106 } 146 operator bool() const
147 {
148 return pRefCnt != NULL;
149 }
107 150
108 bool isSet() const 151 /**
109 { 152 * Do we have a pointer?
110 return pRefCnt != NULL; 153 *@returns (bool) Do we have a pointer?
111 } 154 */
155 bool isSet() const
156 {
157 return pRefCnt != NULL;
158 }
112 159
113private: 160 private:
114 void decCount() const 161 void decCount() const
115 {
116 if( pRefCnt )
117 { 162 {
118 (*pRefCnt) -= 1; 163 if( pRefCnt )
119 //printf("Decrementing ref-count to %d\n", *pRefCnt );
120 if( (*pRefCnt) == 0 )
121 { 164 {
122 delete pRefCnt; 165 (*pRefCnt) -= 1;
123 delete pData; 166 //printf("Decrementing ref-count to %d\n", *pRefCnt );
124 pRefCnt = NULL; 167 if( (*pRefCnt) == 0 )
125 pData = NULL; 168 {
169 delete pRefCnt;
170 delete pData;
171 pRefCnt = NULL;
172 pData = NULL;
173 }
126 } 174 }
127 } 175 }
128 }
129 176
130 mutable int32_t *pRefCnt; 177 mutable int32_t *pRefCnt;
131 mutable T *pData; 178 mutable T *pData;
132}; 179 };
133 180
134template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src ) 181 template< typename Tb, typename Ta > SPtr<Tb> SPtrCast( SPtr<Ta> src )
135{ 182 {
136 SPtr<Tb> ret; 183 SPtr<Tb> ret;
137 ret.pRefCnt = src.pRefCnt; 184 ret.pRefCnt = src.pRefCnt;
138 ret.pData = dynamic_cast<Tb *>(src.pData); 185 ret.pData = dynamic_cast<Tb *>(src.pData);
139 if( ret.pRefCnt ) 186 if( ret.pRefCnt )
140 (*(ret.pRefCnt)) += 1; 187 (*(ret.pRefCnt)) += 1;
141 return ret; 188 return ret;
189 }
142} 190}
143 191
144#endif 192#endif
diff --git a/src/stream.cpp b/src/stream.cpp
index 856a58d..267a7d1 100644
--- a/src/stream.cpp
+++ b/src/stream.cpp
@@ -1,10 +1,10 @@
1#include "stream.h" 1#include "stream.h"
2 2
3Stream::Stream() 3Bu::Stream::Stream()
4{ 4{
5} 5}
6 6
7Stream::~Stream() 7Bu::Stream::~Stream()
8{ 8{
9} 9}
10 10
diff --git a/src/stream.h b/src/stream.h
index e086e28..1e236a6 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -1,27 +1,143 @@
1#ifndef STREAM_H 1#ifndef BU_STREAM_H
2#define STREAM_H 2#define BU_STREAM_H
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <stdio.h> 5#include <stdio.h>
6 6
7class Stream 7namespace Bu
8{ 8{
9public: 9 /**
10 Stream(); 10 * The basis for a completely general data transport mechanism. Anything
11 virtual ~Stream(); 11 * that inherits from this should provide at least the basic read and/or
12 * write functions, and very probably the close function. Any functions
13 * that aren't supported should throw an exception if called.
14 *
15 * The constructor of a child class should pretty much universally be used
16 * to open the stream. I can't think of anything that should require an
17 * exception.
18 */
19 class Stream
20 {
21 public:
22 Stream();
23 virtual ~Stream();
12 24
13 virtual void close() = 0; 25 /**
14 virtual size_t read( char *pBuf, size_t nBytes ) = 0; 26 * Close the stream.
15 virtual size_t write( const char *pBuf, size_t nBytes ) = 0; 27 */
28 virtual void close() = 0;
16 29
17 virtual long tell() = 0; 30 /**
18 virtual void seek( long offset ) = 0; 31 * Read data from the stream into a buffer.
19 virtual void setPos( long pos ) = 0; 32 *@param pBuf (void *) Buffer which will be filled.
20 virtual void setPosEnd( long pos ) = 0; 33 *@param nBytes (size_t) Max data to read.
21 virtual bool isEOS() = 0; 34 *@returns (size_t) Amount of data read.
35 */
36 virtual size_t read( void *pBuf, size_t nBytes ) = 0;
22 37
23private: 38 /**
39 * Write data to the stream.
40 *@param pBuf (const void *) The data to be written.
41 *@param nBytes (size_t) Amount of data to write from pBuf.
42 *@returns (size_t) Amount of data actually written.
43 */
44 virtual size_t write( const void *pBuf, size_t nBytes ) = 0;
24 45
25}; 46 /**
47 * Get the current position in the stream.
48 *@returns (long) The current position in the stream.
49 */
50 virtual long tell() = 0;
51
52 /**
53 * Seek to a position in the stream relative to the current position.
54 *@param offset (long) Offset from current position to seek to.
55 */
56 virtual void seek( long offset ) = 0;
57
58 /**
59 * Set position in the stream relative to the start of the stream.
60 *@param pos (long) The position.
61 */
62 virtual void setPos( long pos ) = 0;
63
64 /**
65 * Set position in the stream relative to the end of the stream.
66 *@param pos (long) The position.
67 */
68 virtual void setPosEnd( long pos ) = 0;
69
70 /**
71 * Are we at the end of the stream?
72 *@returns (bool) Are we at the end of the stream?
73 */
74 virtual bool isEOS() = 0;
75
76 /**
77 * Is the stream open?
78 *@returns (bool) Is the stream open?
79 */
80 virtual bool isOpen() = 0;
81
82 /**
83 * Flush any data still held in buffers.
84 */
85 virtual void flush() = 0;
86
87 /**
88 * In non-blocking streams this indicates if a read operation will
89 * return data at the moment or not. In blocking streams this should
90 * return the same value as isEOS().
91 */
92 virtual bool canRead() = 0;
93
94 /**
95 * In non-blocking streams this indicates if a write operation will
96 * succeed or fail. In some cases writing is not allowed (e.g.
97 * internal buffers are full) temporarilly. In blocking streams this
98 * should return the same value as isWritable.
99 */
100 virtual bool canWrite() = 0;
101
102 /**
103 * Indicates if the stream is capable of read operations. This does not
104 * indicate if such operations will return useful data, see canRead for
105 * that.
106 */
107 virtual bool isReadable() = 0;
108
109 /**
110 * Indicates if the stream is capable of write operations. This does
111 * not indicate if such operations will succeed or fail, see canWrite
112 * for that.
113 */
114 virtual bool isWritable() = 0;
115
116 /**
117 * Indicates if the stream is capable of seek operations. This is
118 * generally false for non-blocking streams. Some buffered streams may
119 * support limited in-buffer seeking.
120 */
121 virtual bool isSeekable() = 0;
122
123 /**
124 * Are we currently set to block mode?
125 *@returns (bool)
126 */
127 virtual bool isBlocking() = 0;
128
129 /**
130 * Set stream to blocking or non-blocking mode.
131 *@param bBlocking (bool) Whether we should block or not.
132 */
133 virtual void setBlocking( bool bBlocking=true ) = 0;
134
135 public: // Filters
136
137
138 private:
139
140 };
141}
26 142
27#endif 143#endif
diff --git a/src/tafnode.cpp b/src/tafnode.cpp
new file mode 100644
index 0000000..53b782e
--- /dev/null
+++ b/src/tafnode.cpp
@@ -0,0 +1,165 @@
1#include "tafnode.h"
2
3Bu::TafNode::TafNode( NodeType eType ) :
4 eType( eType )
5{
6}
7
8Bu::TafNode::~TafNode()
9{
10}
11
12const Bu::TafNode::NodeType Bu::TafNode::getType() const
13{
14 return eType;
15}
16
17/*
18const Bu::TafNode::PropList &Bu::TafNode::getProperties( const Bu::FString &sName ) const
19{
20 return hProp.get( sName );
21}
22
23const Bu::TafNode::NodeList &Bu::TafNode::getChildren( const Bu::FString &sName ) const
24{
25 return hChildren.get( sName );
26}
27
28const Bu::FString &Bu::TafNode::getProperty( const Bu::FString &sName ) const
29{
30 return getProperties( sName ).first();
31}
32
33const Bu::TafNode *Bu::TafNode::getChild( const Bu::FString &sName ) const
34{
35 return getChildren( sName ).first();
36}
37*/
38
39Bu::TafGroup::TafGroup( const Bu::FString &sName ) :
40 TafNode( typeGroup ),
41 sName( sName )
42{
43}
44
45Bu::TafGroup::~TafGroup()
46{
47 //printf("Entering Bu::TafNode::~TafNode() \"%s\"\n", sName.getStr() );
48 for( NodeList::iterator i = lChildren.begin(); i != lChildren.end(); i++ )
49 {
50 delete (*i);
51 }
52}
53
54const Bu::FString &Bu::TafGroup::getName() const
55{
56 return sName;
57}
58
59Bu::TafNode *Bu::TafGroup::addChild( Bu::TafNode *pNode )
60{
61 switch( pNode->getType() )
62 {
63 case typeGroup:
64 addChild( (Bu::TafGroup *)pNode );
65 break;
66
67 case typeProperty:
68 addChild( (Bu::TafProperty *)pNode );
69 break;
70
71 case typeComment:
72 addChild( (Bu::TafComment *)pNode );
73 break;
74 }
75
76 return pNode;
77}
78
79Bu::TafGroup *Bu::TafGroup::addChild( TafGroup *pNode )
80{
81 TafGroup *pGroup = (TafGroup *)pNode;
82 if( !hChildren.has( pGroup->getName() ) )
83 hChildren.insert( pGroup->getName(), GroupList() );
84 hChildren.get( pGroup->getName() ).append( pGroup );
85 lChildren.append( pNode );
86 return pNode;
87}
88
89Bu::TafProperty *Bu::TafGroup::addChild( TafProperty *pNode )
90{
91 TafProperty *pProperty = (TafProperty *)pNode;
92 if( !hProp.has( pProperty->getName() ) )
93 hProp.insert( pProperty->getName(), PropList() );
94 hProp.get( pProperty->getName() ).append( pProperty->getValue() );
95 lChildren.append( pNode );
96 return pNode;
97}
98
99Bu::TafComment *Bu::TafGroup::addChild( TafComment *pNode )
100{
101 lChildren.append( pNode );
102 return pNode;
103}
104
105const Bu::TafGroup::GroupList &Bu::TafGroup::getChildren( const Bu::FString &sName ) const
106{
107 return hChildren.get( sName );
108}
109
110const Bu::TafGroup::NodeList &Bu::TafGroup::getChildren() const
111{
112 return lChildren;
113}
114
115const Bu::TafGroup *Bu::TafGroup::getChild( const Bu::FString &sName ) const
116{
117 return hChildren.get( sName ).first();
118}
119
120const Bu::TafGroup::PropList &Bu::TafGroup::getProperties( const Bu::FString &sName ) const
121{
122 return hProp.get( sName );
123}
124
125const Bu::FString &Bu::TafGroup::getProperty( const Bu::FString &sName ) const
126{
127 return hProp.get( sName ).first();
128}
129
130Bu::TafProperty::TafProperty( const Bu::FString &sName, const Bu::FString &sValue ) :
131 TafNode( typeProperty ),
132 sName( sName ),
133 sValue( sValue )
134{
135}
136
137Bu::TafProperty::~TafProperty()
138{
139}
140
141const Bu::FString &Bu::TafProperty::getName() const
142{
143 return sName;
144}
145
146const Bu::FString &Bu::TafProperty::getValue() const
147{
148 return sValue;
149}
150
151Bu::TafComment::TafComment( const Bu::FString &sText ) :
152 TafNode( typeComment ),
153 sText( sText )
154{
155}
156
157Bu::TafComment::~TafComment()
158{
159}
160
161const Bu::FString &Bu::TafComment::getText() const
162{
163 return sText;
164}
165
diff --git a/src/tafnode.h b/src/tafnode.h
new file mode 100644
index 0000000..cb4093f
--- /dev/null
+++ b/src/tafnode.h
@@ -0,0 +1,94 @@
1#ifndef BU_TAF_NODE_H
2#define BU_TAF_NODE_H
3
4#include <stdint.h>
5#include "bu/fstring.h"
6#include "bu/hash.h"
7#include "bu/list.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafNode
15 {
16 public:
17 enum NodeType
18 {
19 typeGroup,
20 typeProperty,
21 typeComment
22 };
23
24 public:
25 TafNode( NodeType eType );
26 virtual ~TafNode();
27
28 const NodeType getType() const;
29
30 private:
31 NodeType eType;
32 };
33
34 class TafProperty;
35 class TafComment;
36 class TafGroup : public TafNode
37 {
38 public:
39 typedef Bu::List<Bu::FString> PropList;
40 typedef Bu::Hash<Bu::FString, PropList> PropHash;
41 typedef Bu::List<class Bu::TafGroup *> GroupList;
42 typedef Bu::Hash<Bu::FString, GroupList> GroupHash;
43 typedef Bu::List<class Bu::TafNode *> NodeList;
44
45 TafGroup( const Bu::FString &sName );
46 virtual ~TafGroup();
47
48 const Bu::FString &getName() const;
49
50 const Bu::FString &getProperty( const Bu::FString &sName ) const;
51 const PropList &getProperties( const Bu::FString &sName ) const;
52 const TafGroup *getChild( const Bu::FString &sName ) const;
53 const GroupList &getChildren( const Bu::FString &sName ) const;
54 TafNode *addChild( TafNode *pNode );
55 TafGroup *addChild( TafGroup *pNode );
56 TafProperty *addChild( TafProperty *pNode );
57 TafComment *addChild( TafComment *pNode );
58 const NodeList &getChildren() const;
59
60 private:
61 Bu::FString sName;
62 PropHash hProp;
63 GroupHash hChildren;
64 NodeList lChildren;
65 };
66
67 class TafProperty : public TafNode
68 {
69 public:
70 TafProperty( const Bu::FString &sName, const Bu::FString &sValue );
71 virtual ~TafProperty();
72
73 const Bu::FString &getName() const;
74 const Bu::FString &getValue() const;
75
76 private:
77 Bu::FString sName;
78 Bu::FString sValue;
79 };
80
81 class TafComment : public TafNode
82 {
83 public:
84 TafComment( const Bu::FString &sText );
85 virtual ~TafComment();
86
87 const Bu::FString &getText() const;
88
89 private:
90 Bu::FString sText;
91 };
92}
93
94#endif
diff --git a/src/tafreader.cpp b/src/tafreader.cpp
new file mode 100644
index 0000000..db465e9
--- /dev/null
+++ b/src/tafreader.cpp
@@ -0,0 +1,155 @@
1#include "bu/tafreader.h"
2#include "bu/exceptions.h"
3#include "bu/fstring.h"
4
5using namespace Bu;
6
7Bu::TafReader::TafReader( Bu::Stream &sIn ) :
8 c( 0 ),
9 sIn( sIn )
10{
11 next(); next();
12}
13
14Bu::TafReader::~TafReader()
15{
16
17}
18
19Bu::TafGroup *Bu::TafReader::readGroup()
20{
21 ws();
22 if( c != '{' )
23 throw TafException("Expected '{'");
24 next();
25 ws();
26 FString sName = readStr();
27 TafGroup *pGroup = new TafGroup( sName );
28 next();
29 //printf("Node[%s]:\n", sName.getStr() );
30
31 groupContent( pGroup );
32
33 if( c != '}' )
34 throw TafException("Expected '}'");
35
36 next();
37
38 return pGroup;
39}
40
41void Bu::TafReader::groupContent( Bu::TafGroup *pGroup )
42{
43 for(;;)
44 {
45 ws();
46 if( c == '{' )
47 pGroup->addChild( readGroup() );
48 else if( c == '}' )
49 return;
50 else if( c == '/' && la == '*' )
51 pGroup->addChild( readComment() );
52 else
53 pGroup->addChild( readProperty() );
54 }
55}
56
57Bu::TafProperty *Bu::TafReader::readProperty()
58{
59 FString sName = readStr();
60 ws();
61 if( c != '=' )
62 {
63 //printf(" %s (true)\n", sName.getStr() );
64 return new Bu::TafProperty( sName, "" );
65 }
66 next();
67 FString sValue = readStr();
68 return new Bu::TafProperty( sName, sValue );
69 //printf(" %s = %s\n", sName.getStr(), sValue.getStr() );
70}
71
72Bu::TafComment *Bu::TafReader::readComment()
73{
74 next();
75 FString sCmnt;
76 for(;;)
77 {
78 next();
79 if( c == '*' && la == '/' )
80 break;
81 sCmnt += c;
82 }
83
84 return new TafComment( sCmnt );
85}
86
87Bu::FString Bu::TafReader::readStr()
88{
89 ws();
90 FString s;
91 if( c == '"' )
92 {
93 next();
94 for(;;)
95 {
96 if( c == '\\' )
97 {
98 next();
99 if( c == 'x' )
100 {
101 char code[3]={'\0','\0','\0'};
102 next();
103 code[0] = c;
104 next();
105 code[1] = c;
106 c = (unsigned char)strtol( code, NULL, 16 );
107 }
108 else if( c == '"' )
109 c = '"';
110 else
111 throw TafException("Invalid escape sequence.");
112 }
113 else if( c == '"' )
114 break;
115 s += c;
116 next();
117 }
118 next();
119 }
120 else
121 {
122 for(;;)
123 {
124 if( isws() || c == '}' || c == '{' || c == ':' || c == '=' )
125 break;
126 s += c;
127 next();
128 }
129 }
130
131 return s;
132}
133
134void Bu::TafReader::ws()
135{
136 for(;;)
137 {
138 if( !isws() )
139 return;
140
141 next();
142 }
143}
144
145bool Bu::TafReader::isws()
146{
147 return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
148}
149
150void Bu::TafReader::next()
151{
152 c = la;
153 sIn.read( &la, 1 );
154}
155
diff --git a/src/tafreader.h b/src/tafreader.h
new file mode 100644
index 0000000..eeaafb3
--- /dev/null
+++ b/src/tafreader.h
@@ -0,0 +1,35 @@
1#ifndef BU_TAF_READER_H
2#define BU_TAF_READER_H
3
4#include <stdint.h>
5#include "bu/tafnode.h"
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafReader
15 {
16 public:
17 TafReader( Bu::Stream &sIn );
18 virtual ~TafReader();
19
20 Bu::TafGroup *readGroup();
21
22 private:
23 void groupContent( Bu::TafGroup *pNode );
24 Bu::TafProperty *readProperty();
25 Bu::TafComment *readComment();
26 void ws();
27 bool isws();
28 void next();
29 Bu::FString readStr();
30 char c, la;
31 Bu::Stream &sIn;
32 };
33}
34
35#endif
diff --git a/src/tafwriter.cpp b/src/tafwriter.cpp
new file mode 100644
index 0000000..6b505ef
--- /dev/null
+++ b/src/tafwriter.cpp
@@ -0,0 +1,70 @@
1#include "tafwriter.h"
2
3Bu::TafWriter::TafWriter( Bu::Stream &sOut ) :
4 sOut( sOut )
5{
6}
7
8Bu::TafWriter::~TafWriter()
9{
10}
11
12void Bu::TafWriter::writeGroup( const Bu::TafGroup *pRoot )
13{
14 sOut.write("{", 1 );
15 writeString( pRoot->getName() );
16 sOut.write(": ", 2 );
17 const Bu::TafGroup::NodeList &nl = pRoot->getChildren();
18 for( Bu::TafGroup::NodeList::const_iterator i = nl.begin(); i != nl.end(); i++ )
19 {
20 switch( (*i)->getType() )
21 {
22 case Bu::TafNode::typeGroup:
23 writeGroup( (Bu::TafGroup *)(*i) );
24 break;
25
26 case Bu::TafNode::typeProperty:
27 writeProperty( (Bu::TafProperty *)(*i) );
28 break;
29
30 case Bu::TafNode::typeComment:
31 writeComment( (Bu::TafComment *)(*i) );
32 break;
33 }
34 }
35 sOut.write("}", 1 );
36}
37
38void Bu::TafWriter::writeProperty( const Bu::TafProperty *pProp )
39{
40 writeString( pProp->getName() );
41 if( pProp->getValue().getStr() != NULL )
42 {
43 sOut.write("=", 1 );
44 writeString( pProp->getValue() );
45 }
46 sOut.write(" ", 1 );
47}
48
49void Bu::TafWriter::writeComment( const Bu::TafComment *pComment )
50{
51 sOut.write("/*", 2 );
52 sOut.write( pComment->getText().getStr(), pComment->getText().getSize() );
53 sOut.write("*/ ", 3 );
54}
55
56void Bu::TafWriter::writeString( const Bu::FString &str )
57{
58 if( str.getStr() == NULL )
59 return;
60 sOut.write("\"", 1 );
61 for( const char *s = str.getStr(); *s; s++ )
62 {
63 if( *s == '\"' )
64 sOut.write("\\\"", 2 );
65 else
66 sOut.write( s, 1 );
67 }
68 sOut.write("\"", 1 );
69}
70
diff --git a/src/tafwriter.h b/src/tafwriter.h
new file mode 100644
index 0000000..5f80504
--- /dev/null
+++ b/src/tafwriter.h
@@ -0,0 +1,30 @@
1#ifndef BU_TAF_WRITER_H
2#define BU_TAF_WRITER_H
3
4#include <stdint.h>
5#include "bu/tafnode.h"
6#include "bu/stream.h"
7#include "bu/fstring.h"
8
9namespace Bu
10{
11 /**
12 *
13 */
14 class TafWriter
15 {
16 public:
17 TafWriter( Bu::Stream &sOut );
18 virtual ~TafWriter();
19
20 void writeGroup( const Bu::TafGroup *pRoot );
21
22 private:
23 void writeProperty( const Bu::TafProperty *pProp );
24 void writeComment( const Bu::TafComment *pComment );
25 void writeString( const Bu::FString &str );
26 Bu::Stream &sOut;
27 };
28}
29
30#endif
diff --git a/src/tests/archive.cpp b/src/tests/archive.cpp
new file mode 100644
index 0000000..2035aa6
--- /dev/null
+++ b/src/tests/archive.cpp
@@ -0,0 +1,16 @@
1#include "archive.h"
2#include "file.h"
3
4using namespace Bu;
5
6int main()
7{
8 File f("test.dat", "wb");
9 Archive ar( f, Archive::save );
10
11 std::string s("Hello there");
12 ar << s;
13
14 return 0;
15}
16
diff --git a/src/tests/atom.cpp b/src/tests/atom.cpp
new file mode 100644
index 0000000..2077bfd
--- /dev/null
+++ b/src/tests/atom.cpp
@@ -0,0 +1,25 @@
1#include "bu/atom.h"
2#include <stdio.h>
3#include <stdlib.h>
4
5typedef struct bob
6{
7 int a, b;
8} bob;
9int main()
10{
11 Bu::Atom<int> aInt;
12 Bu::Atom<char *> aStr;
13 Bu::Atom<bob> aBob;
14
15 aBob = bob();
16 aBob->a = 5;
17
18 aStr.set("Hey there, dude");
19 aInt.set( 55 );
20 int me = aInt;
21 aInt = 12;
22 printf("%d, %d\n", aInt.get(), me );
23 printf("%s\n", aStr.get() );
24}
25
diff --git a/src/tests/bzip2.cpp b/src/tests/bzip2.cpp
new file mode 100644
index 0000000..683d3d7
--- /dev/null
+++ b/src/tests/bzip2.cpp
@@ -0,0 +1,23 @@
1#include "bu/bzip2.h"
2#include "bu/file.h"
3
4int main( int argc, char *argv[] )
5{
6 char buf[1024];
7 size_t nRead;
8
9 Bu::File f( "test.bz2", "wb" );
10 Bu::BZip2 bz2( f );
11
12 Bu::File fin( argv[1], "rb");
13
14 for(;;)
15 {
16 nRead = fin.read( buf, 1024 );
17 if( nRead > 0 )
18 bz2.write( buf, nRead );
19 if( fin.isEOS() )
20 break;
21 }
22}
23
diff --git a/src/tests/constsptr.cpp b/src/tests/constsptr.cpp
deleted file mode 100644
index e6f87c7..0000000
--- a/src/tests/constsptr.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
1#include <stdio.h>
2#include "sptr.h"
3
4template <typename T>
5class DataBase
6{
7public:
8 DataBase():
9 _bHas(false)
10 {
11 }
12
13 virtual ~DataBase()
14 {
15 clr();
16 }
17
18 virtual bool has() const
19 {
20 return _bHas;
21 }
22
23 virtual void clr()
24 {
25 _bHas = false;
26 }
27
28 virtual void set(T d)
29 {
30 _tVal = d;
31 _bHas = true;
32 }
33
34 virtual T const &get() const
35 {
36 if(!has())
37 throw "no data";
38 return _tVal;
39 }
40
41 virtual T &get()
42 {
43 if(!has())
44 throw "no data";
45 return _tVal;
46 }
47
48protected:
49 bool _bHas;
50 T _tVal;
51};
52
53
54class Test
55{
56public:
57 Test(){};
58 virtual ~Test(){};
59
60 void set(int i)
61 {
62 _i = i;
63 }
64
65 int get() const
66 {
67 return _i;
68 }
69
70private:
71 int _i;
72};
73
74int main()
75{
76 typedef SPtr<Test> TestPtr;
77
78 TestPtr t1(new Test);
79 t1->set(42);
80
81 printf("t1: %d.\n", t1->get());
82
83 const TestPtr t2 = t1;
84
85 printf("t2: %d.\n", t2->get());
86
87 typedef DataBase<const TestPtr> DBTP;
88
89 DBTP db;
90 db.set(t1);
91
92 printf("dbt1: %d.\n", db.get()->get());
93}
94
diff --git a/src/tests/constsptr2.cpp b/src/tests/constsptr2.cpp
deleted file mode 100644
index 8ccb20c..0000000
--- a/src/tests/constsptr2.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
1#include "sptr.h"
2
3void nonsptr()
4{
5 int a = 5;
6 int b = 10;
7 const int *p = &a;
8 p = &b;
9 printf("p = %d\n", (*p) );
10 //(*p)++;
11}
12
13void sptr()
14{
15 int a = 5;
16 int b = 10;
17 const SPtr<int> p = new int(a);
18 p = new int(b);
19 printf("p = %d\n", (*p) );
20 //(*p)++;
21}
22
23int main()
24{
25 printf("Non-sptr:\n");
26 nonsptr();
27 printf("sptr:\n");
28 sptr();
29}
30
diff --git a/src/tests/fstring.cpp b/src/tests/fstring.cpp
index 271738c..48dfc5f 100644
--- a/src/tests/fstring.cpp
+++ b/src/tests/fstring.cpp
@@ -1,9 +1,28 @@
1#include "hash.h" 1#include "bu/hash.h"
2#include "fstring.h" 2#include "bu/fstring.h"
3#include <sys/time.h>
4#include <string>
3 5
4FString genThing() 6#ifndef WIN32
7inline double getTime()
5{ 8{
6 FString bob; 9 struct timeval tv;
10 gettimeofday( &tv, NULL );
11 return ((double)tv.tv_sec) + ((double)tv.tv_usec/1000000.0);
12}
13#else
14#include "windows.h"
15#include "winbase.h"
16inline double getTime()
17{
18 uint32_t t = (uint32_t) GetTickCount();
19 return (double) t / 1000.0;
20}
21#endif
22
23Bu::FString genThing()
24{
25 Bu::FString bob;
7 bob.append("ab "); 26 bob.append("ab ");
8 bob += "cd "; 27 bob += "cd ";
9 bob += "efg"; 28 bob += "efg";
@@ -12,20 +31,91 @@ FString genThing()
12 return bob; 31 return bob;
13} 32}
14 33
15void thing( FString str ) 34void thing( Bu::FString str )
16{ 35{
17 printf("Hey: %s\n", str.c_str() ); 36 printf("Hey: %s\n", str.c_str() );
18} 37}
19 38
39void copyfunc( std::string temp )
40{
41 temp += "Hi";
42}
43
44void copyfunc( Bu::FString temp )
45{
46 temp += "Hi";
47}
48
49void doTimings()
50{
51 Bu::FString fs1, fs2;
52 std::string ss1, ss2;
53 double dStart, dEnd, tfs1, tfs2, tfs3, tss1, tss2, tss3;
54 int nChars = 500000, nChunks=5000, nCopies=5000000, nChunkSize=1024*4;
55 char *buf = new char[nChunkSize];
56 memset( buf, '!', nChunkSize );
57
58 printf("Timing Bu::FString single chars...\n");
59 dStart = getTime();
60 for( int j = 0; j < nChars; j++ ) fs1 += (char)('a'+(j%26));
61 fs1.getStr();
62 dEnd = getTime();
63 tfs1 = dEnd-dStart;
64
65 printf("Timing std::string single chars...\n");
66 dStart = getTime();
67 for( int j = 0; j < nChars; j++ ) ss1 += (char)('a'+(j%26));
68 ss1.c_str();
69 dEnd = getTime();
70 tss1 = dEnd-dStart;
71
72 printf("Timing Bu::FString %d char chunks...\n", nChunkSize);
73 dStart = getTime();
74 for( int j = 0; j < nChunks; j++ ) fs2.append(buf, nChunkSize);
75 fs2.getStr();
76 dEnd = getTime();
77 tfs2 = dEnd-dStart;
78
79 printf("Timing std::string %d char chunks...\n", nChunkSize);
80 dStart = getTime();
81 for( int j = 0; j < nChunks; j++ ) ss2.append(buf, nChunkSize);
82 ss2.c_str();
83 dEnd = getTime();
84 tss2 = dEnd-dStart;
85
86 fs2 = "Hello there.";
87 ss2 = "Hello there.";
88 printf("Timing Bu::FString copies...\n");
89 dStart = getTime();
90 for( int j = 0; j < nCopies; j++ ) Bu::FString stmp = fs2;
91 dEnd = getTime();
92 tfs3 = dEnd-dStart;
93
94 printf("Timing std::string copies...\n");
95 dStart = getTime();
96 for( int j = 0; j < nCopies; j++ ) std::string stpm = ss2;
97 dEnd = getTime();
98 tss3 = dEnd-dStart;
99
100 printf(
101 "Results: singles: chunks: copies:\n"
102 "Bu::FString %10.2f/s %10.2f/s %10.2f/s\n"
103 "std::string %10.2f/s %10.2f/s %10.2f/s\n",
104 nChars/tfs1, nChunks/tfs2, nCopies/tfs3,
105 nChars/tss1, nChunks/tss2, nCopies/tss3 );
106
107 delete[] buf;
108}
109
20#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() ); 110#define pem printf("---------\n%08X: %s\n%08X: %s\n", (unsigned int)str.c_str(), str.c_str(), (unsigned int)str2.c_str(), str2.c_str() );
21int main( int argc, char *argv ) 111int main( int argc, char *argv )
22{ 112{
23 FString str("th"); 113 Bu::FString str("th");
24 114
25 str.prepend("Hello "); 115 str.prepend("Hello ");
26 str.append("ere."); 116 str.append("ere.");
27 117
28 FString str2( str ); 118 Bu::FString str2( str );
29 pem; 119 pem;
30 str += " What's up?"; 120 str += " What's up?";
31 pem; 121 pem;
@@ -43,6 +133,8 @@ int main( int argc, char *argv )
43 thing( str2 ); 133 thing( str2 );
44 thing("test."); 134 thing("test.");
45 135
46 printf("%d == %d\n", __calcHashCode( str ), __calcHashCode( str.c_str() ) ); 136 printf("%d == %d\n", Bu::__calcHashCode( str ), Bu::__calcHashCode( str.c_str() ) );
137
138 doTimings();
47} 139}
48 140
diff --git a/src/tests/hash.cpp b/src/tests/hash.cpp
index 2fc6968..73cfb27 100644
--- a/src/tests/hash.cpp
+++ b/src/tests/hash.cpp
@@ -1,116 +1,24 @@
1#include "hash.h" 1#include "bu/hash.h"
2#include "staticstring.h" 2#include "bu/sptr.h"
3 3
4int main() 4typedef struct Bob
5{ 5{
6 const char *names[]={ 6 int nID;
7 "Homer the Great", 7} Bob;
8 "And Maggie Makes Three",
9 "Bart's Comet",
10 "Homie The Clown",
11 "Bart Vs Australia",
12 "Homer vs Patty and Selma",
13 "A star is burns",
14 "Lisa's Wedding",
15 "Two Dozen and One Greyhounds",
16 "The PTA Disbands",
17 "Round Springfield",
18 "The Springfield connection",
19 "Lemon of Troy",
20 "Who Shot Mr. Burns (Pt. 1)",
21 "Who Shot Mr. Burns (pt. 2)",
22 "Radioactive Man",
23 "Home Sweet Homediddly-dum-doodly",
24 "Bart Sells His Soul",
25 "Lisa the Vegetarian",
26 "Treehouse of horror VI",
27 "King Size Homer",
28 "Mother Simpson",
29 "Sideshow Bob's Last Gleaming",
30 "The Simpson's 138th Show Spectacular",
31 "Marge Be Not Proud",
32 "Team Homer",
33 "Two Bad Neighbors",
34 "Scenes From the Class Struggle in Springfield",
35 "Bart the Fink",
36 "Lisa the Iconoclast",
37 "Homer the Smithers",
38 "The Day the Violence Died",
39 "A Fish Called Selma",
40 "Bart on the road",
41 "22 Short Films about Springfield",
42 "The Curse of the Flying Hellfish",
43 "Much Apu about Nothing",
44 "Homerpalooza",
45 "The Summer of 4 Ft 2",
46 "Treehouse of Horror VII",
47 "You Only Move Twice",
48 "The Homer They Fall",
49 "Burns Baby Burns",
50 "Bart After Dark",
51 "A Millhouse Divided",
52 "Lisas Date With Destiny",
53 "Hurricane Neddy",
54 "The Mysterious Voyage of Our Homer",
55 "The Springfield Files",
56 "The Twisted World of Marge Simpson",
57 "Mountain of Madness",
58 NULL
59 };
60
61 Hash<const char *, int> sTest;
62
63 printf("Inserting\n-------------------\n\n");
64 for( int j = 0; j < 33; j++ )
65 {
66 sTest[names[j]] = j;
67 }
68
69 printf("Test1: %d, Test2: %d\n", sTest.has("Lemon of Troy"), sTest.has(std::string("Lemon of Troy").c_str() ) );
70
71 sTest.has(std::string("Lemon of Troy").c_str() );
72
73 printf("Getting\n-------------------\n\n");
74
75 sTest.erase("Homer the Great");
76 sTest["Bart's Comet"].erase();
77 8
78 for( Hash<const char *, int>::iterator i = sTest.begin(); 9int main()
79 i != sTest.end(); i++ ) 10{
80 { 11 Bu::Hash<int, Bu::SPtr<const Bob> > lb;
81 Hash<const char *, int>::iterator j = i; 12 for( int j = 0; j < 10; j++ )
82 printf("%d: %s\n", (*j).second, (*j).first );
83 }
84
85 printf("Testing\n-------------------\n\n");
86 for( int j = 0; j < 33; j++ )
87 { 13 {
88 if( sTest.has(names[j]) ) 14 Bob *b = new Bob;
89 { 15 b->nID = j;
90 if( sTest[names[j]] != j ) 16 lb.insert( j, b );
91 {
92 printf("'%s' should be %d, is %d\n",
93 names[j], j,
94 sTest[names[j]].value()
95 );
96 }
97 }
98 else
99 {
100 printf("Missing element %d, '%s'\n", j, names[j] );
101 }
102 } 17 }
103 18
104 printf("Clearing\n-------------------\n\n"); 19 for( int j = 0; j < 10; j++ )
105
106 sTest.clear();
107
108 for( Hash<const char *, int>::iterator i = sTest.begin();
109 i != sTest.end(); i++ )
110 { 20 {
111 Hash<const char *, int>::iterator j = i; 21 printf("%d\n", lb[j].value()->nID );
112 printf("%d: %s\n", (*j).second, (*j).first );
113 } 22 }
114
115} 23}
116 24
diff --git a/src/tests/itoqueue1.cpp b/src/tests/itoqueue1.cpp
new file mode 100644
index 0000000..f73f4d3
--- /dev/null
+++ b/src/tests/itoqueue1.cpp
@@ -0,0 +1,110 @@
1#include <string>
2#include "bu/ito.h"
3#include "bu/itoqueue.h"
4
5class Reader : public Bu::Ito
6{
7public:
8 Reader( Bu::ItoQueue<std::string *> &q, int id ) :
9 q( q ),
10 id( id )
11 {
12 }
13
14 void *run()
15 {
16 for( int i = 0; i < 10; i++ )
17 {
18 std::string *pStr = q.dequeue( true );
19 if( pStr == NULL )
20 {
21 printf("Null received...\n");
22 }
23 else
24 {
25 printf("[%d] read: %s\n", id, pStr->c_str() );
26 delete pStr;
27 }
28 usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) );
29 }
30
31 return NULL;
32 }
33
34private:
35 Bu::ItoQueue<std::string *> &q;
36 int id;
37};
38
39class Writer : public Bu::Ito
40{
41public:
42 Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) :
43 q( q ),
44 strbase( strbase ),
45 id( id )
46 {
47 }
48
49 void *run()
50 {
51 for( int i = 0; i < 11; i++ )
52 {
53 usleep( (int)(((double)rand())/((double)RAND_MAX)*2000000.0) );
54 q.enqueue( new std::string( strbase ) );
55 printf("[%d] write: %s\n", id, strbase );
56 }
57
58 return NULL;
59 }
60
61private:
62 Bu::ItoQueue<std::string *> &q;
63 const char *strbase;
64 int id;
65};
66
67int main()
68{
69 Writer *wr[5];
70 Reader *rd[5];
71 const char bob[][7]={
72 {"Test 1"},
73 {"Test 2"},
74 {"Test 3"},
75 {"Test 4"},
76 {"Test 5"}
77 };
78
79 Bu::ItoQueue<std::string *> q;
80
81 for( int j = 0; j < 5; j++ )
82 {
83 wr[j] = new Writer( q, j, bob[j] );
84 rd[j] = new Reader( q, j );
85 }
86
87 for( int j = 0; j < 5; j++ )
88 {
89 rd[j]->start();
90 }
91
92 for( int j = 0; j < 5; j++ )
93 {
94 wr[j]->start();
95 }
96
97 for( int j = 0; j < 5; j++ )
98 {
99 rd[j]->join();
100 }
101
102 for( int j = 0; j < 5; j++ )
103 {
104 delete wr[j];
105 delete rd[j];
106 }
107
108 return 0;
109}
110
diff --git a/src/tests/itoqueue2.cpp b/src/tests/itoqueue2.cpp
new file mode 100644
index 0000000..f4b5e19
--- /dev/null
+++ b/src/tests/itoqueue2.cpp
@@ -0,0 +1,83 @@
1#include <string>
2#include "bu/ito.h"
3#include "bu/itoqueue.h"
4#include <errno.h>
5
6class Reader : public Bu::Ito
7{
8public:
9 Reader( Bu::ItoQueue<std::string *> &q, int id ) :
10 q( q ),
11 id( id )
12 {
13 }
14
15 void *run()
16 {
17 for( int i = 0; i < 10; i++ )
18 {
19 std::string *pStr = q.dequeue( 0, 500000 );
20 if( pStr == NULL )
21 {
22 printf("Null received...\n");
23 i--;
24 }
25 else
26 {
27 printf("[%d] read: %s\n", id, pStr->c_str() );
28 delete pStr;
29 }
30 }
31
32 return NULL;
33 }
34
35private:
36 Bu::ItoQueue<std::string *> &q;
37 int id;
38};
39
40class Writer : public Bu::Ito
41{
42public:
43 Writer( Bu::ItoQueue<std::string *> &q, int id, const char *strbase ) :
44 q( q ),
45 strbase( strbase ),
46 id( id )
47 {
48 }
49
50 void *run()
51 {
52 for( int i = 0; i < 11; i++ )
53 {
54 sleep( 2 );
55 printf("[%d] write: %s\n", id, strbase );
56 q.enqueue( new std::string( strbase ) );
57 }
58
59 return NULL;
60 }
61
62private:
63 Bu::ItoQueue<std::string *> &q;
64 const char *strbase;
65 int id;
66};
67
68int main()
69{
70 printf("ETIMEDOUT: %d\n", ETIMEDOUT );
71 Bu::ItoQueue<std::string *> q;
72 Writer wr( q, 0, "writer" );
73 Reader rd( q, 0 );
74
75 rd.start();
76 wr.start();
77
78 rd.join();
79 wr.join();
80
81 return 0;
82}
83
diff --git a/src/tests/list.cpp b/src/tests/list.cpp
new file mode 100644
index 0000000..12807a5
--- /dev/null
+++ b/src/tests/list.cpp
@@ -0,0 +1,53 @@
1#include "bu/list.h"
2#include <list>
3
4typedef struct Bob
5{
6 int nID;
7} Bob;
8
9int main()
10{
11 Bu::List<int> l;
12
13 l.append( 0 );
14
15 for( int j = 3; j <= 21; j += 3 )
16 {
17 l.append( j );
18 l.prepend( -j );
19 }
20
21 for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ )
22 {
23 printf("%d ", *i );
24 }
25 printf("\n");
26 for( Bu::List<int>::iterator i = l.begin(); i != l.end(); i++ )
27 {
28 l.erase( i );
29 if( i != l.end() )
30 printf("%d ", *i );
31 }
32
33 printf("\n\n");
34
35 Bu::List<Bob> lb;
36 for( int j = 0; j < 10; j++ )
37 {
38 Bob b;
39 b.nID = j;
40 lb.append( b );
41 }
42
43 const Bu::List<Bob> rb = lb;
44
45 for( Bu::List<Bob>::const_iterator i = rb.begin(); i != rb.end(); i++ )
46 {
47 //i->nID += 2;
48 //(*i).nID = 4;
49 printf("%d ", i->nID );
50 }
51 printf("\n\n");
52}
53
diff --git a/src/tests/logger.cpp b/src/tests/logger.cpp
new file mode 100644
index 0000000..290f479
--- /dev/null
+++ b/src/tests/logger.cpp
@@ -0,0 +1,28 @@
1#include "bu/logger.h"
2#include <errno.h>
3#include <stdlib.h>
4
5class Thing
6{
7 public:
8 Thing()
9 {
10 lineLog( 2, "Want a thing?");
11 }
12
13 void go( int i )
14 {
15 lineLog( 1, "GO!!!!");
16 }
17};
18
19int main()
20{
21 setLogLevel( 4 );
22 setLogFormat("%L: %y-%02m-%02d %h:%02M:%02s %f:%l:%F: %t");
23 lineLog( 5, "Hey, error: %s", strerror( errno ) );
24
25 Thing gh;
26 gh.go( 6);
27}
28
diff --git a/src/tests/ringbuffer.cpp b/src/tests/ringbuffer.cpp
new file mode 100644
index 0000000..259ec1f
--- /dev/null
+++ b/src/tests/ringbuffer.cpp
@@ -0,0 +1,29 @@
1#include "bu/ringbuffer.h"
2#include <stdlib.h>
3
4int main()
5{
6 Bu::RingBuffer<uint32_t> ibuf( 10 );
7
8 for( int k = 0; k < 2; k++ )
9 {
10 int j = 1;
11 for(; j < 7; j++ )
12 {
13 ibuf.enqueue( j );
14 }
15
16 for(; j < 20; j++ )
17 {
18 ibuf.enqueue( j );
19 printf("- %d\n", ibuf.dequeue() );
20 }
21
22 for(;;)
23 {
24 if( ibuf.isEmpty() ) break;
25 printf(". %d\n", ibuf.dequeue() );
26 }
27 }
28}
29
diff --git a/src/tests/taf.cpp b/src/tests/taf.cpp
new file mode 100644
index 0000000..e3da120
--- /dev/null
+++ b/src/tests/taf.cpp
@@ -0,0 +1,24 @@
1#include "bu/tafreader.h"
2#include "bu/tafwriter.h"
3#include "bu/file.h"
4
5int main()
6{
7 Bu::File f("test.taf", "rb");
8 Bu::TafReader tr( f );
9
10 Bu::TafGroup *pGroup = tr.readGroup();
11
12 const Bu::TafGroup *pStats = pGroup->getChild("stats");
13 printf("%s\n", pStats->getName().getStr() );
14 printf(" str = %s\n", pStats->getProperty("str").getStr() );
15
16 {
17 Bu::File fo("out.taf", "wb");
18 Bu::TafWriter tw( fo );
19 tw.writeGroup( pGroup );
20 }
21
22 delete pGroup;
23}
24
diff --git a/src/unit/entities/unit b/src/unit/entities/unit
new file mode 100644
index 0000000..28db45f
--- /dev/null
+++ b/src/unit/entities/unit
@@ -0,0 +1,30 @@
1<?xml version="1.1" ?>
2<entity desc="Unit test framework">
3 <param name="name" required="yes" desc="Name of the class"/>
4 <file
5 name="source"
6 filename="{=name:%tolower}.cpp"
7>#include "bu/unitsuite.h"
8
9class Unit : public Bu::UnitSuite
10{
11public:
12 Unit()
13 {
14 setName("{=name}");
15 addTest( Unit::test01 );
16 }
17
18 virtual ~Unit()
19 {
20 }
21
22 void test01()
23 {
24 unitTest( 0 == 5 );
25 }
26};
27
28int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
29</file>
30</entity>
diff --git a/src/unit/file.cpp b/src/unit/file.cpp
new file mode 100644
index 0000000..1eaaf36
--- /dev/null
+++ b/src/unit/file.cpp
@@ -0,0 +1,111 @@
1#include "unitsuite.h"
2#include "file.h"
3#include "exceptions.h"
4
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8
9class Unit : public Bu::UnitSuite
10{
11public:
12 Unit()
13 {
14 setName("File");
15 addTest( Unit::writeFull );
16 addTest( Unit::readBlocks );
17 addTest( Unit::readError1 );
18 addTest( Unit::readError2 );
19 }
20
21 virtual ~Unit() { }
22
23 //
24 // Tests go here
25 //
26 void writeFull()
27 {
28 Bu::File sf("testfile1", "wb");
29 for( int c = 0; c < 256; c++ )
30 {
31 unsigned char ch = (unsigned char)c;
32 sf.write( &ch, 1 );
33 unitTest( sf.tell() == c+1 );
34 }
35 //unitTest( sf.canRead() == false );
36 //unitTest( sf.canWrite() == true );
37 //unitTest( sf.canSeek() == true );
38 sf.close();
39 struct stat sdat;
40 stat("testfile1", &sdat );
41 unitTest( sdat.st_size == 256 );
42 }
43
44 void readBlocks()
45 {
46 Bu::File sf("testfile1", "rb");
47 unsigned char buf[50];
48 size_t total = 0;
49 for(;;)
50 {
51 size_t s = sf.read( buf, 50 );
52 for( size_t c = 0; c < s; c++ )
53 {
54 unitTest( buf[c] == (unsigned char)(c+total) );
55 }
56 total += s;
57 if( s < 50 )
58 {
59 unitTest( total == 256 );
60 unitTest( sf.isEOS() == true );
61 break;
62 }
63 }
64 sf.close();
65 }
66
67 void readError1()
68 {
69 try
70 {
71 Bu::File sf("doesn'texist", "rb");
72 unitFailed("No exception thrown");
73 }
74 catch( Bu::FileException &e )
75 {
76 return;
77 }
78 }
79
80 void readError2()
81 {
82 Bu::File sf("testfile1", "rb");
83 char buf[256];
84 int r = sf.read( buf, 256 );
85 unitTest( r == 256 );
86 // You have to read past the end to set the EOS flag.
87 unitTest( sf.isEOS() == false );
88 try
89 {
90 if( sf.read( buf, 5 ) > 0 )
91 {
92 unitFailed("Non-zero read result");
93 }
94 else
95 {
96 sf.close();
97 }
98 }
99 catch( Bu::FileException &e )
100 {
101 sf.close();
102 return;
103 }
104 }
105};
106
107int main( int argc, char *argv[] )
108{
109 return Unit().run( argc, argv );
110}
111
diff --git a/src/unit/fstring.cpp b/src/unit/fstring.cpp
new file mode 100644
index 0000000..72755eb
--- /dev/null
+++ b/src/unit/fstring.cpp
@@ -0,0 +1,28 @@
1#include "fstring.h"
2#include "unitsuite.h"
3
4class Unit : public Bu::UnitSuite
5{
6public:
7 Unit()
8 {
9 setName("FString");
10 addTest( Unit::test1 );
11 }
12
13 virtual ~Unit()
14 {
15 }
16
17 void test1()
18 {
19 unitTest( 1 == 1 );
20 unitTest( 1 == 0 );
21 }
22};
23
24int main( int argc, char *argv[] )
25{
26 return Unit().run( argc, argv );
27}
28
diff --git a/src/unit/hash.cpp b/src/unit/hash.cpp
new file mode 100644
index 0000000..9ea933f
--- /dev/null
+++ b/src/unit/hash.cpp
@@ -0,0 +1,40 @@
1#include "bu/fstring.h"
2#include "bu/hash.h"
3#include "bu/unitsuite.h"
4
5#include <stdio.h>
6
7class Unit : public Bu::UnitSuite
8{
9private:
10 typedef Bu::Hash<Bu::FString, int> StrIntHash;
11public:
12 Unit()
13 {
14 setName("Hash");
15 addTest( Unit::test_probe );
16 }
17
18 virtual ~Unit()
19 {
20 }
21
22 void test_probe()
23 {
24 StrIntHash h;
25 char buf[20];
26 for(int i=1;i<10000;i++)
27 {
28 sprintf(buf,"%d",i);
29 Bu::FString sTmp(buf);
30 h[sTmp] = i;
31 unitTest( h.has(sTmp) );
32 }
33 }
34};
35
36int main( int argc, char *argv[] )
37{
38 return Unit().run( argc, argv );
39}
40
diff --git a/src/unit/membuf.cpp b/src/unit/membuf.cpp
new file mode 100644
index 0000000..65ba82a
--- /dev/null
+++ b/src/unit/membuf.cpp
@@ -0,0 +1,37 @@
1#include "bu/unitsuite.h"
2#include "bu/membuf.h"
3
4class Unit : public Bu::UnitSuite
5{
6public:
7 Unit()
8 {
9 setName("MemBuf");
10 addTest( Unit::testWriteRead01 );
11 }
12
13 virtual ~Unit()
14 {
15 }
16
17 void testWriteRead01()
18 {
19 Bu::MemBuf mb;
20 unitTest( mb.write("ab", 2 ) == 2 );
21 unitTest( mb.write("cde", 3 ) == 3 );
22 unitTest( mb.write("FG", 2 ) == 2 );
23
24 mb.setPos( 0 );
25
26 char buf[8];
27 buf[7] = '\0';
28 unitTest( mb.read( buf, 7 ) == 7 );
29 unitTest( !strncmp( buf, "abcdeFG", 7 ) );
30 unitTest( mb.read( buf, 7 ) == 0 );
31 mb.seek( -3 );
32 unitTest( mb.read( buf, 7 ) == 3 );
33 unitTest( !strncmp( buf, "eFG", 3 ) );
34 }
35};
36
37int main( int argc, char *argv[] ){ return Unit().run( argc, argv ); }
diff --git a/src/unit/taf.cpp b/src/unit/taf.cpp
new file mode 100644
index 0000000..5e0e914
--- /dev/null
+++ b/src/unit/taf.cpp
@@ -0,0 +1,48 @@
1#include "unitsuite.h"
2#include "file.h"
3#include "tafreader.h"
4
5#include <string.h>
6#include <unistd.h>
7
8class Unit : public Bu::UnitSuite
9{
10public:
11 Unit()
12 {
13 setName("taf");
14 addTest( Unit::read1 );
15 }
16
17 virtual ~Unit()
18 {
19 }
20
21 void read1()
22 {
23#define FN_TMP ("/tmp/tmpXXXXXXXX")
24 Bu::FString sFnTmp(FN_TMP);
25 Bu::File fOut = Bu::File::tempFile( sFnTmp, "wb" );
26 const char *data =
27"{test: name=\"Bob\"}"
28;
29 fOut.write(data,strlen(data));
30 fOut.close();
31
32 Bu::File fIn(sFnTmp.c_str(), "rb");
33 Bu::TafReader tr(fIn);
34
35 Bu::TafGroup *tn = tr.readGroup();
36 unitTest( !strcmp("Bob", tn->getProperty("name").c_str()) );
37 delete tn;
38
39 unlink(sFnTmp.c_str());
40#undef FN_TMP
41 }
42};
43
44int main( int argc, char *argv[] )
45{
46 return Unit().run( argc, argv );
47}
48
diff --git a/src/unitsuite.cpp b/src/unitsuite.cpp
new file mode 100644
index 0000000..2a28eb5
--- /dev/null
+++ b/src/unitsuite.cpp
@@ -0,0 +1,67 @@
1#include "unitsuite.h"
2
3Bu::UnitSuite::UnitSuite()
4{
5}
6
7Bu::UnitSuite::~UnitSuite()
8{
9}
10
11int Bu::UnitSuite::run( int argc, char *argv[] )
12{
13 for( TestList::iterator i = lTests.begin(); i != lTests.end(); i++ )
14 {
15 printf("%s: ", i->sName.getStr() );
16 fflush( stdout );
17 try
18 {
19 (this->*(i->fTest))();
20 printf("passed.\n");
21 }
22 catch( Failed &e )
23 {
24 if( e.bFile )
25 {
26 printf("unitTest(%s) failed. (%s:%d)\n",
27 e.str.getStr(),
28 e.sFile.getStr(),
29 e.nLine
30 );
31 }
32 else
33 {
34 printf("unitTest(%s) failed.\n",
35 e.str.getStr()
36 );
37 }
38 }
39 catch( ... )
40 {
41 printf("failed with external exception.\n");
42 }
43 }
44
45 return 0;
46}
47
48void Bu::UnitSuite::add( Test fTest, Bu::FString sName )
49{
50 TestInfo ti;
51 ti.sName = sName;
52 long index = ti.sName.rfind("::");
53 if( index != -1 )
54 {
55 FString tmp = sSuiteName;
56 tmp += ti.sName.getStr()+index;
57 ti.sName = tmp;
58 }
59 ti.fTest = fTest;
60 lTests.push_back( ti );
61}
62
63void Bu::UnitSuite::setName( const FString &sName )
64{
65 sSuiteName = sName;
66}
67
diff --git a/src/unitsuite.h b/src/unitsuite.h
new file mode 100644
index 0000000..578b4cc
--- /dev/null
+++ b/src/unitsuite.h
@@ -0,0 +1,96 @@
1#ifndef BU_UNIT_SUITE_H
2#define BU_UNIT_SUITE_H
3
4#include <stdint.h>
5#include <list>
6#include "fstring.h"
7
8namespace Bu
9{
10 /**
11 * Provides a unit testing framework. This is pretty easy to use, probably
12 * the best way to get started is to use ch to generate a template, or use
13 * the code below with appropriate tweaks:
14 *@code
15 * #include "unitsuite.h"
16 *
17 * class Unit : public Bu::UnitSuite
18 * {
19 * public:
20 * Unit()
21 * {
22 * setName("Example");
23 * addTest( Unit::test );
24 * }
25 *
26 * virtual ~Unit() { }
27 *
28 * //
29 * // Tests go here
30 * //
31 * void test()
32 * {
33 * unitTest( 1 == 1 );
34 * }
35 * };
36 *
37 * int main( int argc, char *argv[] )
38 * {
39 * return Unit().run( argc, argv );
40 * }
41 *
42 @endcode
43 * The main function can contain other things, but using this one exactly
44 * makes all of the test suites work exactly the same. Using the optional
45 * setName at the top of the constructor replaces the class name with the
46 * chosen name when printing out stats and info.
47 */
48 class UnitSuite
49 {
50 public:
51 UnitSuite();
52 virtual ~UnitSuite();
53
54 int run( int argc=0, char *argv[]=NULL );
55
56 typedef void (UnitSuite::*Test)();
57
58 class Failed
59 {
60 public:
61 Failed() : str(""), bFile( false ) { }
62 Failed( const FString &s ) : str( s ), bFile( false ) { }
63 Failed( const FString &s, const FString &sFile, int nLine ) :
64 str( s ), sFile( sFile ), nLine( nLine ), bFile( true ) { }
65
66 FString str;
67 FString sFile;
68 int nLine;
69 bool bFile;
70 };
71
72 protected:
73 void add( Test fTest, Bu::FString sName );
74 void setName( const FString &sName );
75
76 private:
77 typedef struct TestInfo
78 {
79 FString sName;
80 Test fTest;
81 } TestInfo;
82
83 typedef std::list<TestInfo> TestList;
84 TestList lTests;
85 FString sSuiteName;
86 };
87}
88
89#define addTest( fn ) add( static_cast<Bu::UnitSuite::Test>(&fn), #fn )
90#define unitTest( tst ) if( !(tst) ) \
91{ \
92 throw Bu::UnitSuite::Failed( #tst, __FILE__, __LINE__ ); \
93}
94#define unitFailed( msg ) throw Bu::UnitSuite::Failed(msg, __FILE__, __LINE__);
95
96#endif