/*
 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
 *
 * Squid software is distributed under GPLv2+ license and includes
 * contributions from numerous individuals and organizations.
 * Please see the COPYING and CONTRIBUTORS files for details.
 */

#ifndef SQUID_SRC_MEM_ALLOCATORPROXY_H
#define SQUID_SRC_MEM_ALLOCATORPROXY_H

// XXX: remove AllocatorProxy.h include from mem/forward.h
namespace Mem {
class Allocator;
class PoolStats;
}

/**
 * \hideinitializer
 *
 * Pool and account the memory used for the CLASS object.
 * This macro is intended for use within the declaration of a class.
 *
 * The memory block allocated by operator new is not zeroed; it is the
 * responsibility of users to ensure that constructors correctly
 * initialize all data members.
 */
#define MEMPROXY_CLASS(CLASS) \
    private: \
    static inline Mem::AllocatorProxy &Pool() { \
        static Mem::AllocatorProxy thePool(#CLASS, sizeof(CLASS), false); \
        return thePool; \
    } \
    public: \
    void *operator new(size_t byteCount) { \
        /* derived classes with different sizes must implement their own new */ \
        assert(byteCount == sizeof(CLASS)); \
        return Pool().alloc(); \
    } \
    void operator delete(void *address) { \
        if (address) \
            Pool().freeOne(address); \
    } \
    static int UseCount() { return Pool().inUseCount(); } \
    private:

namespace Mem
{

class PoolMeter;

/**
 * Support late binding of pool type for allocator agnostic classes
 */
class AllocatorProxy
{
public:
    AllocatorProxy(char const *aLabel, size_t const &aSize, bool doZeroBlocks = true):
        label(aLabel),
        size(aSize),
        theAllocator(nullptr),
        doZero(doZeroBlocks)
    {}

    /// Allocate one element from the pool
    void *alloc();

    /// Free a element allocated by Mem::AllocatorProxy::alloc()
    void freeOne(void *);

    int inUseCount() const;
    size_t objectSize() const {return size;}
    char const * objectType() const {return label;}

    PoolMeter const &getMeter() const;

    /**
     * \param stats Object to be filled with statistical data about pool.
     * \retval      Number of objects in use, ie. allocated.
     */
    size_t getStats(PoolStats &stats);

    void zeroBlocks(bool doIt);

private:
    Allocator *getAllocator() const;

    const char *label;
    size_t size;
    mutable Allocator *theAllocator;
    bool doZero;
};

} // namespace Mem

#endif /* SQUID_SRC_MEM_ALLOCATORPROXY_H */

