<commit_before>/*****************************************************************************/
/* CascRootFile_SC1.cpp                   Copyright (c) Ladislav Zezula 2017 */
/*---------------------------------------------------------------------------*/
/* Support for loading Starcraft 1 ROOT file                                 */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 28.10.15  1.00  Lad  The first version of CascRootFile_SC1.cpp            */
/*****************************************************************************/

#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"

//-----------------------------------------------------------------------------
// Structure definitions for Overwatch root file

typedef struct _CASC_FILE_ENTRY
{
    ENCODING_KEY EncodingKey;                       // Encoding key
    ULONGLONG FileNameHash;                         // File name hash
    DWORD dwFileName;                               // Offset of the file name in the name cache
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;

struct TRootHandler_SC1 : public TRootHandler
{
    // Linear global list of file entries
    DYNAMIC_ARRAY FileTable;

    // Linear global list of names
    DYNAMIC_ARRAY FileNames;

    // Global map of FileName -> FileEntry
    PCASC_MAP pRootMap;
};

//-----------------------------------------------------------------------------
// Local functions

static int InsertFileEntry(
    TRootHandler_SC1 * pRootHandler,
    const char * szFileName,
    LPBYTE pbEncodingKey)
{
    PCASC_FILE_ENTRY pFileEntry;
    size_t nLength = strlen(szFileName);

    // Attempt to insert the file name to the global buffer
    szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
    if(szFileName == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Attempt to insert the entry to the array of file entries
    pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
    if(pFileEntry == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Fill the file entry
    pFileEntry->EncodingKey  = *(PENCODING_KEY)pbEncodingKey;
    pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
    pFileEntry->dwFileName   = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);

    // Insert the file entry to the map
    assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
    Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
    return ERROR_SUCCESS;
}

//-----------------------------------------------------------------------------
// Implementation of Overwatch root file

static int SC1Handler_Insert(
    TRootHandler_SC1 * pRootHandler,
    const char * szFileName,
    LPBYTE pbEncodingKey)
{
    return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
}

static LPBYTE SC1Handler_Search(TRootHandler_SC1 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
{
    PCASC_FILE_ENTRY pFileEntry;

    // Are we still inside the root directory range?
    while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
    {
        // Retrieve the file item
        pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);

        // Prepare the pointer to the next search
        pSearch->IndexLevel1++;

        char *filename = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName);
        if (CheckWildCard(filename, pSearch->szMask)) {
            strcpy(pSearch->szFileName, filename);
            return pFileEntry->EncodingKey.Value;
        }
    }

    // No more entries
    return NULL;
}

static void SC1Handler_EndSearch(TRootHandler_SC1 * /* pRootHandler */, TCascSearch * /* pSearch */)
{
    // Do nothing
}

static LPBYTE SC1Handler_GetKey(TRootHandler_SC1 * pRootHandler, const char * szFileName)
{
    ULONGLONG FileNameHash = CalcFileNameHash(szFileName);

    return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
}

static DWORD SC1Handler_GetFileId(TRootHandler_SC1 * /* pRootHandler */, const char * /* szFileName */)
{
  // Not implemented for Overwatch
  return 0;
}

static void SC1Handler_Close(TRootHandler_SC1 * pRootHandler)
{
    if(pRootHandler != NULL)
    {
        // Free the file map
        if(pRootHandler->pRootMap)
            Map_Free(pRootHandler->pRootMap);
        pRootHandler->pRootMap = NULL;

        // Free the array of the file names and file items
        Array_Free(&pRootHandler->FileTable);
        Array_Free(&pRootHandler->FileNames);

        // Free the root file itself
        CASC_FREE(pRootHandler);
    }
}

//-----------------------------------------------------------------------------
// Public functions

int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
    TRootHandler_SC1 * pRootHandler;
    ENCODING_KEY KeyBuffer;
    QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
    void * pTextFile;
    size_t nLength;
    char szOneLine[0x200];
    char szFileName[MAX_PATH+1];
    DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
    int nFileNameIndex;
    int nError = ERROR_SUCCESS;

    // Allocate the root handler object
    hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_SC1, 1);
    if(pRootHandler == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Fill-in the handler functions
    memset(pRootHandler, 0, sizeof(TRootHandler_SC1));
    pRootHandler->Insert      = (ROOT_INSERT)SC1Handler_Insert;
    pRootHandler->Search      = (ROOT_SEARCH)SC1Handler_Search;
    pRootHandler->EndSearch   = (ROOT_ENDSEARCH)SC1Handler_EndSearch;
    pRootHandler->GetKey      = (ROOT_GETKEY)SC1Handler_GetKey;
    pRootHandler->Close       = (ROOT_CLOSE)SC1Handler_Close;
    pRootHandler->GetFileId   = (ROOT_GETFILEID)SC1Handler_GetFileId;

    // Fill-in the flags
    pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;

    // Allocate the linear array of file entries
    nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
    if(nError != ERROR_SUCCESS)
        return nError;

    // Allocate the buffer for the file names
    nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
    if(nError != ERROR_SUCCESS)
        return nError;

    // Create map of ROOT_ENTRY -> FileEntry
    pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
    if(pRootHandler->pRootMap == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Parse the ROOT file
    pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
    if(pTextFile != NULL)
    {
        // Parse the next lines
        while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
        {
            LPSTR szEncodingKey;
            BYTE EncodingKey[MD5_HASH_SIZE];

            szEncodingKey = strchr(szOneLine, _T('|'));
            if(szEncodingKey != NULL)
            {
                // Split the name and encoding key
                *szEncodingKey++ = 0;

                // Insert the entry to the map
                ConvertStringToBinary(szEncodingKey, MD5_STRING_SIZE, EncodingKey);
                InsertFileEntry(pRootHandler, szOneLine, EncodingKey);
            }
        }

        // Free the listfile
        ListFile_Free(pTextFile);
    }

    // Succeeded
    return nError;
}
<commit_msg>Remove compilation warnings<commit_after>/*****************************************************************************/
/* CascRootFile_SC1.cpp                   Copyright (c) Ladislav Zezula 2017 */
/*---------------------------------------------------------------------------*/
/* Support for loading Starcraft 1 ROOT file                                 */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 28.10.15  1.00  Lad  The first version of CascRootFile_SC1.cpp            */
/*****************************************************************************/

#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"

//-----------------------------------------------------------------------------
// Structure definitions for Overwatch root file

typedef struct _CASC_FILE_ENTRY
{
    ENCODING_KEY EncodingKey;                       // Encoding key
    ULONGLONG FileNameHash;                         // File name hash
    DWORD dwFileName;                               // Offset of the file name in the name cache
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;

struct TRootHandler_SC1 : public TRootHandler
{
    // Linear global list of file entries
    DYNAMIC_ARRAY FileTable;

    // Linear global list of names
    DYNAMIC_ARRAY FileNames;

    // Global map of FileName -> FileEntry
    PCASC_MAP pRootMap;
};

//-----------------------------------------------------------------------------
// Local functions

static int InsertFileEntry(
    TRootHandler_SC1 * pRootHandler,
    const char * szFileName,
    LPBYTE pbEncodingKey)
{
    PCASC_FILE_ENTRY pFileEntry;
    size_t nLength = strlen(szFileName);

    // Attempt to insert the file name to the global buffer
    szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
    if(szFileName == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Attempt to insert the entry to the array of file entries
    pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
    if(pFileEntry == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Fill the file entry
    pFileEntry->EncodingKey  = *(PENCODING_KEY)pbEncodingKey;
    pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
    pFileEntry->dwFileName   = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);

    // Insert the file entry to the map
    assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
    Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
    return ERROR_SUCCESS;
}

//-----------------------------------------------------------------------------
// Implementation of Overwatch root file

static int SC1Handler_Insert(
    TRootHandler_SC1 * pRootHandler,
    const char * szFileName,
    LPBYTE pbEncodingKey)
{
    return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
}

static LPBYTE SC1Handler_Search(TRootHandler_SC1 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
{
    PCASC_FILE_ENTRY pFileEntry;

    // Are we still inside the root directory range?
    while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
    {
        // Retrieve the file item
        pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);

        // Prepare the pointer to the next search
        pSearch->IndexLevel1++;

        char *filename = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName);
        if (CheckWildCard(filename, pSearch->szMask)) {
            strcpy(pSearch->szFileName, filename);
            return pFileEntry->EncodingKey.Value;
        }
    }

    // No more entries
    return NULL;
}

static void SC1Handler_EndSearch(TRootHandler_SC1 * /* pRootHandler */, TCascSearch * /* pSearch */)
{
    // Do nothing
}

static LPBYTE SC1Handler_GetKey(TRootHandler_SC1 * pRootHandler, const char * szFileName)
{
    ULONGLONG FileNameHash = CalcFileNameHash(szFileName);

    return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
}

static DWORD SC1Handler_GetFileId(TRootHandler_SC1 * /* pRootHandler */, const char * /* szFileName */)
{
  // Not implemented for Overwatch
  return 0;
}

static void SC1Handler_Close(TRootHandler_SC1 * pRootHandler)
{
    if(pRootHandler != NULL)
    {
        // Free the file map
        if(pRootHandler->pRootMap)
            Map_Free(pRootHandler->pRootMap);
        pRootHandler->pRootMap = NULL;

        // Free the array of the file names and file items
        Array_Free(&pRootHandler->FileTable);
        Array_Free(&pRootHandler->FileNames);

        // Free the root file itself
        CASC_FREE(pRootHandler);
    }
}

//-----------------------------------------------------------------------------
// Public functions

int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
{
    TRootHandler_SC1 * pRootHandler;
    ENCODING_KEY KeyBuffer;
    QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
    void * pTextFile;
    size_t nLength;
    char szOneLine[0x200];
    DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
    int nError = ERROR_SUCCESS;

    // Allocate the root handler object
    hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_SC1, 1);
    if(pRootHandler == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Fill-in the handler functions
    memset(pRootHandler, 0, sizeof(TRootHandler_SC1));
    pRootHandler->Insert      = (ROOT_INSERT)SC1Handler_Insert;
    pRootHandler->Search      = (ROOT_SEARCH)SC1Handler_Search;
    pRootHandler->EndSearch   = (ROOT_ENDSEARCH)SC1Handler_EndSearch;
    pRootHandler->GetKey      = (ROOT_GETKEY)SC1Handler_GetKey;
    pRootHandler->Close       = (ROOT_CLOSE)SC1Handler_Close;
    pRootHandler->GetFileId   = (ROOT_GETFILEID)SC1Handler_GetFileId;

    // Fill-in the flags
    pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;

    // Allocate the linear array of file entries
    nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
    if(nError != ERROR_SUCCESS)
        return nError;

    // Allocate the buffer for the file names
    nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
    if(nError != ERROR_SUCCESS)
        return nError;

    // Create map of ROOT_ENTRY -> FileEntry
    pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
    if(pRootHandler->pRootMap == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    // Parse the ROOT file
    pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
    if(pTextFile != NULL)
    {
        // Parse the next lines
        while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
        {
            LPSTR szEncodingKey;
            BYTE EncodingKey[MD5_HASH_SIZE];

            szEncodingKey = strchr(szOneLine, _T('|'));
            if(szEncodingKey != NULL)
            {
                // Split the name and encoding key
                *szEncodingKey++ = 0;

                // Insert the entry to the map
                ConvertStringToBinary(szEncodingKey, MD5_STRING_SIZE, EncodingKey);
                InsertFileEntry(pRootHandler, szOneLine, EncodingKey);
            }
        }

        // Free the listfile
        ListFile_Free(pTextFile);
    }

    // Succeeded
    return nError;
}
<|endoftext|>


<commit_before>/** Initialize bitcoin.
 *  @pre Parameters should be parsed and config file should be read.
 */
bool AppInit3(boost::thread_group& threadGroup) {
  umask(077);

  // Clean shutdown on SIGTERM
  struct sigaction sa;
  sa.sa_handler = HandleSIGTERM;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  // Reopen debug.log on SIGHUP
  struct sigaction sa_hup;
  sa_hup.sa_handler = HandleSIGHUP;
  sigemptyset(&sa_hup.sa_mask);
  sa_hup.sa_flags = 0;
  sigaction(SIGHUP, &sa_hup, NULL);

#if defined (__SVR4) && defined (__sun)
  // ignore SIGPIPE on Solaris
  signal(SIGPIPE, SIG_IGN);
#endif

  // ********************************************************* Step 2: parameter interactions

  // Make sure enough file descriptors are available
  int nBind = 1;
  nMaxConnections = 125;
  nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
  int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
  if (nFD < MIN_CORE_FILEDESCRIPTORS) {
    return InitError(_("Not enough file descriptors available."));
  }

  if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) {
    nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
  }

  // ********************************************************* Step 3: parameter-to-internal-flags

  // Checkmempool defaults to true in regtest mode
  mempool.setSanityCheck(Params().DefaultCheckMemPool());
  Checkpoints::fEnabled = true;

  // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
  nScriptCheckThreads = DEFAULT_SCRIPTCHECK_THREADS;
  if (nScriptCheckThreads <= 0) {
    nScriptCheckThreads += boost::thread::hardware_concurrency();
  }
  if (nScriptCheckThreads <= 1) {
    nScriptCheckThreads = 0;
  } else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) {
    nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
  }

  fServer = true;
  fPrintToConsole = false;
  fLogTimestamps = true;
  fLogIPs = false;
  setvbuf(stdout, NULL, _IOLBF, 0);
#ifdef ENABLE_WALLET
  bool fDisableWallet = false;
#endif

  // Continue to put "/P2SH/" in the coinbase to monitor
  // BIP16 support.
  // This can be removed eventually...
  const char* pszP2SH = "/P2SH/";
  COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));

