<commit_before>// @(#)root/base:$Id$
// Author: <NAME>   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TString.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#define PVOID (-1)

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;


ClassImp(TStorage)

//------------------------------------------------------------------------------

static const char *gSpaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   gMemStatistics;
static Int_t    gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
static Int_t    gAllocatedTotal, gFreedTotal;
static void   **gTraceArray = 0;
static Int_t    gTraceCapacity = 10, gTraceIndex = 0,
                gMemSize = -1, gMemIndex = -1;


//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!gMemStatistics) return;

   if ((Int_t)size == gMemSize) {
      if (gTraceIndex == gMemIndex)
         Fatal("EnterStat", "trapped allocation %d", gMemIndex);

      if (!gTraceArray)
         gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);

      if (gTraceIndex >= gTraceCapacity) {
         gTraceCapacity = gTraceCapacity*2;
         gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
      }
      gTraceArray[gTraceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      gAllocated[kObjMaxSize-1]++;
   else
      gAllocated[size]++;
   gAllocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!gMemStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == gMemSize) {
      for (int i = 0; i < gTraceIndex; i++)
         if (gTraceArray[i] == vp) {
            gTraceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      gFreed[kObjMaxSize-1]++;
   else
      gFreed[size]++;
   gFreedTotal += size;
}

//______________________________________________________________________________
void *TStorage::Alloc(size_t size)
{
   // Allocate a block of memory, that later can be resized using
   // TStorage::ReAlloc().

   static const char *where = "TStorage::Alloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   return vp;
}

//______________________________________________________________________________
void TStorage::Dealloc(void *ptr)
{
   // De-allocate block of memory, that was allocated via TStorage::Alloc().

#ifndef WIN32
   ::operator delete[](ptr);
#else
   ::operator delete(ptr);
#endif
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   memmove(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else<commit_msg>expand comment of ReAlloc(). Explains ROOT-5115.<commit_after>// @(#)root/base:$Id$
// Author: <NAME>   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TString.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#define PVOID (-1)

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;


ClassImp(TStorage)

//------------------------------------------------------------------------------

static const char *gSpaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   gMemStatistics;
static Int_t    gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
static Int_t    gAllocatedTotal, gFreedTotal;
static void   **gTraceArray = 0;
static Int_t    gTraceCapacity = 10, gTraceIndex = 0,
                gMemSize = -1, gMemIndex = -1;


//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!gMemStatistics) return;

   if ((Int_t)size == gMemSize) {
      if (gTraceIndex == gMemIndex)
         Fatal("EnterStat", "trapped allocation %d", gMemIndex);

      if (!gTraceArray)
         gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);

      if (gTraceIndex >= gTraceCapacity) {
         gTraceCapacity = gTraceCapacity*2;
         gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
      }
      gTraceArray[gTraceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      gAllocated[kObjMaxSize-1]++;
   else
      gAllocated[size]++;
   gAllocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!gMemStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == gMemSize) {
      for (int i = 0; i < gTraceIndex; i++)
         if (gTraceArray[i] == vp) {
            gTraceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      gFreed[kObjMaxSize-1]++;
   else
      gFreed[size]++;
   gFreedTotal += size;
}

//______________________________________________________________________________
void *TStorage::Alloc(size_t size)
{
   // Allocate a block of memory, that later can be resized using
   // TStorage::ReAlloc().

   static const char *where = "TStorage::Alloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   return vp;
}

//______________________________________________________________________________
void TStorage::Dealloc(void *ptr)
{
   // De-allocate block of memory, that was allocated via TStorage::Alloc().

#ifndef WIN32
   ::operator delete[](ptr);
#else
   ::operator delete(ptr);
#endif
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory. Don't use if size is larger
   // than old size, use ReAlloc(void *, size_t, size_t) instead.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   memmove(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else
{'fraction_non_alphanumeric': 0.16134340638791234, 'fraction_numerical': 0.007479991024010771, 'mean_word_length': 2.2008618625807994, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3680782', 'n_tokens_mistral': 3714, 'n_tokens_neox': 3574, 'n_words': 1048}