/* 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is the Sablotron XSLT Processor.
 * 
 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
 * Portions created by Ginger Alliance are Copyright (C) 2000 Ginger
 * Alliance Ltd. All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL"), in which case the provisions of the GPL are applicable 
 * instead of those above.  If you wish to allow use of your 
 * version of this file only under the terms of the GPL and not to
 * allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and
 * replace them with the notice and other provisions required by
 * the GPL.  If you do not delete the provisions above, a recipient
 * may use your version of this file under either the MPL or the
 * GPL.
 */

#ifndef ArenaHIncl
#define ArenaHIncl

// GP: clean

#include "base.h"

struct ArenaBlock
{
    void *data;
    ArenaBlock *next;
    int freeSpace;
};

class Arena
{
public:
    Arena(int bloxize_);
    /*size of by Tim Crook release 0.51 _PH_ */
    void *armalloc(int size, int alignment = sizeof (void*)); 
    void initialize(int bloxize_);
    void arfree(void *p);
    void dispose();
    ~Arena();
private:
    ArenaBlock *newBlock(int size);
    int bloxize;
    ArenaBlock *block0, *blockn;
    int totalAsked, totalMalloced;
};

class ArenaMember
{
public:
    /* VC++ 4.2 doesn't take the following:
    void operator delete(void *ptr, Arena *arena_) {};
    so far, VC++6 throws warnings
    */

    void *operator new(size_t size, Arena *arena_ = NULL)
    {
        // shouldn't be called without an arena specified
//        assert(arena_);
        return arena_? arena_ -> armalloc(size) : ::operator new(size);
    };

    void operator delete(void *ptr, size_t size)
    {
        // do nothing
        // ::operator delete(ptr);
    }
};

class ArenaStr : public ArenaMember, public Str
{
public:
    ArenaStr(Arena *arena__)
        : arena_(arena__) 
    {};
    ArenaStr(Str& string, Arena *arena__)
        : arena_(arena__)
    {
        operator =(string);
    };
/*
    ArenaStr(int num, Arena *arena__)
        : arena_(arena__)
    {
        operator =(num);
    };

    ArenaStr(double num, Arena *arena__)
        : arena_(arena__)
    {
        operator =(num);
    };

    ArenaStr(char c, Arena *arena__)
        : arena_(arena__)
    {
        operator =(c);
    };
*/
    ArenaStr(char *chars, Arena *arena__)
        : arena_(arena__)
    {
        operator =(chars);
    };
    ArenaStr(DStr &dstring, Arena *arena__)
        : arena_(arena__)
    {
        operator =(dstring);
    };

    const ArenaStr& operator= (const Str& string)
    { nset((char*)string, string.length()); return *this; }

    const ArenaStr& operator= (const DStr& dstring)
    { nset((char*)dstring, dstring.length()); return *this; }

    const ArenaStr& operator= (const char *s)
    { nset(s, strlen(s)); return *this; }

    ~ArenaStr()
    {
        remove_();
    }

protected:
    virtual char* claimMemory( int nbytes ) const 
    { 
        // ask for memory with alignment 1 if from arena
        return arena_ ? (char*)(arena_ -> armalloc(nbytes,1)) : Str::claimMemory(nbytes); 
    }
    virtual void returnMemory( char *&p ) const 
    {
        if (arena_)
            arena_ -> arfree(p);
        else
            if (p) delete[] p; 
        p = NULL; 
    }
    Arena *arena_;
};

#endif // ArenaHIncl