#ifdef ENABLE_WALLET
  std::string strWalletFile = "wallet.dat";
#endif

  // *********************************************************
  // Step 4: application initialization: dir lock, daemonize, pidfile, debug log
  // Sanity check
  if (!InitSanityCheck()) {
    return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down."));
  }

  std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET
  // Wallet file must be a plain filename without a directory
  if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) {
    return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
  }
#endif

  // Make sure only a single Bitcoin process is using the data directory.
  boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
  FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
  if (file) fclose(file);
  static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
  if (!lock.try_lock()) {
    return InitError(strprintf(_(
      "Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running."), strDataDir));
  }

  if (nScriptCheckThreads) {
    for (int i = 0; i < nScriptCheckThreads - 1; i++) {
      threadGroup.create_thread(&ThreadScriptCheck);
    }
  }

  int64_t nStart;

  // ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
  if (!fDisableWallet) {
    if (!bitdb.Open(GetDataDir())) {
      // try moving the database env out of the way
      boost::filesystem::path pathDatabase = GetDataDir() / "database";
      boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
      try {
        boost::filesystem::rename(pathDatabase, pathDatabaseBak);
      } catch(boost::filesystem::filesystem_error &error) {
         // failure is ok (well, not really, but it's not worse than what we started with)
      }

      // try again
      if (!bitdb.Open(GetDataDir())) {
        // if it still fails, it probably means we can't even create the database env
        return InitError(msg);
      }
    }

    if (filesystem::exists(GetDataDir() / strWalletFile)) {
      CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover);
      if (r == CDBEnv::RECOVER_OK) {
        string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
                     " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
                     " your balance or transactions are incorrect you should"
                     " restore from a backup."), strDataDir);
        InitWarning(msg);
      }
      if (r == CDBEnv::RECOVER_FAIL) {
        return InitError(_("wallet.dat corrupt, salvage failed"));
      }
    }
  }
#endif // ENABLE_WALLET
  // ********************************************************* Step 6: network initialization

  RegisterNodeSignals(GetNodeSignals());

  bool fBound = false;
  if (fListen) {
    struct in_addr inaddr_any;
    inaddr_any.s_addr = INADDR_ANY;
    fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
    fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
    if (!fBound) {
      return InitError(_("Failed to listen on any port."));
    }
  }

  // ********************************************************* Step 7: load block chain

  fReindex = false;

  // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
  filesystem::path blocksDir = GetDataDir() / "blocks";
  if (!filesystem::exists(blocksDir))
  {
    filesystem::create_directories(blocksDir);
    bool linked = false;
    for (unsigned int i = 1; i < 10000; i++) {
      filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i);
      if (!filesystem::exists(source)) break;
      filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i-1);
      try {
        filesystem::create_hard_link(source, dest);
        linked = true;
      } catch (filesystem::filesystem_error & e) {
        // Note: hardlink creation failing is not a disaster, it just means
        // blocks will get re-downloaded from peers.
        break;
      }
    }
    if (linked) {
      fReindex = true;
    }
  }

  // cache size calculations
  size_t nTotalCache = nDefaultDbCache << 20;
  if (nTotalCache < (nMinDbCache << 20)) {
    nTotalCache = (nMinDbCache << 20); // total cache cannot be less than nMinDbCache
  } else if (nTotalCache > (nMaxDbCache << 20)) {
    nTotalCache = (nMaxDbCache << 20); // total cache cannot be greater than nMaxDbCache
  }
  size_t nBlockTreeDBCache = nTotalCache / 8;
  if (nBlockTreeDBCache > (1 << 21)) {
    nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
  }
  nTotalCache -= nBlockTreeDBCache;
  size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache
  nTotalCache -= nCoinDBCache;
  nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes

  bool fLoaded = false;
  while (!fLoaded) {
    bool fReset = fReindex;
    std::string strLoadError;

    nStart = GetTimeMillis();
    do {
      try {
        UnloadBlockIndex();
        delete pcoinsTip;
        delete pcoinsdbview;
        delete pblocktree;

        pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
        pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
        pcoinsTip = new CCoinsViewCache(*pcoinsdbview);

        if (fReindex) {
          pblocktree->WriteReindexing(true);
        }

        if (!LoadBlockIndex()) {
          strLoadError = _("Error loading block database");
          break;
        }

        // If the loaded chain has a wrong genesis, bail out immediately
        // (we're likely using a testnet datadir, or the other way around).
        if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL)
          return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));

        // Initialize the block index (no-op if non-empty database was already loaded)
        if (!InitBlockIndex()) {
          strLoadError = _("Error initializing block database");
          break;
        }

        // Check for changed -txindex state
        if (fTxIndex != false) {
          strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
          break;
        }

        if (!CVerifyDB().VerifyDB(3, 288)) {
          strLoadError = _("Corrupted block database detected");
          break;
        }
      } catch(std::exception &e) {
        strLoadError = _("Error opening block database");
        break;
      }

      fLoaded = true;
    } while(false);

    if (!fLoaded) {
      if (!fReset) {
        // reindex or return
        fReindex = true;
        fRequestShutdown = false;
        // return false;
      } else {
        return InitError(strLoadError);
      }
    }
  }

  // As LoadBlockIndex can take several minutes, it's possible the user
  // requested to kill the GUI during the last operation. If so, exit.
  // As the program has not fully started yet, Shutdown() is possibly overkill.
  if (fRequestShutdown) {
    return false;
  }

  boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
  CAutoFile est_filein = CAutoFile(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION);
  // Allowed to fail as this file IS missing on first startup.
  if (est_filein) {
    mempool.ReadFeeEstimates(est_filein);
  }

  // ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
  if (fDisableWallet) {
    pwalletMain = NULL;
  } else {
    // needed to restore wallet transaction meta data after -zapwallettxes
    std::vector<CWalletTx> vWtx;

    nStart = GetTimeMillis();
    bool fFirstRun = true;
    pwalletMain = new CWallet(strWalletFile);
    DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
    if (nLoadWalletRet != DB_LOAD_OK) {
      if (nLoadWalletRet == DB_CORRUPT) {
        strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
      } else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) {
        string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
               " or address book entries might be missing or incorrect."));
        InitWarning(msg);
      } else if (nLoadWalletRet == DB_TOO_NEW) {
        strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin Core") << "\n";
      } else if (nLoadWalletRet == DB_NEED_REWRITE) {
        strErrors << _("Wallet needed to be rewritten: restart Bitcoin Core to complete") << "\n";
        return InitError(strErrors.str());
      } else {
        strErrors << _("Error loading wallet.dat") << "\n";
      }
    }

    if (fFirstRun) {
      int nMaxVersion = 0;
      if (nMaxVersion == 0) {
        nMaxVersion = CLIENT_VERSION;
        pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
      } else {
        if (nMaxVersion < pwalletMain->GetVersion()) {
          strErrors << _("Cannot downgrade wallet") << "\n";
        }
      }
      pwalletMain->SetMaxVersion(nMaxVersion);

      // Create new keyUser and set as default key
      RandAddSeedPerfmon();

      CPubKey newDefaultKey;
      if (pwalletMain->GetKeyFromPool(newDefaultKey)) {
        pwalletMain->SetDefaultKey(newDefaultKey);
        if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) {
          strErrors << _("Cannot write default address") << "\n";
        }
      }

      pwalletMain->SetBestChain(chainActive.GetLocator());
    }

    RegisterWallet(pwalletMain);

    CBlockIndex *pindexRescan = chainActive.Tip();
    CWalletDB walletdb(strWalletFile);
    CBlockLocator locator;

    if (walletdb.ReadBestBlock(locator)) {
      pindexRescan = chainActive.FindFork(locator);
    } else {
      pindexRescan = chainActive.Genesis();
    }

    if (chainActive.Tip() && chainActive.Tip() != pindexRescan) {
      nStart = GetTimeMillis();
      pwalletMain->ScanForWalletTransactions(pindexRescan, true);
      pwalletMain->SetBestChain(chainActive.GetLocator());
      nWalletDBUpdated++;
    }
  }
