|
|
| version 1.2, 2001/01/26 15:28:39 | version 1.27, 2001/03/10 16:34:35 |
|---|---|
| Line 1 | Line 1 |
| /* | /* |
| Parser | |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | |
| Author: Alexander Petrosyan <paf@design.ru> | |
| String Chunk0 | $Id$ |
| ====== ======== | |
| head--------->[ptr, size] | |
| append_here-------->[ptr, size] | |
| link_row ........ | |
| . . | |
| . [ptr, size] | |
| ...........>[link to the next chunk] | |
| */ | */ |
| #ifndef PA_POOL_H | #ifndef PA_POOL_H |
| Line 16 | Line 11 |
| #include <stddef.h> | #include <stddef.h> |
| class Pool; | class Exception; |
| class Temp_exception; | |
| class String { | class Pool { |
| friend Temp_exception; | |
| public: | public: |
| enum { | |
| CR_PREALLOCATED_COUNT=5, | |
| CR_GROW_PERCENT=60 | |
| }; | |
| private: | Pool() : fexception(0) {} |
| friend Pool; | ~Pool() {} |
| // the pool I'm allocated on | Exception& exception() const { return *fexception; } |
| Pool *pool; | |
| // last chank allocated count cache | void *malloc(size_t size) { |
| int curr_chunk_rows; | return check(real_malloc(size), size); |
| struct Chunk { | } |
| // the number of rows per chunk | void *calloc(size_t size) { |
| int count; | return check(real_calloc(size), size); |
| union Row { | |
| // chunk item | |
| struct { | |
| char *ptr; // pointer to the start of string fragment | |
| size_t size; // length of the fragment | |
| } item; | |
| Chunk *link; // link to the next chunk in chain | |
| } first[CR_PREALLOCATED_COUNT]; | |
| // next rows are here | |
| Chunk *preallocated_link; | |
| } | } |
| head; // the head chunk of the chunk chain | |
| // next append would write to this record | private: // implementation defined |
| Chunk::Row *append_here; | |
| // the address of place where lies address | |
| // of the link to the next chunk to allocate | |
| Chunk::Row *link_row; | |
| // new&constructors made private to enforce factory manufacturing at pool | void *real_malloc(size_t size); |
| void *operator new(size_t size, Pool *apool); | void *real_calloc(size_t size); |
| void construct(Pool *apool); | private: |
| String(Pool *apool) { | |
| construct(apool); | // checks whether mem allocated OK. throws exception otherwise |
| } | void *check(void *ptr, size_t size) { |
| String(Pool *apool, char *src) { | if(ptr) |
| construct(apool); | return ptr; |
| *this+=src; | |
| fail(size); | |
| // never reached | |
| return 0; | |
| } | } |
| // throws proper exception | |
| void fail(size_t size) const; | |
| bool chunk_is_full() { | protected: // exception handling |
| return append_here == link_row; | |
| // exception replacement mechanism is 'protected' from direct usage | |
| // Temp_exception_change object enforces paired set/restore | |
| Exception *set_exception(Exception *e){ | |
| Exception *r=fexception; | |
| fexception=e; | |
| return r; | |
| } | |
| void restore_exception(Exception *e) { | |
| fexception=e; | |
| } | } |
| void expand(); | |
| public: | private: |
| // current request's exception object | |
| Exception *fexception; | |
| size_t size(); | private: //disabled |
| char *c_str(); | |
| String& operator += (char *src); | // Pool(const Pool&) {} |
| Pool& operator = (const Pool&) { return *this; } | |
| }; | }; |
| class Pool { | class Pooled { |
| // the pool i'm allocated on | |
| Pool& fpool; | |
| public: | public: |
| Pool(); | |
| ~Pool(); | static void *operator new(size_t size, Pool& apool) { |
| void *alloc(size_t size); | return apool.malloc(size); |
| void *calloc(size_t size); | } |
| String *makeString() { | Pooled(Pool& apool) : fpool(apool) { |
| return new(this) String(this); | |
| } | } |
| String *makeString(char *src) { | |
| return new(this) String(this, src); | Pool& pool() const { return fpool; } |
| void *malloc(size_t size) const { return fpool.malloc(size); } | |
| void *calloc(size_t size) const { return fpool.calloc(size); } | |
| Exception& exception() const { return fpool.exception(); } | |
| }; | |
| #define NEW new(pool()) | |
| class Temp_exception { | |
| Pool pool; | |
| Exception *saved_exception; | |
| public: | |
| Temp_exception(Pool& apool, Exception& exception) : | |
| pool(apool), | |
| saved_exception(apool.set_exception(&exception)) { | |
| } | |
| ~Temp_exception() { | |
| pool.restore_exception(saved_exception); | |
| } | } |
| }; | }; |
| #define TRY \ | |
| { \ | |
| Exception temp_exception; \ | |
| Temp_exception le(pool(), temp_exception); \ | |
| if(setjmp(temp_exception.mark)==0) | |
| #define THROW exception()._throw | |
| #define POOL_THROW pool.exception()._throw | |
| #define CATCH(e) \ | |
| else{ \ | |
| Exception& e=temp_exception; | |
| #define END_CATCH \ | |
| } \ | |
| } | |
| // usage: | |
| // TRY { ...; if(?) RAISE(?); ...; } CATCH(e) { catch-code e.comment() } END_CATCH | |
| #endif | #endif |