|
|
| version 1.32, 2001/03/13 16:38:22 | version 1.86.4.2, 2003/03/18 09:53:01 |
|---|---|
| Line 1 | Line 1 |
| /* | /** @file |
| Parser | Parser: pool class decl. |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | |
| $Id$ | Copyright (c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | |
| */ | */ |
| #ifndef PA_POOL_H | #ifndef PA_POOL_H |
| #define PA_POOL_H | #define PA_POOL_H |
| #include <stddef.h> | static const char* IDENT_POOL_H="$Date$"; |
| #include "pa_config_includes.h" | |
| #ifdef XML | |
| # include "gdome.h" | |
| // for xmlChar | |
| # include "libxml/tree.h" | |
| #endif | |
| // forwards | |
| class Exception; | class Exception; |
| class Temp_exception; | class String; |
| class Charset; | |
| class GdomeDOMString_auto_ptr; | |
| /** | |
| Pool mechanizm allows users not to free up allocated memory, | |
| leaving that problem to 'pools'. | |
| @see Pooled | |
| */ | |
| class Pool { | class Pool { |
| friend Temp_exception; | |
| public: | public: |
| Pool() : fexception(0) {} | Pool(void *astorage); |
| ~Pool() {} | ~Pool(); |
| //{@ collector issues | |
| void collect_garbage(); | |
| void log_high_watermark(const char *msg); | |
| //}@ | |
| //{@ statistics | |
| size_t total_allocated() { return ftotal_allocated; } | |
| unsigned int total_times() { return ftotal_times; } | |
| //}@ | |
| Exception& exception() const { return *fexception; } | void set_context(void *acontext) { fcontext=acontext; } |
| void *get_context() { return fcontext; } | |
| void *malloc(size_t size) { | /// allocates some bytes on pool |
| return check(real_malloc(size), size); | void *malloc_atomic(size_t size, int place=0) { |
| return check(real_malloc_atomic(size, place), size); | |
| } | } |
| /// allocates some bytes on pool | |
| void *malloc(size_t size, int place=0) { | |
| return check(real_malloc(size, place), size); | |
| } | |
| /// allocates some bytes clearing them with zeros | |
| void *calloc(size_t size) { | void *calloc(size_t size) { |
| return check(real_calloc(size), size); | return check(real_calloc(size), size); |
| } | } |
| private: // implementation defined | /// registers a routine to clean up non-pooled allocations |
| void register_cleanup(void (*cleanup) (void *, void *), void *data) { | |
| if(!real_register_cleanup(cleanup, data)) | |
| fail_register_cleanup(); | |
| } | |
| //{@ helpers | |
| void *copy(const void *buf, const size_t size); | |
| char *copy(const char *cstr); | |
| //}@ | |
| //{@ source charset | |
| void set_source_charset(Charset& acharset); | |
| Charset& get_source_charset(); | |
| //}@ | |
| //{@ client charset | |
| void set_client_charset(Charset& charset); | |
| Charset& get_client_charset(); | |
| //}@ | |
| #ifdef XML | |
| /// @see Charset::transcode_cstr(xmlChar *s); | |
| const char *transcode_cstr(xmlChar *s); | |
| /// @see Charset::transcode(xmlChar *s); | |
| String& transcode(xmlChar *s | |
| #ifndef NO_STRING_ORIGIN | |
| , const String *origin | |
| #endif | |
| ); | |
| /// @see Charset::transcode_cstr(GdomeDOMString *s); | |
| const char *transcode_cstr(GdomeDOMString *s); | |
| /// @see Charset::transcode(GdomeDOMString *s); | |
| String& transcode(GdomeDOMString *s | |
| #ifndef NO_STRING_ORIGIN | |
| , const String *origin | |
| #endif | |
| ); | |
| /// @see Charset::transcode_cstr(const char *buf, size_t buf_size=0); | |
| xmlChar *transcode_buf2xchar(const char *buf, size_t buf_size=0); | |
| /// @see Charset::transcode(const String& s) | |
| GdomeDOMString_auto_ptr transcode(const String& s); | |
| #endif | |
| private: | |
| void *fstorage; | |
| void *fcontext; | |
| Charset *source_charset; | |
| Charset *client_charset; | |
| void *real_malloc(size_t size); | private: |
| //{ | |
| /// @name implementation defined | |
| void real_init(); | |
| void real_finit(); | |
| void *real_malloc(size_t size, int place); | |
| void *real_malloc_atomic(size_t size, int place); | |
| void *real_calloc(size_t size); | void *real_calloc(size_t size); |
| bool real_register_cleanup(void (*cleanup) (void *,void *), void *data); | |
| //} | |
| private: | private: |
| // checks whether mem allocated OK. throws exception otherwise | /// checks whether mem allocated OK. throws exception otherwise |
| void *check(void *ptr, size_t size) { | void *check(void *ptr, size_t size) { |
| if(ptr) | if(ptr) { |
| ftotal_allocated+=size; | |
| ftotal_times++; | |
| return ptr; | return ptr; |
| } | |
| fail(size); | fail_alloc(size); |
| // never reached | // never reached |
| return 0; | return 0; |
| } | } |
| // throws proper exception | /// throws allocation exception |
| void fail(size_t size) const; | void fail_alloc(size_t size) const; |
| protected: // exception handling | |
| // exception replacement mechanism is 'protected' from direct usage | /// throws register cleanup exception |
| // Temp_exception_change object enforces paired set/restore | void fail_register_cleanup() const; |
| Exception *set_exception(Exception *e){ | |
| Exception *r=fexception; | |
| fexception=e; | |
| return r; | |
| } | |
| void restore_exception(Exception *e) { | |
| fexception=e; | |
| } | |
| private: | private: // statistics |
| // current request's exception object | size_t ftotal_allocated; |
| Exception *fexception; | unsigned int ftotal_times; |
| private: //disabled | private: //disabled |
| // Pool(const Pool&) {} | Pool(const Pool&); |
| Pool& operator = (const Pool&) { return *this; } | Pool& operator= (const Pool&); |
| }; | }; |
| /** | |
| Base for all classes that are allocated in 'pools'. | |
| Holds Pool object. Contains useful wrappers to it's methods. | |
| @see NEW | |
| */ | |
| /** | |
| @todo: try to remember the meaning of this old comment: | |
| all classes that are members parents of packed class [String] | |
| sould be packed also to avoid sparc odd st/lduh problem | |
| [packing is unacceptable for garbage collector] | |
| */ | |
| class Pooled { | class Pooled { |
| // the pool i'm allocated on | // the pool i'm allocated on |
| Pool& fpool; | Pool *fpool; |
| public: | public: |
| static void *operator new(size_t size, Pool& apool) { | |
| return apool.malloc(size); | |
| } | |
| Pooled(Pool& apool) : fpool(apool) { | /// the Pooled-sole: Pooled instances can be allocated in Pool rather then on heap |
| static void *operator new(size_t size, Pool& apool) { | |
| return apool.malloc(size, 1); | |
| } | } |
| Pool& pool() const { return fpool; } | Pooled(Pool& apool) : fpool(&apool) {} |
| void *malloc(size_t size) const { return fpool.malloc(size); } | /// my pool |
| void *calloc(size_t size) const { return fpool.calloc(size); } | Pool& pool() const { return *fpool; } |
| Exception& exception() const { return fpool.exception(); } | |
| }; | |
| #define NEW new(pool()) | |
| class Temp_exception { | /** used for moving objects from one pool to another. |
| Pool& fpool; | in between object can have no pool and can not be used |
| Exception *saved_exception; | @see SQL_Driver_manager |
| public: | */ |
| Temp_exception(Pool& apool, Exception& exception) : | void set_pool(Pool *apool) { fpool=apool; } |
| fpool(apool), | |
| saved_exception(apool.set_exception(&exception)) { | //{ |
| } | /// @name useful wrapper around pool |
| ~Temp_exception() { | void *malloc(size_t size, int place=0) const { return fpool->malloc(size, place); } |
| fpool.restore_exception(saved_exception); | void *malloc_atomic(size_t size, int place=0) const { return fpool->malloc_atomic(size, place); } |
| void *calloc(size_t size) const { return fpool->calloc(size); } | |
| void register_cleanup(void (*cleanup) (void *, void *), void *data) { fpool->register_cleanup(cleanup, data); } | |
| void *copy(const void *buf, const size_t size) { return fpool->copy(buf, size); } | |
| char *copy(const char *cstr) { return fpool->copy(cstr); } | |
| #ifdef XML | |
| const char *transcode_cstr(GdomeDOMString *s) { return fpool->transcode_cstr(s); } | |
| String& transcode(GdomeDOMString *s | |
| #ifndef NO_STRING_ORIGIN | |
| , const String *origin | |
| #endif | |
| ) { | |
| return fpool->transcode(s | |
| #ifndef NO_STRING_ORIGIN | |
| , origin | |
| #endif | |
| ); | |
| } | } |
| }; | |
| #define TRY \ | #endif |
| { \ | //} |
| Exception temp_exception; \ | }; |
| Temp_exception le(pool(), temp_exception); \ | |
| if(setjmp(temp_exception.mark)==0) | |
| #define THROW exception()._throw | |
| #define PTHROW pool.exception()._throw | |
| #define RTHROW r.pool().exception()._throw | |
| #define CATCH(e) \ | |
| else{ \ | |
| Exception& e=temp_exception; | |
| #define END_CATCH \ | /// useful macro for creating objects on current Pooled object Pooled::pool() |
| } \ | #define NEW new(pool()) |
| } | |
| // usage: | |
| // TRY { ...; if(?) RAISE(?); ...; } CATCH(e) { catch-code e.comment() } END_CATCH | |
| #endif | #endif |