#endif
  // ********************************************************* Step 9: import blocks

  // scan for better chains in the block chain database, that are not yet connected in the active best chain
  CValidationState state;
  if (!ActivateBestChain(state)) {
    strErrors << "Failed to connect best block";
  }

  std::vector<boost::filesystem::path> vImportFiles;
  threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));

  // ********************************************************* Step 10: load peers

  nStart = GetTimeMillis();

  {
    CAddrDB adb;
    adb.Read(addrman);
  }

  // ********************************************************* Step 11: start node

  if (!CheckDiskSpace()) {
    return false;
  }

  if (!strErrors.str().empty()) {
    return InitError(strErrors.str());
  }

  RandAddSeedPerfmon();

  StartNode(threadGroup);
  if (fServer) {
    StartRPCThreads();
  }

#ifdef ENABLE_WALLET
  // Generate coins in the background
  if (pwalletMain) {
    GenerateBitcoins(false, pwalletMain, -1);
  }
#endif

  // ********************************************************* Step 12: finished

#ifdef ENABLE_WALLET
  if (pwalletMain) {
    // Add wallet transactions that aren't already in a block to mapTransactions
    pwalletMain->ReacceptWalletTransactions();

    // Run a thread to flush wallet periodically
    threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
  }
#endif

  return !fRequestShutdown;
}
<commit_msg>drop warnings.<commit_after>/** Initialize bitcoin.
 *  @pre Parameters should be parsed and config file should be read.
 */
bool AppInit3(boost::thread_group& threadGroup) {
  umask(077);

  // Clean shutdown on SIGTERM
  struct sigaction sa;
  sa.sa_handler = HandleSIGTERM;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sigaction(SIGTERM, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);

  // Reopen debug.log on SIGHUP
  struct sigaction sa_hup;
  sa_hup.sa_handler = HandleSIGHUP;
  sigemptyset(&sa_hup.sa_mask);
  sa_hup.sa_flags = 0;
  sigaction(SIGHUP, &sa_hup, NULL);

#if defined (__SVR4) && defined (__sun)
  // ignore SIGPIPE on Solaris
  signal(SIGPIPE, SIG_IGN);
#endif

  // ********************************************************* Step 2: parameter interactions

  // Make sure enough file descriptors are available
  int nBind = 1;
  nMaxConnections = 125;
  nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
  int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
  if (nFD < MIN_CORE_FILEDESCRIPTORS) {
    return InitError(_("Not enough file descriptors available."));
  }

  if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) {
    nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
  }

  // ********************************************************* Step 3: parameter-to-internal-flags

  // Checkmempool defaults to true in regtest mode
  mempool.setSanityCheck(Params().DefaultCheckMemPool());
  Checkpoints::fEnabled = true;

  // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
  nScriptCheckThreads = DEFAULT_SCRIPTCHECK_THREADS;
  if (nScriptCheckThreads <= 0) {
    nScriptCheckThreads += boost::thread::hardware_concurrency();
  }
  if (nScriptCheckThreads <= 1) {
    nScriptCheckThreads = 0;
  } else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) {
    nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
  }

  fServer = true;
  fPrintToConsole = false;
  fLogTimestamps = true;
  fLogIPs = false;
  setvbuf(stdout, NULL, _IOLBF, 0);
#ifdef ENABLE_WALLET
  bool fDisableWallet = false;
#endif

  // Continue to put "/P2SH/" in the coinbase to monitor
  // BIP16 support.
  // This can be removed eventually...
  const char* pszP2SH = "/P2SH/";
  COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));

#ifdef ENABLE_WALLET
  std::string strWalletFile = "wallet.dat";
#endif

  // *********************************************************
  // Step 4: application initialization: dir lock, daemonize, pidfile, debug log
  // Sanity check
  if (!InitSanityCheck()) {
    return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down."));
  }

  std::string strDataDir = GetDataDir().string();
#ifdef ENABLE_WALLET
  // Wallet file must be a plain filename without a directory
  if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)) {
    return InitError(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir));
  }
#endif

  // Make sure only a single Bitcoin process is using the data directory.
  boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
  FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
  if (file) fclose(file);
  static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
  if (!lock.try_lock()) {
    return InitError(strprintf(_(
      "Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running."), strDataDir));
  }

  if (nScriptCheckThreads) {
    for (int i = 0; i < nScriptCheckThreads - 1; i++) {
      threadGroup.create_thread(&ThreadScriptCheck);
    }
  }

  int64_t nStart;

  // ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
  if (!fDisableWallet) {
    if (!bitdb.Open(GetDataDir())) {
      // try moving the database env out of the way
      boost::filesystem::path pathDatabase = GetDataDir() / "database";
      boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
      try {
        boost::filesystem::rename(pathDatabase, pathDatabaseBak);
      } catch(boost::filesystem::filesystem_error &error) {
         // failure is ok (well, not really, but it's not worse than what we started with)
      }

      // try again
      if (!bitdb.Open(GetDataDir())) {
        // if it still fails, it probably means we can't even create the database env
        string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir);
        return InitError(msg);
      }
    }

    if (filesystem::exists(GetDataDir() / strWalletFile)) {
      CDBEnv::VerifyResult r = bitdb.Verify(strWalletFile, CWalletDB::Recover);
      if (r == CDBEnv::RECOVER_OK) {
        // Warning: wallet.dat corrupt, data salvaged!
        // Original wallet.dat saved as wallet.{timestamp}.bak in data dir; if
        // your balance or transactions are incorrect you should
        // restore from a backup.
      }
      if (r == CDBEnv::RECOVER_FAIL) {
        return InitError(_("wallet.dat corrupt, salvage failed"));
      }
    }
  }
