From 6b4a375ec3ff855b202dd2746d5a78212fdb1978 Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Sun, 29 Aug 2010 15:14:15 +0000 Subject: XPath: Allocator now uses custom allocation functions and has single static page, added out of memory handling during parsing git-svn-id: http://pugixml.googlecode.com/svn/trunk@647 99668b35-9821-0410-8761-19e4c4f06640 --- src/pugixpath.cpp | 86 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp index 6663ef8..a30ec55 100644 --- a/src/pugixpath.cpp +++ b/src/pugixpath.cpp @@ -620,14 +620,10 @@ namespace pugi } #endif - const size_t xpath_memory_block_size = 4096; ///< Memory block size, 4 kb + const size_t xpath_memory_block_size = 4096; class xpath_allocator { - // disable copy ctor and assignment - xpath_allocator(const xpath_allocator&); - xpath_allocator& operator=(const xpath_allocator&); - struct memory_block { memory_block(): next(0), size(0) @@ -641,23 +637,41 @@ namespace pugi }; memory_block* _root; + memory_block _first; public: - xpath_allocator(): _root(0) + static xpath_allocator* create() { - _root = new memory_block; + void* memory = get_memory_allocation_function()(sizeof(xpath_allocator)); + + return new (memory) xpath_allocator(); } - - ~xpath_allocator() + + static void destroy(xpath_allocator* alloc) { - while (_root) + if (!alloc) return; + + // free all allocated pages + memory_block* cur = alloc->_root; + memory_block* first = &alloc->_first; + + while (cur != first) { - memory_block* cur = _root->next; - delete _root; - _root = cur; + memory_block* next = cur->next; + + get_memory_deallocation_function()(cur); + + cur = next; } + + // free allocator memory (with the first page) + get_memory_deallocation_function()(alloc); } + xpath_allocator(): _root(&_first) + { + } + void* allocate(size_t size) { // align size so that we're able to store pointers in subsequent blocks @@ -671,13 +685,12 @@ namespace pugi } else { - memory_block* block; + size_t block_data_size = (size > xpath_memory_block_size) ? size : xpath_memory_block_size; + size_t block_size = block_data_size + offsetof(memory_block, data); + + memory_block* block = static_cast(get_memory_allocation_function()(block_size)); + if (!block) return 0; - if (size > xpath_memory_block_size) - block = static_cast(operator new(size + sizeof(memory_block) - xpath_memory_block_size)); - else - block = new memory_block; - block->next = _root; block->size = size; @@ -957,11 +970,6 @@ namespace pugi class xpath_lexer { - // disable copy ctor and assignment - xpath_lexer(const xpath_lexer&); - xpath_lexer& operator=(const xpath_lexer&); - - private: const char_t* _cur; const char_t* _cur_lexeme_pos; xpath_lexer_string _cur_lexeme_contents; @@ -2584,7 +2592,11 @@ namespace pugi void* alloc_node() { - return _alloc.allocate(sizeof(xpath_ast_node)); + void* result = _alloc.allocate(sizeof(xpath_ast_node)); + + if (!result) throw_error("Out of memory"); + + return result; } const char_t* alloc_string(const xpath_lexer_string& value) @@ -2594,6 +2606,8 @@ namespace pugi size_t length = static_cast(value.end - value.begin); char_t* c = static_cast(_alloc.allocate((length + 1) * sizeof(char_t))); + if (!c) throw_error("Out of memory"); + memcpy(c, value.begin, length * sizeof(char_t)); c[length] = 0; @@ -3373,9 +3387,6 @@ namespace pugi static xpath_ast_node* parse(const char_t* query, xpath_allocator& alloc, xpath_parse_result* result) { - result->error = 0; - result->offset = 0; - xpath_parser parser(query, alloc, result); int error = setjmp(parser._error_handler); @@ -3391,12 +3402,23 @@ namespace pugi xpath_query::xpath_query(const char_t* query): _alloc(0), _root(0) { - _alloc = new xpath_allocator; - _root = xpath_parser::parse(query, *_alloc, &_result); + _result.error = 0; + _result.offset = 0; + + _alloc = xpath_allocator::create(); + + if (!_alloc) + { + _result.error = "Out of memory"; + } + else + { + _root = xpath_parser::parse(query, *_alloc, &_result); + } if (!_root) { - delete _alloc; + xpath_allocator::destroy(_alloc); _alloc = 0; #ifndef PUGIXML_NO_EXCEPTIONS @@ -3407,7 +3429,7 @@ namespace pugi xpath_query::~xpath_query() { - delete _alloc; + xpath_allocator::destroy(_alloc); } xpath_value_type xpath_query::return_type() const -- cgit v1.2.3