00001
00009 #ifndef ATOMS_BUFFER_HH
00010 #define ATOMS_BUFFER_HH
00011
00012 #include <atoms/gen.hh>
00013 #include <stdlib.h>
00014 #include <locale>
00015 #include <atoms/stream.hh>
00016
00017 namespace atoms {
00018
00052 class Buffer {
00053 public:
00054 Buffer() : markSet(false), position(0), limit(0), capacity(0), buf(NULL) {}
00055
00060 ~Buffer() {
00061 assert(!markSet);
00062 free(buf);
00063 }
00064
00080 size_t readAndAppend(Stream *s, size_t min);
00081 size_t readAndAppend(const boost::shared_ptr<Stream> &s, size_t min) {
00082 return readAndAppend(s.get(), min);
00083 }
00085
00093 void append(const void *src, size_t n);
00094
00095 template <typename internT, typename externT, typename stateT>
00096 void append(const internT *from, const internT *fromEnd, stateT&,
00097 const std::codecvt<internT,externT,stateT>&);
00098
00107 void replace(const void *src, size_t p, size_t n);
00108
00119 size_t writeAndShift(Stream *s, size_t max);
00120 size_t writeAndShift(const boost::shared_ptr<Stream> &s, size_t max) {
00121 return writeAndShift(s.get(), max);
00122 }
00124
00133 void shift(void *dest, size_t n);
00134
00139 size_t truncate(size_t n);
00140
00142 size_t getSize() const { return limit - position; }
00143
00145 size_t getCapacity() const { return capacity; }
00146
00148 size_t getRollbackSize() const { return position; }
00149
00156 void setMark() {
00157 assert(!markSet);
00158 mark = position;
00159 markSet = true;
00160 }
00161
00167 void rollback() {
00168 assert(markSet);
00169 position = mark;
00170 markSet = false;
00171 }
00172
00176 void rollback(size_t n) {
00177 assert(n <= position);
00178 position -= n;
00179 if (position <= mark) {
00180 markSet = false;
00181 }
00182 }
00183
00189 void clear() {
00190 assert(markSet);
00191 markSet = false;
00192 }
00193 private:
00198 void prepareForAppend(size_t n);
00199
00207 size_t mark;
00208 bool markSet;
00210
00212 size_t position;
00213
00218 size_t limit;
00219
00221 size_t capacity;
00222
00227 char *buf;
00228
00230 static size_t MINIMUM_ALLOCATION;
00231
00232 static DebugLogger LOGGER;
00233 };
00234
00235 template <typename internT, typename externT, typename stateT>
00236 void Buffer::append(const internT *from, const internT *fromEnd, stateT &state,
00237 const std::codecvt<internT,externT,stateT> &cvt) {
00238 using namespace std;
00239 size_t oldSize = getSize();
00240 std::codecvt_base::result r;
00241 try {
00242 const internT *fromNext = from;
00243 externT *to, *toEnd, *toNext;
00244 do {
00245
00246 prepareForAppend(sizeof(externT));
00247
00248
00249 to = toNext = reinterpret_cast<externT*>(&buf[limit]);
00250 toEnd = reinterpret_cast<externT*>(&buf[capacity]);
00251 r = cvt.out(state, from, fromEnd, from, to, toEnd, to);
00252 limit += (toNext - to) * sizeof(externT);
00253 from = fromNext;
00254 } while (r == codecvt_base::partial && to == toEnd) ;
00255 } catch (std::bad_alloc&) {
00256
00257 limit = position + oldSize;
00258 throw;
00259 }
00260 if (r == codecvt_base::error) {
00261
00262
00263 limit = position + oldSize;
00264 throw Error("Invalid character conversion.");
00265 }
00266 if (r == codecvt_base::noconv) {
00267 append(from, sizeof(internT) * (fromEnd - from));
00268 return;
00269 }
00270 assert(r == codecvt_base::ok);
00271 }
00272
00273 }
00274 #endif // !ATOMS_BUFFER_HH