#endif // ENABLE_WALLET
  // ********************************************************* Step 6: network initialization

  RegisterNodeSignals(GetNodeSignals());

  bool fBound = false;
  if (fListen) {
    struct in_addr inaddr_any;
    inaddr_any.s_addr = INADDR_ANY;
    fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
    fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
    if (!fBound) {
      return InitError(_("Failed to listen on any port."));
    }
  }

  // ********************************************************* Step 7: load block chain

  fReindex = false;

  // Upgrading to 0.8; hard-link the old blknnnn.dat files into /blocks/
  filesystem::path blocksDir = GetDataDir() / "blocks";
  if (!filesystem::exists(blocksDir))
  {
    filesystem::create_directories(blocksDir);
    bool linked = false;
    for (unsigned int i = 1; i < 10000; i++) {
      filesystem::path source = GetDataDir() / strprintf("blk%04u.dat", i);
      if (!filesystem::exists(source)) break;
      filesystem::path dest = blocksDir / strprintf("blk%05u.dat", i-1);
      try {
        filesystem::create_hard_link(source, dest);
        linked = true;
      } catch (filesystem::filesystem_error & e) {
        // Note: hardlink creation failing is not a disaster, it just means
        // blocks will get re-downloaded from peers.
        break;
      }
    }
    if (linked) {
      fReindex = true;
    }
  }

  // cache size calculations
  size_t nTotalCache = nDefaultDbCache << 20;
  if (nTotalCache < (nMinDbCache << 20)) {
    nTotalCache = (nMinDbCache << 20); // total cache cannot be less than nMinDbCache
  } else if (nTotalCache > (nMaxDbCache << 20)) {
    nTotalCache = (nMaxDbCache << 20); // total cache cannot be greater than nMaxDbCache
  }
  size_t nBlockTreeDBCache = nTotalCache / 8;
  if (nBlockTreeDBCache > (1 << 21)) {
    nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
  }
  nTotalCache -= nBlockTreeDBCache;
  size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache
  nTotalCache -= nCoinDBCache;
  nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes

  bool fLoaded = false;
  while (!fLoaded) {
    bool fReset = fReindex;
    std::string strLoadError;

    nStart = GetTimeMillis();
    do {
      try {
        UnloadBlockIndex();
        delete pcoinsTip;
        delete pcoinsdbview;
        delete pblocktree;

        pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
        pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
        pcoinsTip = new CCoinsViewCache(*pcoinsdbview);

        if (fReindex) {
          pblocktree->WriteReindexing(true);
        }

        if (!LoadBlockIndex()) {
          strLoadError = _("Error loading block database");
          break;
        }

        // If the loaded chain has a wrong genesis, bail out immediately
        // (we're likely using a testnet datadir, or the other way around).
        if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL) {
          return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
        }

        // Initialize the block index (no-op if non-empty database was already loaded)
        if (!InitBlockIndex()) {
          strLoadError = _("Error initializing block database");
          break;
        }

        // Check for changed -txindex state
        if (fTxIndex != false) {
          strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
          break;
        }

        if (!CVerifyDB().VerifyDB(3, 288)) {
          strLoadError = _("Corrupted block database detected");
          break;
        }
      } catch(std::exception &e) {
        strLoadError = _("Error opening block database");
        break;
      }

      fLoaded = true;
    } while(false);

    if (!fLoaded) {
      if (!fReset) {
        // reindex or return
        fReindex = true;
        fRequestShutdown = false;
        // return false;
      } else {
        return InitError(strLoadError);
      }
    }
  }

  // As LoadBlockIndex can take several minutes, it's possible the user
  // requested to kill the GUI during the last operation. If so, exit.
  // As the program has not fully started yet, Shutdown() is possibly overkill.
  if (fRequestShutdown) {
    return false;
  }

  boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
  CAutoFile est_filein = CAutoFile(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION);
  // Allowed to fail as this file IS missing on first startup.
  if (est_filein) {
    mempool.ReadFeeEstimates(est_filein);
  }

  // ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
  if (fDisableWallet) {
    pwalletMain = NULL;
  } else {
    // needed to restore wallet transaction meta data after -zapwallettxes
    std::vector<CWalletTx> vWtx;

    nStart = GetTimeMillis();
    bool fFirstRun = true;
    pwalletMain = new CWallet(strWalletFile);
    DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
    if (nLoadWalletRet != DB_LOAD_OK) {
      if (nLoadWalletRet == DB_CORRUPT) {
        strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
      } else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) {
        // Warning: error reading wallet.dat! All keys read correctly, but transaction data
        // or address book entries might be missing or incorrect.
      } else if (nLoadWalletRet == DB_TOO_NEW) {
        strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin Core") << "\n";
      } else if (nLoadWalletRet == DB_NEED_REWRITE) {
        strErrors << _("Wallet needed to be rewritten: restart Bitcoin Core to complete") << "\n";
        return InitError(strErrors.str());
      } else {
        strErrors << _("Error loading wallet.dat") << "\n";
      }
    }

    if (fFirstRun) {
      int nMaxVersion = 0;
      if (nMaxVersion == 0) {
        nMaxVersion = CLIENT_VERSION;
        pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
      } else {
        if (nMaxVersion < pwalletMain->GetVersion()) {
          strErrors << _("Cannot downgrade wallet") << "\n";
        }
      }
      pwalletMain->SetMaxVersion(nMaxVersion);

      // Create new keyUser and set as default key
      RandAddSeedPerfmon();

      CPubKey newDefaultKey;
      if (pwalletMain->GetKeyFromPool(newDefaultKey)) {
        pwalletMain->SetDefaultKey(newDefaultKey);
        if (!pwalletMain->SetAddressBook(pwalletMain->vchDefaultKey.GetID(), "", "receive")) {
          strErrors << _("Cannot write default address") << "\n";
        }
      }

      pwalletMain->SetBestChain(chainActive.GetLocator());
    }

    RegisterWallet(pwalletMain);

    CBlockIndex *pindexRescan = chainActive.Tip();
    CWalletDB walletdb(strWalletFile);
    CBlockLocator locator;

    if (walletdb.ReadBestBlock(locator)) {
      pindexRescan = chainActive.FindFork(locator);
    } else {
      pindexRescan = chainActive.Genesis();
    }

    if (chainActive.Tip() && chainActive.Tip() != pindexRescan) {
      nStart = GetTimeMillis();
      pwalletMain->ScanForWalletTransactions(pindexRescan, true);
      pwalletMain->SetBestChain(chainActive.GetLocator());
      nWalletDBUpdated++;
    }
  }
#endif
  // ********************************************************* Step 9: import blocks

  // scan for better chains in the block chain database, that are not yet connected in the active best chain
  CValidationState state;
  if (!ActivateBestChain(state)) {
    strErrors << "Failed to connect best block";
  }

  std::vector<boost::filesystem::path> vImportFiles;
  threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));

  // ********************************************************* Step 10: load peers

  nStart = GetTimeMillis();

  {
    CAddrDB adb;
    adb.Read(addrman);
  }

  // ********************************************************* Step 11: start node

  if (!CheckDiskSpace()) {
    return false;
  }

  if (!strErrors.str().empty()) {
    return InitError(strErrors.str());
  }

  RandAddSeedPerfmon();

  StartNode(threadGroup);
  if (fServer) {
    StartRPCThreads();
  }

#ifdef ENABLE_WALLET
  // Generate coins in the background
  if (pwalletMain) {
    GenerateBitcoins(false, pwalletMain, -1);
  }
#endif

  // ********************************************************* Step 12: finished

#ifdef ENABLE_WALLET
  if (pwalletMain) {
    // Add wallet transactions that aren't already in a block to mapTransactions
    pwalletMain->ReacceptWalletTransactions();

    // Run a thread to flush wallet periodically
    threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
  }
#endif

  return !fRequestShutdown;
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <map>
#include <set>
#include "bandit/bandit.h"

using std::map;
using std::set;

static bool _enabled = false;
static size_t _allocation_count = 0;
static map<void *, size_t> _outstanding_allocations;

namespace record_alloc {

void start() {
  _enabled = true;
  _allocation_count = 0;
  _outstanding_allocations.clear();
}

void stop() {
  _enabled = false;
}

set<size_t> outstanding_allocation_indices() {
  set<size_t> result;
  for (const auto &entry : _outstanding_allocations) {
    result.insert(entry.second);
  }
  return result;
}

size_t allocation_count() {
  return _allocation_count;
}

}  // namespace record_alloc

extern "C" {

static void *record_allocation(void *result) {
  if (!_enabled)
    return result;

  _outstanding_allocations[result] = _allocation_count;
  _allocation_count++;
  return result;
}

static void record_deallocation(void *pointer) {
  if (!_enabled)
    return;

  auto entry = _outstanding_allocations.find(pointer);
  if (entry != _outstanding_allocations.end()) {
    _outstanding_allocations.erase(entry);
  }
}

void *ts_record_malloc(size_t size) {
  return record_allocation(malloc(size));
}

void *ts_record_realloc(void *pointer, size_t size) {
  record_deallocation(pointer);
  return record_allocation(realloc(pointer, size));
}

void *ts_record_calloc(size_t count, size_t size) {
  return record_allocation(calloc(count, size));
}

void ts_record_free(void *pointer) {
  free(pointer);
  record_deallocation(pointer);
}

bool ts_record_allocations_toggle(bool value) {
  bool previous_value = _enabled;
  _enabled = value;
  return previous_value;
}

}
<commit_msg>Silence false-positive warning in ts_record_free<commit_after>#include <stdlib.h>
#include <map>
#include <set>
#include "bandit/bandit.h"

using std::map;
using std::set;

static bool _enabled = false;
static size_t _allocation_count = 0;
static map<void *, size_t> _outstanding_allocations;

namespace record_alloc {

void start() {
  _enabled = true;
  _allocation_count = 0;
  _outstanding_allocations.clear();
}

void stop() {
  _enabled = false;
}

set<size_t> outstanding_allocation_indices() {
  set<size_t> result;
  for (const auto &entry : _outstanding_allocations) {
    result.insert(entry.second);
  }
  return result;
}

size_t allocation_count() {
  return _allocation_count;
}

}  // namespace record_alloc

extern "C" {

static void *record_allocation(void *result) {
  if (!_enabled)
    return result;

  _outstanding_allocations[result] = _allocation_count;
  _allocation_count++;
  return result;
}

static void record_deallocation(void *pointer) {
  if (!_enabled)
    return;

  auto entry = _outstanding_allocations.find(pointer);
  if (entry != _outstanding_allocations.end()) {
    _outstanding_allocations.erase(entry);
  }
}

void *ts_record_malloc(size_t size) {
  return record_allocation(malloc(size));
}

void *ts_record_realloc(void *pointer, size_t size) {
  record_deallocation(pointer);
  return record_allocation(realloc(pointer, size));
}

void *ts_record_calloc(size_t count, size_t size) {
  return record_allocation(calloc(count, size));
}

void ts_record_free(void *pointer) {
  record_deallocation(pointer);
  free(pointer);
}

bool ts_record_allocations_toggle(bool value) {
  bool previous_value = _enabled;
  _enabled = value;
  return previous_value;
}

}
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "main.hxx"

#include <dune/stuff/common/timedlogging.hh>

using namespace Dune;
using namespace Dune::Stuff;
using namespace Dune::Stuff::Common;

void before_create()
{
  TimedLogger().get("before_create").info() << "this info should not be visible" << std::endl;
  TimedLogger().get("before_create").debug() << "this debug should not be visible" << std::endl;
  TimedLogger().get("before_create").warn() << "this warning should be visible in red" << std::endl;
}

void after_create_inner()
{
  TimedLogger().get("after_create_inner").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("after_create_inner").debug() << "this debug should not be visible" << std::endl;
  TimedLogger().get("after_create_inner").warn() << "this warning should not be visible" << std::endl;
}

void after_create()
{
  auto logger = TimedLogger().get("after_create");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  after_create_inner();
}

void fool_level_tracking_inner()
{
  TimedLogger().get("fool_level_tracking_inner").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("fool_level_tracking_inner").debug() << "this debug should be visible in yellow" << std::endl;
  TimedLogger().get("fool_level_tracking_inner").warn() << "this warning should not be visible" << std::endl;
}

void fool_level_tracking()
{
  TimedLogger().get("fool_level_tracking").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("fool_level_tracking").debug() << "this debug should be visible in yellow" << std::endl;
  TimedLogger().get("fool_level_tracking").warn() << "this warning should not be visible" << std::endl;
  fool_level_tracking_inner();
}

TEST(TimedPrefixedLogStream, all)
{
  Timer timer;
  TimedPrefixedLogStream out(timer, "prefix: ", std::cout);
  out << "sample\nline" << std::flush;
  busywait(2000);
  out << "\n" << 3 << "\n\nend" << std::endl;
} // TEST(TimedPrefixedLogStream, all)

TEST(TimedLogger, before_create)
{
  auto logger = TimedLogger().get("main");
  auto& info = logger.info();
  info << "this info should be visible in " << TimedLogging::default_info_color() << std::endl;
  logger.debug() << "this debug should not be visible" << std::endl;
  logger.warn() << "this warning should be visible in " << TimedLogging::default_warning_color() << std::endl;
  before_create();
}

TEST(TimedLogger, after_create)
{
  TimedLogger().create(10, 1, false, true, "blue", "yellow");
  auto logger = TimedLogger().get("main");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  after_create();
}

TEST(TimedLogger, fool_level_tracking)
{
  auto logger = TimedLogger().get("");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  fool_level_tracking();
}

<commit_msg>[test.common_timedlogging] do not use man.hxx<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_TEST_MAIN_CATCH_EXCEPTIONS
# define DUNE_STUFF_TEST_MAIN_CATCH_EXCEPTIONS 0
#endif

#include "config.h"

#include <dune/stuff/test/gtest/gtest.h>
#include <dune/stuff/common/timedlogging.hh>

#include "common.hh"

using namespace Dune;
using namespace Dune::Stuff;
using namespace Dune::Stuff::Common;

void before_create()
{
  TimedLogger().get("before_create").info() << "this info should not be visible" << std::endl;
  TimedLogger().get("before_create").debug() << "this debug should not be visible" << std::endl;
  TimedLogger().get("before_create").warn() << "this warning should be visible in red" << std::endl;
}

void after_create_inner()
{
  TimedLogger().get("after_create_inner").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("after_create_inner").debug() << "this debug should not be visible" << std::endl;
  TimedLogger().get("after_create_inner").warn() << "this warning should not be visible" << std::endl;
}

void after_create()
{
  auto logger = TimedLogger().get("after_create");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  after_create_inner();
}

void fool_level_tracking_inner()
{
  TimedLogger().get("fool_level_tracking_inner").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("fool_level_tracking_inner").debug() << "this debug should be visible in yellow" << std::endl;
  TimedLogger().get("fool_level_tracking_inner").warn() << "this warning should not be visible" << std::endl;
}

void fool_level_tracking()
{
  TimedLogger().get("fool_level_tracking").info() << "this info should be visible in blue" << std::endl;
  TimedLogger().get("fool_level_tracking").debug() << "this debug should be visible in yellow" << std::endl;
  TimedLogger().get("fool_level_tracking").warn() << "this warning should not be visible" << std::endl;
  fool_level_tracking_inner();
}

TEST(TimedPrefixedLogStream, all)
{
  Timer timer;
  TimedPrefixedLogStream out(timer, "prefix: ", std::cout);
  out << "sample\nline" << std::flush;
  busywait(2000);
  out << "\n" << 3 << "\n\nend" << std::endl;
} // TEST(TimedPrefixedLogStream, all)

TEST(TimedLogger, before_create)
{
  auto logger = TimedLogger().get("main");
  auto& info = logger.info();
  info << "this info should be visible in " << TimedLogging::default_info_color() << std::endl;
  logger.debug() << "this debug should not be visible" << std::endl;
  logger.warn() << "this warning should be visible in " << TimedLogging::default_warning_color() << std::endl;
  before_create();
}

TEST(TimedLogger, after_create)
{
  TimedLogger().create(10, 1, false, true, "blue", "yellow");
  auto logger = TimedLogger().get("main");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  after_create();
}

TEST(TimedLogger, fool_level_tracking)
{
  auto logger = TimedLogger().get("");
  logger.info() << "this info should be visible in blue" << std::endl;
  logger.debug() << "this debug should be visible in yellow" << std::endl;
  logger.warn() << "this warning should not be visible" << std::endl;
  fool_level_tracking();
}

int main(int argc, char** argv)
{
#if DUNE_STUFF_TEST_MAIN_CATCH_EXCEPTIONS
  try {
#endif
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
#if DUNE_STUFF_TEST_MAIN_CATCH_EXCEPTIONS
  } catch (Dune::Exception& e) {
    std::cerr << "\nDune reported error: " << e.what() << std::endl;
    std::abort();
  } catch (std::exception& e) {
    std::cerr << "\n" << e.what() << std::endl;
    std::abort();
  } catch (...) {
    std::cerr << "Unknown exception thrown!" << std::endl;
    std::abort();
  } // try
#endif // DUNE_STUFF_TEST_MAIN_CATCH_EXCEPTIONS
} // ... main(...)
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s

// CHECK: @"\01?a@@3HA"
// CHECK: @"\01?b@N@@3HA"
// CHECK: @"\01?anonymous@?A@N@@3HA"
// CHECK: @c
// CHECK: @"\01?d@foo@@0FB"
// CHECK: @"\01?e@foo@@1JC"
// CHECK: @"\01?f@foo@@2DD"
// CHECK: @"\01?g@bar@@2HA"
// CHECK: @"\01?h1@@3QAHA"
// CHECK: @"\01?h2@@3QBHB"
// CHECK: @"\01?i@@3PAY0BE@HA"
// CHECK: @"\01?j@@3P6GHCE@ZA"
// X64: @"\01?k@@3PETfoo@@DET1@"
// CHECK: @"\01?l@@3P8foo@@AEHH@ZQ1@"
// CHECK: @"\01?color1@@3PANA"
// CHECK: @"\01?color2@@3QBNB"
// CHECK: @"\01?color3@@3QAY02$$CBNA"
// CHECK: @"\01?color4@@3QAY02$$CBNA"
// X64: @"\01?memptr1@@3RESB@@HES1@"
// X64: @"\01?memptr2@@3PESB@@HES1@"
// X64: @"\01?memptr3@@3REQB@@HEQ1@"
// X64: @"\01?funmemptr1@@3RESB@@R6AHXZES1@"
// X64: @"\01?funmemptr2@@3PESB@@R6AHXZES1@"
// X64: @"\01?funmemptr3@@3REQB@@P6AHXZEQ1@"
// X64: @"\01?memptrtofun1@@3R8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun2@@3P8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun3@@3P8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun4@@3R8B@@EAAHXZEQ1@"
// X64: @"\01?memptrtofun5@@3P8B@@EAA?CHXZEQ1@"
// X64: @"\01?memptrtofun6@@3P8B@@EAA?BHXZEQ1@"
// X64: @"\01?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@"
// X64: @"\01?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@"
// X64: @"\01?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@"

int a;

namespace N {
  int b;

  namespace {
    int anonymous;
  }
}

static int c;
int _c(void) {return N::anonymous + c;}
// CHECK: @"\01?_c@@YAHXZ"
// X64: @"\01?_c@@YAHXZ"

class foo {
  static const short d;
protected:
  static volatile long e;
public:
  static const volatile char f;
  int operator+(int a);
  foo(){}
//CHECK: @"\01??0foo@@QAE@XZ"
//X64: @"\01??0foo@@QEAA@XZ"

  ~foo(){}
//CHECK: @"\01??1foo@@QAE@XZ"
//X64: @"\01??1foo@@QEAA@XZ

  foo(int i){}
//CHECK: @"\01??0foo@@QAE@H@Z"
//X64: @"\01??0foo@@QEAA@H@Z"

  foo(char *q){}
//CHECK: @"\01??0foo@@QAE@PAD@Z"
//X64: @"\01??0foo@@QEAA@PEAD@Z"

  static foo* static_method() { return 0; }

}f,s1(1),s2((char*)0);

typedef foo (foo2);

struct bar {
  static int g;
};

union baz {
  int a;
  char b;
  double c;
};

enum quux {
  qone,
  qtwo,
  qthree
};

foo bar() { return foo(); }
//CHECK: @"\01?bar@@YA?AVfoo@@XZ"
//X64: @"\01?bar@@YA?AVfoo@@XZ"

int foo::operator+(int a) {
//CHECK: @"\01??Hfoo@@QAEHH@Z"
//X64: @"\01??Hfoo@@QEAAHH@Z"

  foo::static_method();
//CHECK: @"\01?static_method@foo@@SAPAV1@XZ"
//X64: @"\01?static_method@foo@@SAPEAV1@XZ"
  bar();
  return a;
}

const short foo::d = 0;
volatile long foo::e;
const volatile char foo::f = 'C';

int bar::g;

extern int * const h1 = &a;
extern const int * const h2 = &a;

int i[10][20];

int (__stdcall *j)(signed char, unsigned char);

const volatile char foo2::*k;

int (foo2::*l)(int);

// Static functions are mangled, too.
// Also make sure calling conventions, arglists, and throw specs work.
static void __stdcall alpha(float a, double b) throw() {}
bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) {
// CHECK: @"\01?beta@@YI_N_J_W@Z"
// X64: @"\01?beta@@YA_N_J_W@Z"
  alpha(0.f, 0.0);
  return false;
}

// CHECK: @"\01?alpha@@YGXMN@Z"
// X64: @"\01?alpha@@YAXMN@Z"

// Make sure tag-type mangling works.
void gamma(class foo, struct bar, union baz, enum quux) {}
// CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"
// X64: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"

// Make sure pointer/reference-type mangling works.
void delta(int * const a, const long &) {}
// CHECK: @"\01?delta@@YAXQAHABJ@Z"
// X64: @"\01?delta@@YAXQEAHAEBJ@Z"

// Array mangling.
void epsilon(int a[][10][20]) {}
// CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z"
// X64: @"\01?epsilon@@YAXQEAY19BE@H@Z"

void zeta(int (*)(int, int)) {}
// CHECK: @"\01?zeta@@YAXP6AHHH@Z@Z"
// X64: @"\01?zeta@@YAXP6AHHH@Z@Z"

// Blocks mangling (Clang extension). A block should be mangled slightly
// differently from a similar function pointer.
void eta(int (^)(int, int)) {}
// CHECK: @"\01?eta@@YAXP_EAHHH@Z@Z"

typedef int theta_arg(int,int);
void theta(theta_arg^ block) {}
// CHECK: @"\01?theta@@YAXP_EAHHH@Z@Z"

void operator_new_delete() {
  char *ptr = new char;
// CHECK: @"\01??2@YAPAXI@Z"

  delete ptr;
// CHECK: @"\01??3@YAXPAX@Z"

  char *array = new char[42];
// CHECK: @"\01??_U@YAPAXI@Z"

  delete [] array;
// CHECK: @"\01??_V@YAXPAX@Z"
}

// PR13022
void (redundant_parens)();
void redundant_parens_use() { redundant_parens(); }
// CHECK: @"\01?redundant_parens@@YAXXZ"
// X64: @"\01?redundant_parens@@YAXXZ"

// PR13047
typedef double RGB[3];
RGB color1;
extern const RGB color2 = {};
extern RGB const color3[5] = {};
extern RGB const ((color4)[5]) = {};

struct B;
volatile int B::* volatile memptr1;
volatile int B::* memptr2;
int B::* volatile memptr3;
typedef int (*fun)();
volatile fun B::* volatile funmemptr1;
volatile fun B::* funmemptr2;
fun B::* volatile funmemptr3;
void (B::* volatile memptrtofun1)();
const void (B::* memptrtofun2)();
volatile void (B::* memptrtofun3)();
int (B::* volatile memptrtofun4)();
volatile int (B::* memptrtofun5)();
const int (B::* memptrtofun6)();
fun (B::* volatile memptrtofun7)();
volatile fun (B::* memptrtofun8)();
const fun (B::* memptrtofun9)();

// PR12603
enum E {};
// CHECK: "\01?fooE@@YA?AW4E@@XZ"
// X64: "\01?fooE@@YA?AW4E@@XZ"
E fooE() { return E(); }

class X {};
// CHECK: "\01?fooX@@YA?AVX@@XZ"
// X64: "\01?fooX@@YA?AVX@@XZ"
X fooX() { return X(); }

namespace PR13182 {
  extern char s0[];
  // CHECK: @"\01?s0@PR13182@@3PADA"
  extern char s1[42];
  // CHECK: @"\01?s1@PR13182@@3PADA"
  extern const char s2[];
  // CHECK: @"\01?s2@PR13182@@3QBDB"
  extern const char s3[42];
  // CHECK: @"\01?s3@PR13182@@3QBDB"
  extern volatile char s4[];
  // CHECK: @"\01?s4@PR13182@@3RCDC"
  extern const volatile char s5[];
  // CHECK: @"\01?s5@PR13182@@3SDDD"
  extern const char* const* s6;
  // CHECK: @"\01?s6@PR13182@@3PBQBDB"

  char foo() {
    return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0];
  }
}
<commit_msg>Add back a test that was removed in r188450<commit_after>// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s

// CHECK: @"\01?a@@3HA"
// CHECK: @"\01?b@N@@3HA"
// CHECK: @"\01?anonymous@?A@N@@3HA"
// CHECK: @c
// CHECK: @"\01?d@foo@@0FB"
// CHECK: @"\01?e@foo@@1JC"
// CHECK: @"\01?f@foo@@2DD"
// CHECK: @"\01?g@bar@@2HA"
// CHECK: @"\01?h1@@3QAHA"
// CHECK: @"\01?h2@@3QBHB"
// CHECK: @"\01?i@@3PAY0BE@HA"
// CHECK: @"\01?j@@3P6GHCE@ZA"
// CHECK: @"\01?k@@3PTfoo@@DT1@"
// X64: @"\01?k@@3PETfoo@@DET1@"
// CHECK: @"\01?l@@3P8foo@@AEHH@ZQ1@"
// CHECK: @"\01?color1@@3PANA"
// CHECK: @"\01?color2@@3QBNB"
// CHECK: @"\01?color3@@3QAY02$$CBNA"
// CHECK: @"\01?color4@@3QAY02$$CBNA"
// X64: @"\01?memptr1@@3RESB@@HES1@"
// X64: @"\01?memptr2@@3PESB@@HES1@"
// X64: @"\01?memptr3@@3REQB@@HEQ1@"
// X64: @"\01?funmemptr1@@3RESB@@R6AHXZES1@"
// X64: @"\01?funmemptr2@@3PESB@@R6AHXZES1@"
// X64: @"\01?funmemptr3@@3REQB@@P6AHXZEQ1@"
// X64: @"\01?memptrtofun1@@3R8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun2@@3P8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun3@@3P8B@@EAAXXZEQ1@"
// X64: @"\01?memptrtofun4@@3R8B@@EAAHXZEQ1@"
// X64: @"\01?memptrtofun5@@3P8B@@EAA?CHXZEQ1@"
// X64: @"\01?memptrtofun6@@3P8B@@EAA?BHXZEQ1@"
// X64: @"\01?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@"
// X64: @"\01?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@"
// X64: @"\01?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@"

int a;

namespace N {
  int b;

  namespace {
    int anonymous;
  }
}

static int c;
int _c(void) {return N::anonymous + c;}
// CHECK: @"\01?_c@@YAHXZ"
// X64: @"\01?_c@@YAHXZ"

class foo {
  static const short d;
protected:
  static volatile long e;
public:
  static const volatile char f;
  int operator+(int a);
  foo(){}
//CHECK: @"\01??0foo@@QAE@XZ"
//X64: @"\01??0foo@@QEAA@XZ"

  ~foo(){}
//CHECK: @"\01??1foo@@QAE@XZ"
//X64: @"\01??1foo@@QEAA@XZ

  foo(int i){}
//CHECK: @"\01??0foo@@QAE@H@Z"
//X64: @"\01??0foo@@QEAA@H@Z"

  foo(char *q){}
//CHECK: @"\01??0foo@@QAE@PAD@Z"
//X64: @"\01??0foo@@QEAA@PEAD@Z"

  static foo* static_method() { return 0; }

}f,s1(1),s2((char*)0);

typedef foo (foo2);

struct bar {
  static int g;
};

union baz {
  int a;
  char b;
  double c;
};

enum quux {
  qone,
  qtwo,
  qthree
};

foo bar() { return foo(); }
//CHECK: @"\01?bar@@YA?AVfoo@@XZ"
//X64: @"\01?bar@@YA?AVfoo@@XZ"

int foo::operator+(int a) {
//CHECK: @"\01??Hfoo@@QAEHH@Z"
//X64: @"\01??Hfoo@@QEAAHH@Z"

  foo::static_method();
//CHECK: @"\01?static_method@foo@@SAPAV1@XZ"
//X64: @"\01?static_method@foo@@SAPEAV1@XZ"
  bar();
  return a;
}

const short foo::d = 0;
volatile long foo::e;
const volatile char foo::f = 'C';

int bar::g;

extern int * const h1 = &a;
extern const int * const h2 = &a;

int i[10][20];

int (__stdcall *j)(signed char, unsigned char);

const volatile char foo2::*k;

int (foo2::*l)(int);

// Static functions are mangled, too.
// Also make sure calling conventions, arglists, and throw specs work.
static void __stdcall alpha(float a, double b) throw() {}
bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) {
// CHECK: @"\01?beta@@YI_N_J_W@Z"
// X64: @"\01?beta@@YA_N_J_W@Z"
  alpha(0.f, 0.0);
  return false;
}

// CHECK: @"\01?alpha@@YGXMN@Z"
// X64: @"\01?alpha@@YAXMN@Z"

// Make sure tag-type mangling works.
void gamma(class foo, struct bar, union baz, enum quux) {}
// CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"
// X64: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z"

// Make sure pointer/reference-type mangling works.
void delta(int * const a, const long &) {}
// CHECK: @"\01?delta@@YAXQAHABJ@Z"
// X64: @"\01?delta@@YAXQEAHAEBJ@Z"

// Array mangling.
void epsilon(int a[][10][20]) {}
// CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z"
// X64: @"\01?epsilon@@YAXQEAY19BE@H@Z"

void zeta(int (*)(int, int)) {}
// CHECK: @"\01?zeta@@YAXP6AHHH@Z@Z"
// X64: @"\01?zeta@@YAXP6AHHH@Z@Z"

// Blocks mangling (Clang extension). A block should be mangled slightly
// differently from a similar function pointer.
void eta(int (^)(int, int)) {}
// CHECK: @"\01?eta@@YAXP_EAHHH@Z@Z"

typedef int theta_arg(int,int);
void theta(theta_arg^ block) {}
// CHECK: @"\01?theta@@YAXP_EAHHH@Z@Z"

void operator_new_delete() {
  char *ptr = new char;
// CHECK: @"\01??2@YAPAXI@Z"

  delete ptr;
// CHECK: @"\01??3@YAXPAX@Z"

  char *array = new char[42];
// CHECK: @"\01??_U@YAPAXI@Z"

  delete [] array;
// CHECK: @"\01??_V@YAXPAX@Z"
}

// PR13022
void (redundant_parens)();
void redundant_parens_use() { redundant_parens(); }
// CHECK: @"\01?redundant_parens@@YAXXZ"
// X64: @"\01?redundant_parens@@YAXXZ"

// PR13047
typedef double RGB[3];
RGB color1;
extern const RGB color2 = {};
extern RGB const color3[5] = {};
extern RGB const ((color4)[5]) = {};

struct B;
volatile int B::* volatile memptr1;
volatile int B::* memptr2;
int B::* volatile memptr3;
typedef int (*fun)();
volatile fun B::* volatile funmemptr1;
volatile fun B::* funmemptr2;
fun B::* volatile funmemptr3;
void (B::* volatile memptrtofun1)();
const void (B::* memptrtofun2)();
volatile void (B::* memptrtofun3)();
int (B::* volatile memptrtofun4)();
volatile int (B::* memptrtofun5)();
const int (B::* memptrtofun6)();
fun (B::* volatile memptrtofun7)();
volatile fun (B::* memptrtofun8)();
const fun (B::* memptrtofun9)();

// PR12603
enum E {};
// CHECK: "\01?fooE@@YA?AW4E@@XZ"
// X64: "\01?fooE@@YA?AW4E@@XZ"
E fooE() { return E(); }

class X {};
// CHECK: "\01?fooX@@YA?AVX@@XZ"
// X64: "\01?fooX@@YA?AVX@@XZ"
X fooX() { return X(); }

namespace PR13182 {
  extern char s0[];
  // CHECK: @"\01?s0@PR13182@@3PADA"
  extern char s1[42];
  // CHECK: @"\01?s1@PR13182@@3PADA"
  extern const char s2[];
  // CHECK: @"\01?s2@PR13182@@3QBDB"
  extern const char s3[42];
  // CHECK: @"\01?s3@PR13182@@3QBDB"
  extern volatile char s4[];
  // CHECK: @"\01?s4@PR13182@@3RCDC"
  extern const volatile char s5[];
  // CHECK: @"\01?s5@PR13182@@3SDDD"
  extern const char* const* s6;
  // CHECK: @"\01?s6@PR13182@@3PBQBDB"

  char foo() {
    return s0[0] + s1[0] + s2[0] + s3[0] + s4[0] + s5[0] + s6[0][0];
  }
}
<|endoftext|>


<commit_before>#pragma once

#include <memory>
#include <vector>

#include "Runtime/Particle/IElement.hpp"

/* Documentation at: https://wiki.axiodl.com/w/Particle_Script#Int_Elements */

namespace urde {

class CIEKeyframeEmitter : public CIntElement {
  u32 x4_percent;
  u32 x8_unk1;
  bool xc_loop;
  bool xd_unk2;
  u32 x10_loopEnd;
  u32 x14_loopStart;
  std::vector<int> x18_keys;

public:
  explicit CIEKeyframeEmitter(CInputStream& in);
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEDeath : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEDeath(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEClamp : public CIntElement {
  std::unique_ptr<CIntElement> x4_min;
  std::unique_ptr<CIntElement> x8_max;
  std::unique_ptr<CIntElement> xc_val;

public:
  CIEClamp(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_min(std::move(a)), x8_max(std::move(b)), xc_val(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIETimeChain : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;
  std::unique_ptr<CIntElement> xc_swFrame;

public:
  CIETimeChain(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_a(std::move(a)), x8_b(std::move(b)), xc_swFrame(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEAdd : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEAdd(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b) : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEConstant : public CIntElement {
  int x4_val;

public:
  explicit CIEConstant(int val) : x4_val(val) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEImpulse : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;

public:
  explicit CIEImpulse(std::unique_ptr<CIntElement>&& a) : x4_a(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIELifetimePercent : public CIntElement {
  std::unique_ptr<CIntElement> x4_percentVal;

public:
  explicit CIELifetimePercent(std::unique_ptr<CIntElement>&& a) : x4_percentVal(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEInitialRandom : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEInitialRandom(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEPulse : public CIntElement {
  std::unique_ptr<CIntElement> x4_aDuration;
  std::unique_ptr<CIntElement> x8_bDuration;
  std::unique_ptr<CIntElement> xc_aVal;
  std::unique_ptr<CIntElement> x10_bVal;

public:
  CIEPulse(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c,
           std::unique_ptr<CIntElement>&& d)
  : x4_aDuration(std::move(a)), x8_bDuration(std::move(b)), xc_aVal(std::move(c)), x10_bVal(std::move(d)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEMultiply : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEMultiply(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIESampleAndHold : public CIntElement {
  std::unique_ptr<CIntElement> x4_sampleSource;
  mutable int x8_nextSampleFrame = 0;
  std::unique_ptr<CIntElement> xc_waitFramesMin;
  std::unique_ptr<CIntElement> x10_waitFramesMax;
  mutable int x14_holdVal;

public:
  CIESampleAndHold(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_sampleSource(std::move(a)), xc_waitFramesMin(std::move(b)), x10_waitFramesMax(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIERandom : public CIntElement {
  std::unique_ptr<CIntElement> x4_min;
  std::unique_ptr<CIntElement> x8_max;

public:
  CIERandom(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_min(std::move(a)), x8_max(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIETimeScale : public CIntElement {
  std::unique_ptr<CRealElement> x4_a;

public:
  explicit CIETimeScale(std::unique_ptr<CRealElement>&& a) : x4_a(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetCumulativeParticleCount : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetActiveParticleCount : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetEmitterTime : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEModulo : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEModulo(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIESubtract : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIESubtract(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIERealToInt final : public CIntElement {
  std::unique_ptr<CRealElement> x4_a;
  std::unique_ptr<CRealElement> x8_b;

public:
  explicit CIERealToInt(std::unique_ptr<CRealElement>&& a, std::unique_ptr<CRealElement>&& b)
  : x4_a{std::move(a)}, x8_b{std::move(b)} {}

  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

} // namespace urde
<commit_msg>CIntElement: Initialize x14_holdVal in CIESampleAndHold<commit_after>#pragma once

#include <memory>
#include <vector>

#include "Runtime/Particle/IElement.hpp"

/* Documentation at: https://wiki.axiodl.com/w/Particle_Script#Int_Elements */

namespace urde {

class CIEKeyframeEmitter : public CIntElement {
  u32 x4_percent;
  u32 x8_unk1;
  bool xc_loop;
  bool xd_unk2;
  u32 x10_loopEnd;
  u32 x14_loopStart;
  std::vector<int> x18_keys;

public:
  explicit CIEKeyframeEmitter(CInputStream& in);
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEDeath : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEDeath(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEClamp : public CIntElement {
  std::unique_ptr<CIntElement> x4_min;
  std::unique_ptr<CIntElement> x8_max;
  std::unique_ptr<CIntElement> xc_val;

public:
  CIEClamp(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_min(std::move(a)), x8_max(std::move(b)), xc_val(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIETimeChain : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;
  std::unique_ptr<CIntElement> xc_swFrame;

public:
  CIETimeChain(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_a(std::move(a)), x8_b(std::move(b)), xc_swFrame(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEAdd : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEAdd(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b) : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEConstant : public CIntElement {
  int x4_val;

public:
  explicit CIEConstant(int val) : x4_val(val) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEImpulse : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;

public:
  explicit CIEImpulse(std::unique_ptr<CIntElement>&& a) : x4_a(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIELifetimePercent : public CIntElement {
  std::unique_ptr<CIntElement> x4_percentVal;

public:
  explicit CIELifetimePercent(std::unique_ptr<CIntElement>&& a) : x4_percentVal(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEInitialRandom : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEInitialRandom(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEPulse : public CIntElement {
  std::unique_ptr<CIntElement> x4_aDuration;
  std::unique_ptr<CIntElement> x8_bDuration;
  std::unique_ptr<CIntElement> xc_aVal;
  std::unique_ptr<CIntElement> x10_bVal;

public:
  CIEPulse(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c,
           std::unique_ptr<CIntElement>&& d)
  : x4_aDuration(std::move(a)), x8_bDuration(std::move(b)), xc_aVal(std::move(c)), x10_bVal(std::move(d)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEMultiply : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEMultiply(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIESampleAndHold : public CIntElement {
  std::unique_ptr<CIntElement> x4_sampleSource;
  mutable int x8_nextSampleFrame = 0;
  std::unique_ptr<CIntElement> xc_waitFramesMin;
  std::unique_ptr<CIntElement> x10_waitFramesMax;
  mutable int x14_holdVal = 0;

public:
  CIESampleAndHold(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)
  : x4_sampleSource(std::move(a)), xc_waitFramesMin(std::move(b)), x10_waitFramesMax(std::move(c)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIERandom : public CIntElement {
  std::unique_ptr<CIntElement> x4_min;
  std::unique_ptr<CIntElement> x8_max;

public:
  CIERandom(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_min(std::move(a)), x8_max(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIETimeScale : public CIntElement {
  std::unique_ptr<CRealElement> x4_a;

public:
  explicit CIETimeScale(std::unique_ptr<CRealElement>&& a) : x4_a(std::move(a)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetCumulativeParticleCount : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetActiveParticleCount : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEGetEmitterTime : public CIntElement {
public:
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIEModulo : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIEModulo(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIESubtract : public CIntElement {
  std::unique_ptr<CIntElement> x4_a;
  std::unique_ptr<CIntElement> x8_b;

public:
  CIESubtract(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b)
  : x4_a(std::move(a)), x8_b(std::move(b)) {}
  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

class CIERealToInt final : public CIntElement {
  std::unique_ptr<CRealElement> x4_a;
  std::unique_ptr<CRealElement> x8_b;

public:
  explicit CIERealToInt(std::unique_ptr<CRealElement>&& a, std::unique_ptr<CRealElement>&& b)
  : x4_a{std::move(a)}, x8_b{std::move(b)} {}

  bool GetValue(int frame, int& valOut) const override;
  int GetMaxValue() const override;
};

} // namespace urde
<|endoftext|>


<commit_before>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

/*

standard ODE geometry primitives: public API and pairwise collision functions.

the rule is that only the low level primitive collision functions should set
dContactGeom::g1 and dContactGeom::g2.

*/

#include <ode/common.h>
#include <ode/collision.h>
#include <ode/matrix.h>
#include <ode/rotation.h>
#include <ode/odemath.h>
#include "collision_kernel.h"
#include "collision_std.h"
#include "collision_util.h"

#ifdef _MSC_VER
#pragma warning(disable:4291)  // for VC++, no complaints about "no matching operator delete found"
#endif

//****************************************************************************
// plane public API

static void make_sure_plane_normal_has_unit_length (dxPlane *g)
{
  dReal l = g->p[0]*g->p[0] + g->p[1]*g->p[1] + g->p[2]*g->p[2];
  if (l > 0) {
    l = dRecipSqrt(l);
    g->p[0] *= l;
    g->p[1] *= l;
    g->p[2] *= l;
    g->p[3] *= l;
  }
  else {
    g->p[0] = 1;
    g->p[1] = 0;
    g->p[2] = 0;
    g->p[3] = 0;
  }
}

dxPlane::dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) :
  dxGeom (space,0)
{
  type = dPlaneClass;
  p[0] = a;
  p[1] = b;
  p[2] = c;
  p[3] = d;
  make_sure_plane_normal_has_unit_length (this);
}

void dxPlane::computeAABB()
{
  // @@@ planes that have normal vectors aligned along an axis can use a
  // @@@ less comprehensive (half space) bounding box.
  aabb[0] = -dInfinity;
  aabb[1] = dInfinity;
  aabb[2] = -dInfinity;
  aabb[3] = dInfinity;
  aabb[4] = -dInfinity;
  aabb[5] = dInfinity;
}

dGeomID dCreatePlane (dSpaceID space,
		      dReal a, dReal b, dReal c, dReal d)
{
  return new dxPlane (space,a,b,c,d);
}

void dGeomPlaneSetParams (dGeomID g, dReal a, dReal b, dReal c, dReal d)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  p->p[0] = a;
  p->p[1] = b;
  p->p[2] = c;
  p->p[3] = d;
  make_sure_plane_normal_has_unit_length (p);
  dGeomMoved (g);
}

void dGeomPlaneGetParams (dGeomID g, dVector4 result)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  result[0] = p->p[0];
  result[1] = p->p[1];
  result[2] = p->p[2];
  result[3] = p->p[3];
}

dReal dGeomPlanePointDepth (dGeomID g, dReal x, dReal y, dReal z)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  return p->p[3] - p->p[0]*x - p->p[1]*y - p->p[2]*z;
}
<commit_msg>Added half-space optimisation by Andres James, an improvement for AABBs of planes aligned along a world axis.<commit_after>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

/*

standard ODE geometry primitives: public API and pairwise collision functions.

the rule is that only the low level primitive collision functions should set
dContactGeom::g1 and dContactGeom::g2.

*/

#include <ode/common.h>
#include <ode/collision.h>
#include <ode/matrix.h>
#include <ode/rotation.h>
#include <ode/odemath.h>
#include "collision_kernel.h"
#include "collision_std.h"
#include "collision_util.h"

#ifdef _MSC_VER
#pragma warning(disable:4291)  // for VC++, no complaints about "no matching operator delete found"
#endif

//****************************************************************************
// plane public API

static void make_sure_plane_normal_has_unit_length (dxPlane *g)
{
  dReal l = g->p[0]*g->p[0] + g->p[1]*g->p[1] + g->p[2]*g->p[2];
  if (l > 0) {
    l = dRecipSqrt(l);
    g->p[0] *= l;
    g->p[1] *= l;
    g->p[2] *= l;
    g->p[3] *= l;
  }
  else {
    g->p[0] = 1;
    g->p[1] = 0;
    g->p[2] = 0;
    g->p[3] = 0;
  }
}

dxPlane::dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) :
  dxGeom (space,0)
{
  type = dPlaneClass;
  p[0] = a;
  p[1] = b;
  p[2] = c;
  p[3] = d;
  make_sure_plane_normal_has_unit_length (this);
}

void dxPlane::computeAABB()
{
	aabb[0] = -dInfinity;
	aabb[1] = dInfinity;
	aabb[2] = -dInfinity;
	aabb[3] = dInfinity;
	aabb[4] = -dInfinity;
	aabb[5] = dInfinity;

	// Planes that have normal vectors aligned along an axis can use a
	// less comprehensive (half space) bounding box.

	if ( p[1] == 0.0f && p[2] == 0.0f ) {
		// normal aligned with x-axis
		aabb[0] = (p[0] > 0) ? -dInfinity : -p[3];
		aabb[1] = (p[0] > 0) ? p[3] : dInfinity;
	} else
	if ( p[0] == 0.0f && p[2] == 0.0f ) {
		// normal aligned with y-axis
		aabb[2] = (p[1] > 0) ? -dInfinity : -p[3];
		aabb[3] = (p[1] > 0) ? p[3] : dInfinity;
	} else
	if ( p[0] == 0.0f && p[1] == 0.0f ) {
		// normal aligned with z-axis
		aabb[4] = (p[2] > 0) ? -dInfinity : -p[3];
		aabb[5] = (p[2] > 0) ? p[3] : dInfinity;
	}
}

dGeomID dCreatePlane (dSpaceID space,
		      dReal a, dReal b, dReal c, dReal d)
{
  return new dxPlane (space,a,b,c,d);
}

void dGeomPlaneSetParams (dGeomID g, dReal a, dReal b, dReal c, dReal d)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  p->p[0] = a;
  p->p[1] = b;
  p->p[2] = c;
  p->p[3] = d;
  make_sure_plane_normal_has_unit_length (p);
  dGeomMoved (g);
}

void dGeomPlaneGetParams (dGeomID g, dVector4 result)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  result[0] = p->p[0];
  result[1] = p->p[1];
  result[2] = p->p[2];
  result[3] = p->p[3];
}

dReal dGeomPlanePointDepth (dGeomID g, dReal x, dReal y, dReal z)
{
  dUASSERT (g && g->type == dPlaneClass,"argument not a plane");
  dxPlane *p = (dxPlane*) g;
  return p->p[3] - p->p[0]*x - p->p[1]*y - p->p[2]*z;
}
<|endoftext|>