<commit_before>#ifndef cipClientCapi_h
#define cipClientCapi_h

/* $Header$ */

/**
 * @file cipClientCapi.H
 * @brief Cronus & IP eCMD Extension

 * Extension Owner : Chris Engel
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <ecmdReturnCodes.H>
#include <ecmdStructs.H>
#include <ecmdDataBuffer.H>
#include <cipStructs.H>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

/* Functions in here are defined as extern C for the following reasons:
 1)  Keeps Function names small by preventing C++ "mangling"
 2)  Allows (C-based) perl interpreter to access these functions

*/
extern "C" {

/** @name Load/Unload Functions */
//@{

/**
 @brief Initialize eCMD CIP Extension DLL
 @retval ECMD_SUCCESS if successful load
 @retval ECMD_INVALID_DLL_VERSION if Dll version loaded doesn't match client version
 @retval nonzero if unsuccessful
 @post eCMD CIP Extension is initialized and version checked

*/
uint32_t cipInitExtension();

//@}

/** @name Processor Functions */
//@{

/**
 @brief Start Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStartInstructions (ecmdChipTarget & i_target);

/**
 @brief Start Instructions on all configured processors
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStartAllInstructions ();

/**
 @brief Stop Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStopInstructions (ecmdChipTarget & i_target);

/**
 @brief Stop All Instructions
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStopAllInstructions ();

/**
 @brief Step Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_steps Number of steps to execute
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStepInstructions (ecmdChipTarget & i_target, uint32_t i_steps);

/**
 @brief Set a hardware breakpoint in Processor using a real address
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_address Address to set breakpoint at
 @param i_type Type of breakpoint to set
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipSetBreakpoint (ecmdChipTarget & i_target, uint64_t i_address, ecmdBreakpointType_t & i_type);

/**
 @brief Clear a hardware breakpoint from Processor using a real address
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_address Address to clear breakpoint at
 @param i_type Type of breakpoint to set
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipClearBreakpoint (ecmdChipTarget & i_target, uint64_t i_address, ecmdBreakpointType_t & i_type);

/**
 @brief Reads the selected Processor Architected VMX Register (VPR) into the data buffer
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_vprNum Number of vpr to read from
 @param o_data DataBuffer object that holds data read from vpr

*/
uint32_t cipGetVpr (ecmdChipTarget & i_target, uint32_t i_vprNum, ecmdDataBuffer & o_data);

/**
 @brief Reads the selected Processor Architected VMX Register (VPR) into the data buffers
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param io_entries List of entries to fetch ecmdIndexEntry.index field must be filled in

 The return value of this function is set to the first non-zero return code found when
  retrieving multiple entries.  The entry that caused the failure in the list will also be marked with
  the same return code. That data and all subsequent entries in the list will not be fetched and the data
  should be considered invalid.

*/
uint32_t cipGetVprMultiple (ecmdChipTarget & i_target, std::list<ecmdIndexEntry> & io_entries);

/**
 @brief Writes the data buffer into the selected Processor Architected VMX Register (VPR)
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_SUCCESS if successful
 @retval ECMD_DATA_OVERFLOW Too much data was provided for a write
 @retval ECMD_DATA_UNDERFLOW  Too little data was provided to a write function
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disaled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_vprNum Number of vpr to write to
 @param i_data DataBuffer object that holds data to write into vpr

*/
uint32_t cipPutVpr (ecmdChipTarget & i_target, uint32_t i_vprNum, ecmdDataBuffer & i_data);

/**
 @brief Writes the data buffer into the selected Processor Architected VMX Register (VPR)
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_SUCCESS if successful
 @retval ECMD_DATA_OVERFLOW Too much data was provided for a write
 @retval ECMD_DATA_UNDERFLOW  Too little data was provided to a write function
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_entries List of entries to write all ecmdIndexEntry fields must be filled in

 The return value of this function is set to the first non-zero return code found when
  writing multiple entries.  The function will NOT continue through all subsequent entries.

*/
uint32_t cipPutVprMultiple (ecmdChipTarget & i_target, std::list<ecmdIndexEntry> & i_entries);

//@}
/* End Processor Functions */

/** @name Memory Functions */
//@{

/**
 @brief Reads System Mainstore through the processor chip using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to read from
 @param i_bytes Number of bytes to write
 @param o_data DataBuffer object that holds data read from memory
 @param o_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipGetMemProc (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & o_memoryData, ecmdDataBuffer & o_memoryTags);

/**
 @brief Writes System Mainstore through the processor chip using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to write to
 @param i_bytes Number of bytes to write
 @param i_data DataBuffer object that holds data to write into memory
 @param i_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipPutMemProc (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & i_memoryData, ecmdDataBuffer & i_memoryTags);

/**
 @brief Reads System Mainstore through the memory controller using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a memory controller
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to read from
 @param i_bytes Number of bytes to write
 @param o_data DataBuffer object that holds data read from memory
 @param o_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipGetMemMemCtrl (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & o_memoryData, ecmdDataBuffer & o_memoryTags);

/**
 @brief Writes System Mainstore through the memory controller using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a memory controller
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to write to
 @param i_bytes Number of bytes to write
 @param i_data DataBuffer object that holds data to write into memory
 @param i_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipPutMemMemCtrl (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & i_memoryData, ecmdDataBuffer & i_memoryTags);

//@}
/* End Memory Functions */

} /* end extern "c" */

#endif /* cipClientCapi_h */

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              cengel Initial Creation
//
// End Change Log *****************************************************
<commit_msg>Fixed doxygen comments<commit_after>#ifndef cipClientCapi_h
#define cipClientCapi_h

/* $Header$ */

/**
 * @file cipClientCapi.H
 * @brief Cronus & IP eCMD Extension

 * Extension Owner : Chris Engel
*/

//--------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------
#include <ecmdReturnCodes.H>
#include <ecmdStructs.H>
#include <ecmdDataBuffer.H>
#include <cipStructs.H>

//--------------------------------------------------------------------
//  Forward References
//--------------------------------------------------------------------

/* Functions in here are defined as extern C for the following reasons:
 1)  Keeps Function names small by preventing C++ "mangling"
 2)  Allows (C-based) perl interpreter to access these functions

*/
extern "C" {

/** @name Load/Unload Functions */
//@{

/**
 @brief Initialize eCMD CIP Extension DLL
 @retval ECMD_SUCCESS if successful load
 @retval ECMD_INVALID_DLL_VERSION if Dll version loaded doesn't match client version
 @retval nonzero if unsuccessful
 @post eCMD CIP Extension is initialized and version checked

*/
uint32_t cipInitExtension();

//@}

/** @name Processor Functions */
//@{

/**
 @brief Start Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStartInstructions (ecmdChipTarget & i_target);

/**
 @brief Start Instructions on all configured processors
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStartAllInstructions ();

/**
 @brief Stop Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStopInstructions (ecmdChipTarget & i_target);

/**
 @brief Stop All Instructions
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStopAllInstructions ();

/**
 @brief Step Instructions
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_steps Number of steps to execute
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipStepInstructions (ecmdChipTarget & i_target, uint32_t i_steps);

/**
 @brief Set a hardware breakpoint in Processor using a real address
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_address Address to set breakpoint at
 @param i_type Type of breakpoint to set
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipSetBreakpoint (ecmdChipTarget & i_target, uint64_t i_address, ecmdBreakpointType_t & i_type);

/**
 @brief Clear a hardware breakpoint from Processor using a real address
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_address Address to clear breakpoint at
 @param i_type Type of breakpoint to set
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful
 @retval nonzero if unsuccessful
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation

*/
uint32_t cipClearBreakpoint (ecmdChipTarget & i_target, uint64_t i_address, ecmdBreakpointType_t & i_type);

/**
 @brief Reads the selected Processor Architected VMX Register (VPR) into the data buffer
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_vprNum Number of vpr to read from
 @param o_data DataBuffer object that holds data read from vpr

*/
uint32_t cipGetVpr (ecmdChipTarget & i_target, uint32_t i_vprNum, ecmdDataBuffer & o_data);

/**
 @brief Reads the selected Processor Architected VMX Register (VPR) into the data buffers
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param io_entries List of entries to fetch ecmdIndexEntry.index field must be filled in

 The return value of this function is set to the first non-zero return code found when
  retrieving multiple entries.  The entry that caused the failure in the list will also be marked with
  the same return code. That data and all subsequent entries in the list will not be fetched and the data
  should be considered invalid.

*/
uint32_t cipGetVprMultiple (ecmdChipTarget & i_target, std::list<ecmdIndexEntry> & io_entries);

/**
 @brief Writes the data buffer into the selected Processor Architected VMX Register (VPR)
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_SUCCESS if successful
 @retval ECMD_DATA_OVERFLOW Too much data was provided for a write
 @retval ECMD_DATA_UNDERFLOW  Too little data was provided to a write function
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disaled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_vprNum Number of vpr to write to
 @param i_data DataBuffer object that holds data to write into vpr

*/
uint32_t cipPutVpr (ecmdChipTarget & i_target, uint32_t i_vprNum, ecmdDataBuffer & i_data);

/**
 @brief Writes the data buffer into the selected Processor Architected VMX Register (VPR)
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_INVALID_ARGS Vpr number is invalid
 @retval ECMD_SUCCESS if successful
 @retval ECMD_DATA_OVERFLOW Too much data was provided for a write
 @retval ECMD_DATA_UNDERFLOW  Too little data was provided to a write function
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position/core/thread information
 @param i_entries List of entries to write all ecmdIndexEntry fields must be filled in

 The return value of this function is set to the first non-zero return code found when
  writing multiple entries.  The function will NOT continue through all subsequent entries.

*/
uint32_t cipPutVprMultiple (ecmdChipTarget & i_target, std::list<ecmdIndexEntry> & i_entries);

//@}
/* End Processor Functions */

/** @name Memory Functions */
//@{

/**
 @brief Reads System Mainstore through the processor chip using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to read from
 @param i_bytes Number of bytes to write
 @param o_memoryData DataBuffer object that holds data read from memory
 @param o_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipGetMemProc (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & o_memoryData, ecmdDataBuffer & o_memoryTags);

/**
 @brief Writes System Mainstore through the processor chip using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a processor
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to write to
 @param i_bytes Number of bytes to write
 @param i_memoryData DataBuffer object that holds data to write into memory
 @param i_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipPutMemProc (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & i_memoryData, ecmdDataBuffer & i_memoryTags);

/**
 @brief Reads System Mainstore through the memory controller using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a memory controller
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval ECMD_SUCCESS if successful read
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to read from
 @param i_bytes Number of bytes to write
 @param o_memoryData DataBuffer object that holds data read from memory
 @param o_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipGetMemMemCtrl (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & o_memoryData, ecmdDataBuffer & o_memoryTags);

/**
 @brief Writes System Mainstore through the memory controller using a real address
 @retval ECMD_TARGET_INVALID_TYPE if target is not a memory controller
 @retval ECMD_TARGET_NOT_CONFIGURED if target is not available in the system
 @retval ECMD_SUCCESS if successful
 @retval ECMD_RING_CACHE_ENABLED Ring Cache enabled function - must be disabled to use this function
 @retval ECMD_CLOCKS_IN_INVALID_STATE Chip Clocks were in an invalid state to perform the operation
 @retval nonzero if unsuccessful
 @param i_target Struct that contains chip and cage/node/slot/position information
 @param i_address Starting address to write to
 @param i_bytes Number of bytes to write
 @param i_memoryData DataBuffer object that holds data to write into memory
 @param i_memoryTags 1 bit of tag for every 64 bits of memory data

 NOTE : This function requires that the address be aligned on a 64 bit boundary

*/
uint32_t cipPutMemMemCtrl (ecmdChipTarget & i_target, uint64_t i_address, uint32_t i_bytes, ecmdDataBuffer & i_memoryData, ecmdDataBuffer & i_memoryTags);

//@}
/* End Memory Functions */

} /* end extern "c" */

#endif /* cipClientCapi_h */

// Change Log *********************************************************
//
//  Flag Reason   Vers Date     Coder  Description
//  ---- -------- ---- -------- -----  -------------------------------
//                              cengel Initial Creation
//
// End Change Log *****************************************************
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <dtkCore/dtkPluginManager.h>

#include <medSql/medDatabaseController.h>
#include <medSql/medDatabaseImporter.h>
#include <medCore/medStorage.h>
#include <medCore/medDataIndex.h>

#include <QtCore>

bool checkDirectoryHierarchyAndThumbnails(QString dbPath, QString patientName, QString studyName, QString sessionName, unsigned int thumbnailsCount);
int countRowsInTable(QSqlDatabase db, QString tableName);
bool checkIfRowExists(QSqlDatabase db, QString tableName, QString columnName, QString value);
bool checkIfRowExists(QSqlDatabase db, QString tableName, QHash<QString, QString> columnValues);

int medDatabaseControllerImplTest(int argc, char* argv[])
{
    // this test requires medinria plugins path and medinria data path
    if (argc < 3)
      return EXIT_FAILURE;

    // get the input directories
    QString pluginsPath = argv[1];
    QString dataDir = argv[2];

    // load medinria plugins, we will need data types, readers and writers
    dtkPluginManager::instance()->setPath(pluginsPath);
    dtkPluginManager::instance()->initialize();

    // create temporary directory for new database
    QString dbPath = QDir::tempPath() + "/medinria-test-db";

    medStorage::setDataLocation(dbPath);

    QPointer<medDatabaseControllerImpl> dbc = medDatabaseController::instance();

    // create connection and create database schema
    if(!dbc->createConnection())
    {
        qWarning() << "Unable to create a connection to the database";
        return EXIT_FAILURE;
    }

    QString file = dataDir + QString("/Clatz/I1.nhdr");
    QFileInfo info(file);
    bool indexWithoutCopying = false;

    // import
    medDatabaseImporter *importer = new medDatabaseImporter(info.absoluteFilePath(), indexWithoutCopying);
    importer->run();

    /* CHECK
     * We won't do a full and exhaustive check in here, we will
     * see if the appropriate folders were created, we will
     * check thumbnails image files (only by name) and then we
     * will take a deep look at the database tables.
     */

    QString patientName = "John Doe";
    QString studyName = "EmptyStudy";
    QString sessionName = "I11";

    if(!checkDirectoryHierarchyAndThumbnails(dbPath, patientName, studyName, sessionName, 63))
        return EXIT_FAILURE;

    // super, so we reached a point that all the files we expect are there
    // however we didn't check the content, but still...
    // now onto db check

    QSqlDatabase db = *(dbc->database());

    // check that there is only one row in patient table
    if(1 != countRowsInTable(db, "patient"))
        return EXIT_FAILURE;

    // check that patient named John Doe exists
    // we do not check for all the other columns
    if(!checkIfRowExists(db, "patient", "name", patientName))
        return EXIT_FAILURE;

    // check that there is only one row in study table
    if(1 != countRowsInTable(db, "study"))
        return EXIT_FAILURE;

    // check that there is a study named EmptyStudy
    // we do not check for all the other columns
    if(!checkIfRowExists(db, "study", "name", studyName))
        return EXIT_FAILURE;

    // check that there is only one row in series table
    if(1 != countRowsInTable(db, "series"))
        return EXIT_FAILURE;

    // check that the proper path is in series table
    QString seriesPath = QDir::separator() + patientName + QDir::separator()  + studyName + QDir::separator() + sessionName + QString(".mha");
    if(!checkIfRowExists(db, "series", "path", seriesPath))
        return EXIT_FAILURE;

    int imageCount = 64;

    // check that there are #imageCount rows in image table
    if (imageCount != countRowsInTable(db, "image"))
        return EXIT_FAILURE;

    // check every row
    for (int i = 0; i < imageCount ; i++)
    {
        QHash<QString, QString> columnValues;
        columnValues.insert("size", QString::number(imageCount));
        columnValues.insert("name", "I1.nhdr" + QString::number(i));
        columnValues.insert("path", file);
        columnValues.insert("instance_path", seriesPath);
        QString thumbnailPath = QDir::separator() + patientName + QDir::separator()  + studyName + QDir::separator() + sessionName + QDir::separator() + QString::number(i) + ".png";
        columnValues.insert("thumbnail", thumbnailPath);

        if(!checkIfRowExists(db, "image", columnValues))
            return EXIT_FAILURE;
    }

    // clean
    medStorage::removeDir(dbPath, NULL);
    medDatabaseController::destroy();

    return EXIT_SUCCESS;
}

bool checkDirectoryHierarchyAndThumbnails(QString dbPath, QString patientName, QString studyName, QString sessionName, unsigned int thumbnailsCount)
{
    // We do not check the content of the files
    // we just see whether they exist

    // Patient
    QString patientPath = dbPath + QDir::separator() + patientName;
    if (QDir(patientPath).exists())
    {
        QString studyPath = patientPath + QDir::separator() + studyName;
        if (QDir(studyPath).exists())
        {
            QString sessionPath = studyPath + QDir::separator() + sessionName;
            QString sessionFile = sessionPath + QString(".mha");
            if (QDir(sessionPath).exists() && QFile(sessionFile).exists())
            {
                // check if thumbnails exist
                for (int i = 0; i <= thumbnailsCount; i++) {
                    QFile thumbnail(sessionPath + QDir::separator() + QString::number(i) + QString(".png"));
                    if (!thumbnail.exists())
                        return false;
                }

                // finally check ref.png
                QFile ref(sessionPath + QDir::separator() + QString("ref.png"));
                if (!ref.exists())
                    return false;

                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

int countRowsInTable(QSqlDatabase db, QString tableName)
{
    QSqlQuery query(db);

    query.prepare("SELECT COUNT(*) FROM " + tableName);

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return -1;
    }

    if(query.first()) {
        QVariant rowsCount = query.value(0);
        return rowsCount.toInt();
    }
    else
        return -1;
}

bool checkIfRowExists(QSqlDatabase db, QString tableName, QString columnName, QString value)
{
    QSqlQuery query(db);

    query.prepare("SELECT id FROM " + tableName + " WHERE " + columnName + " = :value");
    query.bindValue(":value", value);

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return false;
    }

    if(query.first()) {
        QVariant patientId = query.value(0);
        return true;
    }
    else
        return false;
}

bool checkIfRowExists(QSqlDatabase db, QString tableName, QHash<QString, QString> columnValues)
{
    // TODO this way of building the query string is just awful
    // try to find another...

	QString queryString = "SELECT id FROM " + tableName + " WHERE ";

	QHashIterator<QString, QString> it(columnValues);
    bool firstTime = true;

    while (it.hasNext())
    {
        it.next();

        if (!firstTime)
        {
            queryString.append(" AND ");
        }
        else
            firstTime = false;

        queryString.append(it.key()).append( " = :").append(it.key());
    }

    QSqlQuery query(db);
    query.prepare(queryString);

    it.toFront();

    while (it.hasNext())
    {
        it.next();
        query.bindValue(":"+it.key(), it.value());
    }

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return false;
    }

    // see executed query
	//qDebug() << query.executedQuery().toStdString().c_str();

    if(query.first()) {
        QVariant patientId = query.value(0);
        return true;
    }
    else
        return false;
}
<commit_msg>Fixed warning.<commit_after>#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <dtkCore/dtkPluginManager.h>

#include <medSql/medDatabaseController.h>
#include <medSql/medDatabaseImporter.h>
#include <medCore/medStorage.h>
#include <medCore/medDataIndex.h>

#include <QtCore>

bool checkDirectoryHierarchyAndThumbnails(QString dbPath, QString patientName, QString studyName, QString sessionName, unsigned int thumbnailsCount);
int countRowsInTable(QSqlDatabase db, QString tableName);
bool checkIfRowExists(QSqlDatabase db, QString tableName, QString columnName, QString value);
bool checkIfRowExists(QSqlDatabase db, QString tableName, QHash<QString, QString> columnValues);

int medDatabaseControllerImplTest(int argc, char* argv[])
{
    // this test requires medinria plugins path and medinria data path
    if (argc < 3)
      return EXIT_FAILURE;

    // get the input directories
    QString pluginsPath = argv[1];
    QString dataDir = argv[2];

    // load medinria plugins, we will need data types, readers and writers
    dtkPluginManager::instance()->setPath(pluginsPath);
    dtkPluginManager::instance()->initialize();

    // create temporary directory for new database
    QString dbPath = QDir::tempPath() + "/medinria-test-db";

    medStorage::setDataLocation(dbPath);

    QPointer<medDatabaseControllerImpl> dbc = medDatabaseController::instance();

    // create connection and create database schema
    if(!dbc->createConnection())
    {
        qWarning() << "Unable to create a connection to the database";
        return EXIT_FAILURE;
    }

    QString file = dataDir + QString("/Clatz/I1.nhdr");
    QFileInfo info(file);
    bool indexWithoutCopying = false;

    // import
    medDatabaseImporter *importer = new medDatabaseImporter(info.absoluteFilePath(), indexWithoutCopying);
    importer->run();

    /* CHECK
     * We won't do a full and exhaustive check in here, we will
     * see if the appropriate folders were created, we will
     * check thumbnails image files (only by name) and then we
     * will take a deep look at the database tables.
     */

    QString patientName = "John Doe";
    QString studyName = "EmptyStudy";
    QString sessionName = "I11";

    if(!checkDirectoryHierarchyAndThumbnails(dbPath, patientName, studyName, sessionName, 63))
        return EXIT_FAILURE;

    // super, so we reached a point that all the files we expect are there
    // however we didn't check the content, but still...
    // now onto db check

    QSqlDatabase db = *(dbc->database());

    // check that there is only one row in patient table
    if(1 != countRowsInTable(db, "patient"))
        return EXIT_FAILURE;

    // check that patient named John Doe exists
    // we do not check for all the other columns
    if(!checkIfRowExists(db, "patient", "name", patientName))
        return EXIT_FAILURE;

    // check that there is only one row in study table
    if(1 != countRowsInTable(db, "study"))
        return EXIT_FAILURE;

    // check that there is a study named EmptyStudy
    // we do not check for all the other columns
    if(!checkIfRowExists(db, "study", "name", studyName))
        return EXIT_FAILURE;

    // check that there is only one row in series table
    if(1 != countRowsInTable(db, "series"))
        return EXIT_FAILURE;

    // check that the proper path is in series table
    QString seriesPath = QDir::separator() + patientName + QDir::separator()  + studyName + QDir::separator() + sessionName + QString(".mha");
    if(!checkIfRowExists(db, "series", "path", seriesPath))
        return EXIT_FAILURE;

    int imageCount = 64;

    // check that there are #imageCount rows in image table
    if (imageCount != countRowsInTable(db, "image"))
        return EXIT_FAILURE;

    // check every row
    for (int i = 0; i < imageCount ; i++)
    {
        QHash<QString, QString> columnValues;
        columnValues.insert("size", QString::number(imageCount));
        columnValues.insert("name", "I1.nhdr" + QString::number(i));
        columnValues.insert("path", file);
        columnValues.insert("instance_path", seriesPath);
        QString thumbnailPath = QDir::separator() + patientName + QDir::separator()  + studyName + QDir::separator() + sessionName + QDir::separator() + QString::number(i) + ".png";
        columnValues.insert("thumbnail", thumbnailPath);

        if(!checkIfRowExists(db, "image", columnValues))
            return EXIT_FAILURE;
    }

    // clean
    medStorage::removeDir(dbPath, NULL);
    medDatabaseController::destroy();

    return EXIT_SUCCESS;
}

bool checkDirectoryHierarchyAndThumbnails(QString dbPath, QString patientName, QString studyName, QString sessionName, unsigned int thumbnailsCount)
{
    // We do not check the content of the files
    // we just see whether they exist

    // Patient
    QString patientPath = dbPath + QDir::separator() + patientName;
    if (QDir(patientPath).exists())
    {
        QString studyPath = patientPath + QDir::separator() + studyName;
        if (QDir(studyPath).exists())
        {
            QString sessionPath = studyPath + QDir::separator() + sessionName;
            QString sessionFile = sessionPath + QString(".mha");
            if (QDir(sessionPath).exists() && QFile(sessionFile).exists())
            {
                // check if thumbnails exist
                for (unsigned int i = 0; i <= thumbnailsCount; i++) {
                    QFile thumbnail(sessionPath + QDir::separator() + QString::number(i) + QString(".png"));
                    if (!thumbnail.exists())
                        return false;
                }

                // finally check ref.png
                QFile ref(sessionPath + QDir::separator() + QString("ref.png"));
                if (!ref.exists())
                    return false;

                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

int countRowsInTable(QSqlDatabase db, QString tableName)
{
    QSqlQuery query(db);

    query.prepare("SELECT COUNT(*) FROM " + tableName);

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return -1;
    }

    if(query.first()) {
        QVariant rowsCount = query.value(0);
        return rowsCount.toInt();
    }
    else
        return -1;
}

bool checkIfRowExists(QSqlDatabase db, QString tableName, QString columnName, QString value)
{
    QSqlQuery query(db);

    query.prepare("SELECT id FROM " + tableName + " WHERE " + columnName + " = :value");
    query.bindValue(":value", value);

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return false;
    }

    if(query.first()) {
        QVariant patientId = query.value(0);
        return true;
    }
    else
        return false;
}

bool checkIfRowExists(QSqlDatabase db, QString tableName, QHash<QString, QString> columnValues)
{
    // TODO this way of building the query string is just awful
    // try to find another...

	QString queryString = "SELECT id FROM " + tableName + " WHERE ";

	QHashIterator<QString, QString> it(columnValues);
    bool firstTime = true;

    while (it.hasNext())
    {
        it.next();

        if (!firstTime)
        {
            queryString.append(" AND ");
        }
        else
            firstTime = false;

        queryString.append(it.key()).append( " = :").append(it.key());
    }

    QSqlQuery query(db);
    query.prepare(queryString);

    it.toFront();

    while (it.hasNext())
    {
        it.next();
        query.bindValue(":"+it.key(), it.value());
    }

    if(!query.exec())
    {
        qDebug() << DTK_COLOR_FG_RED << query.lastError() << DTK_NO_COLOR;
        return false;
    }

    // see executed query
	//qDebug() << query.executedQuery().toStdString().c_str();

    if(query.first()) {
        QVariant patientId = query.value(0);
        return true;
    }
    else
        return false;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(HOST_OS_WINDOWS)

#include "vm/virtual_memory.h"

#include "platform/assert.h"
#include "vm/os.h"

#include "vm/isolate.h"

namespace dart {

uword VirtualMemory::page_size_ = 0;

void VirtualMemory::InitOnce() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  page_size_ = info.dwPageSize;
}

VirtualMemory* VirtualMemory::Allocate(intptr_t size,
                                       bool is_executable,
                                       const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, prot);
  if (address == NULL) {
    return NULL;
  }
  MemoryRegion region(address, size);
  return new VirtualMemory(region, region);
}

VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
                                              intptr_t alignment,
                                              bool is_executable,
                                              const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  ASSERT(Utils::IsAligned(alignment, page_size_));
  intptr_t reserved_size = size + alignment;
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, reserved_size, MEM_RESERVE, prot);
  if (address == NULL) {
    return NULL;
  }

  void* aligned_address = reinterpret_cast<void*>(
      Utils::RoundUp(reinterpret_cast<uword>(address), alignment));
  if (VirtualAlloc(aligned_address, size, MEM_COMMIT, prot) !=
      aligned_address) {
    VirtualFree(address, reserved_size, MEM_RELEASE);
    return NULL;
  }

  MemoryRegion region(aligned_address, size);
  MemoryRegion reserved(address, reserved_size);
  return new VirtualMemory(region, reserved);
}

VirtualMemory::~VirtualMemory() {
  if (!vm_owns_region() || (reserved_.size() == 0)) {
    return;
  }
  if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
    FATAL("VirtualFree failed");
  }
}

bool VirtualMemory::FreeSubSegment(void* address,
                                   intptr_t size) {
  // On Windows only the entire segment returned by VirtualAlloc
  // can be freed. Therefore we will have to waste these unused
  // virtual memory sub-segments.
  return false;
}

void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
  ASSERT(Thread::Current()->IsMutatorThread() ||
         Isolate::Current()->mutator_thread()->IsAtSafepoint());
  uword start_address = reinterpret_cast<uword>(address);
  uword end_address = start_address + size;
  uword page_address = Utils::RoundDown(start_address, PageSize());
  DWORD prot = 0;
  switch (mode) {
    case kNoAccess:
      prot = PAGE_NOACCESS;
      break;
    case kReadOnly:
      prot = PAGE_READONLY;
      break;
    case kReadWrite:
      prot = PAGE_READWRITE;
      break;
    case kReadExecute:
      prot = PAGE_EXECUTE_READ;
      break;
    case kReadWriteExecute:
      prot = PAGE_EXECUTE_READWRITE;
      break;
  }
  DWORD old_prot = 0;
  if (VirtualProtect(reinterpret_cast<void*>(page_address),
                     end_address - page_address, prot, &old_prot) == 0) {
    FATAL1("VirtualProtect failed %d\n", GetLastError());
  }
}

}  // namespace dart

#endif  // defined(HOST_OS_WINDOWS)
<commit_msg>[vm][windows] Implement VirtualMemory::FreeSubSegment<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/globals.h"
#if defined(HOST_OS_WINDOWS)

#include "vm/virtual_memory.h"

#include "platform/assert.h"
#include "vm/os.h"

#include "vm/isolate.h"

namespace dart {

uword VirtualMemory::page_size_ = 0;

void VirtualMemory::InitOnce() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  page_size_ = info.dwPageSize;
}

VirtualMemory* VirtualMemory::Allocate(intptr_t size,
                                       bool is_executable,
                                       const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, prot);
  if (address == NULL) {
    return NULL;
  }
  MemoryRegion region(address, size);
  return new VirtualMemory(region, region);
}

VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
                                              intptr_t alignment,
                                              bool is_executable,
                                              const char* name) {
  ASSERT(Utils::IsAligned(size, page_size_));
  ASSERT(Utils::IsAligned(alignment, page_size_));
  intptr_t reserved_size = size + alignment;
  int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
  void* address = VirtualAlloc(NULL, reserved_size, MEM_RESERVE, prot);
  if (address == NULL) {
    return NULL;
  }

  void* aligned_address = reinterpret_cast<void*>(
      Utils::RoundUp(reinterpret_cast<uword>(address), alignment));
  if (VirtualAlloc(aligned_address, size, MEM_COMMIT, prot) !=
      aligned_address) {
    VirtualFree(address, reserved_size, MEM_RELEASE);
    return NULL;
  }

  MemoryRegion region(aligned_address, size);
  MemoryRegion reserved(address, reserved_size);
  return new VirtualMemory(region, reserved);
}

VirtualMemory::~VirtualMemory() {
  if (!vm_owns_region() || (reserved_.size() == 0)) {
    return;
  }
  if (VirtualFree(reserved_.pointer(), 0, MEM_RELEASE) == 0) {
    FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
  }
}

bool VirtualMemory::FreeSubSegment(void* address,
                                   intptr_t size) {
  if (VirtualFree(address, size, MEM_DECOMMIT) == 0) {
    FATAL1("VirtualFree failed: Error code %d\n", GetLastError());
  }
  return true;
}

void VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
  ASSERT(Thread::Current()->IsMutatorThread() ||
         Isolate::Current()->mutator_thread()->IsAtSafepoint());
  uword start_address = reinterpret_cast<uword>(address);
  uword end_address = start_address + size;
  uword page_address = Utils::RoundDown(start_address, PageSize());
  DWORD prot = 0;
  switch (mode) {
    case kNoAccess:
      prot = PAGE_NOACCESS;
      break;
    case kReadOnly:
      prot = PAGE_READONLY;
      break;
    case kReadWrite:
      prot = PAGE_READWRITE;
      break;
    case kReadExecute:
      prot = PAGE_EXECUTE_READ;
      break;
    case kReadWriteExecute:
      prot = PAGE_EXECUTE_READWRITE;
      break;
  }
  DWORD old_prot = 0;
  if (VirtualProtect(reinterpret_cast<void*>(page_address),
                     end_address - page_address, prot, &old_prot) == 0) {
    FATAL1("VirtualProtect failed %d\n", GetLastError());
  }
}

}  // namespace dart

#endif  // defined(HOST_OS_WINDOWS)
<|endoftext|>


<commit_before><commit_msg>Use new char[] to match the delete[]. To fix a valgrind error.<commit_after><|endoftext|>


<commit_before>//
//  Keyboard.h
//  Clock Signal
//
//  Created by Thomas Harte on 08/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef Keyboard_hpp
#define Keyboard_hpp

namespace Apple {
namespace Macintosh {

class Keyboard {
	public:
		void set_input(bool data) {
		}

		bool get_clock() {
			return false;
		}

		bool get_data() {
			return false;
		}

		/*!
			The keyboard expects ~10 µs-frequency ticks, i.e. a clock rate of just around 100 kHz.
		*/
		void run_for(HalfCycles cycle) {
			// TODO: something.
		}
};

/*
	"When sending data to the computer, the keyboard transmits eight cycles of 330 µS each (160 µS low, 170 µS high)
	on the normally high Keyboard Clock line. It places a data bit on the data line 40 µS before the falling edge of each
	clock cycle and maintains it for 330 µS. The VIA in the compu(er latches the data bit into its Shift register on the
	rising edge of the Keyboard Clock signal."

	"When the computer is sending data to the keyboard, the keyboard transmits eight cycles of 400 µS each (180 µS low,
	220 µS high) on the Keyboard Clock line. On the falling edge of each keyboard clock cycle, the Macintosh Plus places
	a data bit on the data line and holds it there for 400 µS. The keyboard reads the data bit 80 µS after the rising edge
	of the Keyboard Clock signal."
*/

}
}

#endif /* Keyboard_h */
<commit_msg>Takes a first crack at the keyboard's serial protocol.<commit_after>//
//  Keyboard.h
//  Clock Signal
//
//  Created by Thomas Harte on 08/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef Keyboard_hpp
#define Keyboard_hpp

namespace Apple {
namespace Macintosh {

class Keyboard {
	public:
		void set_input(bool data) {
			switch(mode_) {
				case Mode::Waiting:
					/*
						"Only the computer can initiate communication over the keyboard lines. When the computer and keyboard
						are turned on, the computer is in charge of the keyboard interface and the keyboard is passive. The
						computer signals that it is ready to begin communication by pulling the Keyboard Data line low."
					*/
					if(!data) {
						mode_ = Mode::AcceptingCommand;
						phase_ = 0;
						command_ = 0;
					}
				break;

				case Mode::AcceptingCommand:
					/* Note value, so that it can be latched upon a clock transition. */
					data_input_ = data;
				break;

				case Mode::AwaitingEndOfCommand:
					/*
						The last bit of the command leaves the Keyboard Data line low; the computer then indicates that it is ready
						to receive the keyboard's response by setting the Keyboard Data line high.
					*/
					if(data) {
						mode_ = Mode::PerformingCommand;
						phase_ = 0;
					}
				break;

				default:
				case Mode::SendingResponse:
					/* This line isn't currently an input; do nothing. */
				break;
			}
		}

		bool get_clock() {
			return clock_output_;
		}

		bool get_data() {
			return !!(response_ & 0x80);
		}

		/*!
			The keyboard expects ~10 µs-frequency ticks, i.e. a clock rate of just around 100 kHz.
		*/
		void run_for(HalfCycles cycle) {
			switch(mode_) {
				default:
				case Mode::AwaitingEndOfCommand:
				case Mode::Waiting: return;

				case Mode::AcceptingCommand: {
					/*
						"When the computer is sending data to the keyboard, the keyboard transmits eight cycles of 400 µS each (180 µS low,
						220 µS high) on the Keyboard Clock line. On the falling edge of each keyboard clock cycle, the Macintosh Plus places
						a data bit on the data line and holds it there for 400 µS. The keyboard reads the data bit 80 µS after the rising edge
						of the Keyboard Clock signal."
					*/
					const auto offset = phase_ % 40;
					clock_output_ = offset >= 18;

					if(offset == 26) {
						command_ = (command_ << 1) | (data_input_ ? 1 : 0);
					}

					++phase_;
					if(phase_ == 8*40) {
						mode_ = Mode::AwaitingEndOfCommand;
						phase_ = 0;
					}
				} break;

				case Mode::PerformingCommand: {
					response_ = perform_command(command_);

					// Inquiry has a 0.25-second timeout; everything else is instant.
					++phase_;
					if(phase_ == 25000 || command_ != 0x10 || response_ != 0x7b) {
						mode_ = Mode::SendingResponse;
						phase_ = 0;
					}
				} break;

				case Mode::SendingResponse: {
					/*
						"When sending data to the computer, the keyboard transmits eight cycles of 330 µS each (160 µS low, 170 µS high)
						on the normally high Keyboard Clock line. It places a data bit on the data line 40 µS before the falling edge of each
						clock cycle and maintains it for 330 µS. The VIA in the computer latches the data bit into its shift register on the
						rising edge of the Keyboard Clock signal."
					*/
					const auto offset = phase_ % 33;
					clock_output_ = offset >= 16;

					if(offset == 29) {
						response_ <<= 1;
					}

					++phase_;
					if(phase_ == 8*33) {
						mode_ = Mode::Waiting;
						phase_ = 0;
					}
				} break;
			}
		}

	private:

		int perform_command(int command) {
			switch(command) {
				case 0x10:	// Inquiry.
				break;

				case 0x14:	// Instant.
				break;

				case 0x16:	// Model number.
				return
					0x01 |			// b0: always 1
					(1 << 1) |		// keyboard model number
					(1 << 4);		// next device number
									// (b7 not set => no next device)

				case 0x36:	// Test
				return 0x7d;		// 0x7d = ACK, 0x77 = not ACK.
			}
			return 0x7b;	// No key transition.
		}

		enum class Mode {
			Waiting,
			AcceptingCommand,
			AwaitingEndOfCommand,
			SendingResponse,
			PerformingCommand
		} mode_ = Mode::Waiting;
		int phase_ = 0;
		int command_ = 0;
		int response_ = 0;

		bool data_input_ = false;
		bool clock_output_ = false;
};

}
}

#endif /* Keyboard_h */
<|endoftext|>


<commit_before>#include "AliGFWFilter.h"
using namespace GFWFlags;
AliGFWFilter::AliGFWFilter():
  fRetFlags(0),
  flTrFlag(0),
  fEventFlag(0),
  fTrackMasks({}),
  fNTrMasks(0),
  fEventMasks({}),
  fNEvMasks(0),
  fAODTrack(0),
  fEventCuts(0),
  fPtMin(0.2),
  fPtMax(3.0),
  fEtaMin(-0.8),
  fEtaMax(0.8)
{
};
AliGFWFilter::~AliGFWFilter() {
};
void AliGFWFilter::CleanUp() {
};
Bool_t AliGFWFilter::AcceptVertex(AliAODEvent *inEv, Double_t *lvtxXYZ) {
  const AliAODVertex* vtx = dynamic_cast<const AliAODVertex*>(inEv->GetPrimaryVertex());
  if(!vtx || vtx->GetNContributors() < 1)
    return kFALSE;
  const AliAODVertex* vtxSPD = dynamic_cast<const AliAODVertex*>(inEv->GetPrimaryVertexSPD());
  Double_t dMaxResol = 0.25; // suggested from DPG
  Double_t cov[6] = {0};
  vtxSPD->GetCovarianceMatrix(cov);
  Double_t zRes = TMath::Sqrt(cov[5]);
  if ( vtxSPD->IsFromVertexerZ() && (zRes > dMaxResol)) return kFALSE;
  const Double_t aodVtxZ = vtx->GetZ();
  vtx->GetXYZ(lvtxXYZ);
  return kTRUE;
};
void AliGFWFilter::CheckEvent(AliVEvent* inEv) {
  AliAODEvent *fAOD = dynamic_cast<AliAODEvent*>(inEv);
  // AliESDEvent *fESD = dynamic_cast<AliESDEvent*>(inEv); //ESD not implemented yet
  if(!fRetFlags) {fRetFlags = new AliGFWFlags(); }
  else fRetFlags->CleanUp();
  if(fAOD) {
    fEventFlag=0;
    //If event cuts are set, then only consider events that pass the event selection
    if(fEventCuts)  { if(fEventCuts->AcceptEvent(fAOD)) AddEv(klEventCuts); else return; }
    else AddEv(klEventCuts); //Otherwise, mark all as passed (assuming ES is done outside)
    Double_t vtxXYZ[3];
    if(AcceptVertex(fAOD,vtxXYZ)) AddEv(klVtxOK);
    else return; //If vertex ain't accepted, no point to continue
    Double_t lvtxz = TMath::Abs(fAOD->GetPrimaryVertex()->GetZ());
    if(lvtxz<5)  AddEv(klVtxZ5);
    if(lvtxz<7)  AddEv(klVtxZ7);
    if(lvtxz<9)  AddEv(klVtxZ9);
    if(lvtxz<10) AddEv(klVtxZ10);
    UInt_t evfl = calculateEventFlag();
    fRetFlags->SetEventFlags(evfl);
    Double_t pt, eta, trXYZ[3], trDCAxy;
    UShort_t nTPCCLSsh, nTPCcl;
    for(Int_t i=0;i<fAOD->GetNumberOfTracks();i++) {
      fAODTrack = (AliAODTrack*)fAOD->GetTrack(i);
      if(!fAODTrack) continue;
      pt = fAODTrack->Pt();
      eta = fAODTrack->Eta();
      if(pt<fPtMin || pt>fPtMax) continue;
      if(eta<fEtaMin || eta>fEtaMax) continue;
      flTrFlag=0;
      //Testing filter bits:
      if(fAODTrack->TestFilterBit(32)) AddTr(klFB32);
      if(fAODTrack->TestFilterBit(64)) AddTr(klFB64);
      if(fAODTrack->TestFilterBit(256)) AddTr(klFB256);
      if(fAODTrack->TestFilterBit(512)) AddTr(klFB512);
      //Testing shared clusters
      nTPCCLSsh = fAODTrack->GetTPCnclsS();
      nTPCcl    = fAODTrack->GetTPCncls();
      if(nTPCCLSsh*1.0/nTPCcl <= 0.4) AddTr(klSharedClusters);
      //Testing hit on first layer SDD
      if(fAODTrack->HasPointOnITSLayer(4)) AddTr(klHitOnSDD); //2xSPD, 2xSSD, 2xSDD
      if(!fAODTrack->HasPointOnITSLayer(0) && !fAODTrack->HasPointOnITSLayer(1)) AddTr(klNoSPD); //No hits in SPD -> Necessary for FB 96<->768 overlap
      //Calculating DCAs:
      fAODTrack->GetXYZ(trXYZ);
      trXYZ[0] -= vtxXYZ[0];
      trXYZ[1] -= vtxXYZ[1];
      trXYZ[2] -= vtxXYZ[2];
      trDCAxy = TMath::Sqrt(trXYZ[0]*trXYZ[0] + trXYZ[1]*trXYZ[1]);
      //Checking DCAz:
      if(TMath::Abs(trXYZ[2])<2) AddTr(klDCAz20);
      if(TMath::Abs(trXYZ[2])<1) AddTr(klDCAz10);
      if(TMath::Abs(trXYZ[2])<0.5) AddTr(klDCAz05);
      //Checking DCAxy:
      Double_t dcaCut2010 = f_DCAxy2010(pt);
      Double_t dcaCut2011 = f_DCAxy2011(pt);
      if(trDCAxy<dcaCut2010*7) AddTr(klDCAxy2010);
      if(trDCAxy<dcaCut2011*7) AddTr(klDCAxy2011);
      if(trDCAxy<dcaCut2011*4) AddTr(klDCAxy4Sigma);
      if(trDCAxy<dcaCut2011*8) AddTr(klDCAxy8Sigma);
      if(trDCAxy<dcaCut2011*10) AddTr(klDCAxy10Sigma);
      //Checking TPC chi2 per cluster:
      Double_t tpcChi2PerCluster = fAODTrack->GetTPCchi2perCluster();
      if(tpcChi2PerCluster<=2.) AddTr(klTPCchi2PC20);
      if(tpcChi2PerCluster<=2.5) AddTr(klTPCchi2PC25);
      if(tpcChi2PerCluster<=3.0) AddTr(klTPCchi2PC30);
      if(tpcChi2PerCluster<=4.0) AddTr(klTPCchi2PC40);
      //Checking number of TPC clusters:
      UShort_t nTPCCls = fAODTrack->GetTPCNclsF();
      if(nTPCCls>70) AddTr(klNTPCcls70);
      if(nTPCCls>80) AddTr(klNTPCcls80);
      if(nTPCCls>90) AddTr(klNTPCcls90);
      if(nTPCCls>100) AddTr(klNTPCcls100);
      //Derived track cuts -- only for diff. modifications of filter bits, where OR is required
      if(TSB(klFB32)||TSB(klFB64)) AddTr(klFB96);
      if(TSB(klFB96)&&TSB(klSharedClusters)) AddTr(klFB96Tuned); //Tuned to overlap with 768 (modified)
      if(TSB(klFB256)||TSB(klFB512)) AddTr(klFB768);
      if(TSB(klFB256)||TB(klFB512+klNoSPD+klHitOnSDD)) AddTr(klFB768Tuned); //Tuned to overlap with 96 (modified). Second part is that only second part requires hit in SDD
      UInt_t flagToAdd = calculateTrackFlag();
      if(flagToAdd) fRetFlags->AddTrackFlags(i,flagToAdd); //Only count ones that pass any cuts
    };
  };
};
//klFB32, klFB64, klFB256, klFB512, klFB96, klFB96Tuned, klFB768, klFB768Tuned,
//klSharedClusters, klHitOnSDD, -- included in *Tuned fb's already
//klDCAz20, klDCAz10, klDCAz05,
//klDCAxy2010, klDCAxy2011, klDCAxy8Sigma, klDCAxy4Sigma, klDCAxy10Sigma,
//klTPCchi2PC25, klTPCchi2PC20, klTPCchi2PC30, klTPCchi2PC40
//klNTPCcls70, klNTPCcls80, klNTPCcls90, klNTPCcls100
void AliGFWFilter::CreateStandardCutMasks(kLocalTrackFlags lStandardChi2Cut) {
  //Standard cuts:
  //Nominal -- FB96:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768:
  fTrackMasks.push_back(klFB768 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |dcaZ| < 1:
  fTrackMasks.push_back(klFB96 + klDCAz10 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |dcaZ| < 0.5:
  fTrackMasks.push_back(klFB96 + klDCAz05 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |DCAxy| 4 sigma:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy4Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB96, |DCAxy| 10 sigma:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy10Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB96, chi2 per cluster <2:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + klTPCchi2PC20 + klNTPCcls70);
  //FB96, chi2 per cluster <3:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + klTPCchi2PC30 + klNTPCcls70);
  //FB96, Ntpc clusters > 80:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls80);
  //FB96, Ntpc clusters > 90:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls90);
  //FB96, Ntpc clusters > 100:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls100);
  //More reasonable ones:
  //Nominal, tuned to overlap with 768
  fTrackMasks.push_back(klFB96Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned to overlap with 96
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, smaller DCAz cut
  fTrackMasks.push_back(klFB768Tuned + klDCAz05 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, DCAxy 4 sigma
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy4Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, DCAxy 10 sigma
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy10Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB768tunes tuned, TPC chi2 <2
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + klTPCchi2PC20 + klNTPCcls70);
  //FB768tunes tuned, TPC chi2 <3
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + klTPCchi2PC30 + klNTPCcls70);
  //FB768tunes tuned, nTPC clusters >90
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls90);
  //FB96 with 2010 AND 2011 DCAxy
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2010 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);

  //Event cuts:
  // if(!fEventMasks) fEventMasks = new UInt_t[gNEventFlags];
  //Nominal:
  fEventMasks.push_back(klVtxZ10 + klEventCuts);
  //vtx z<9
  fEventMasks.push_back(klVtxZ9 + klEventCuts);
  //vtx z<7
  fEventMasks.push_back(klVtxZ7 + klEventCuts);
  //vtx z<5
  fEventMasks.push_back(klVtxZ5 + klEventCuts);

  fNTrMasks = (Int_t)fTrackMasks.size(); //fetch number of track cuts actually added, also so that we don't need to check the size for each track
  fNEvMasks = (Int_t)fEventMasks.size(); //same as above, but for events
};
void AliGFWFilter::AddCustomCuts(Bool_t cleanFirst, UInt_t lEv, UInt_t lTr) {
  if(cleanFirst) {fEventMasks.clear(); fTrackMasks.clear(); };
  fTrackMasks.push_back(lTr);
  fEventMasks.push_back(lEv);
  fNTrMasks = (Int_t)fTrackMasks.size(); //fetch number of track cuts actually added, also so that we don't need to check the size for each track
  fNEvMasks = (Int_t)fEventMasks.size(); //same as above, but for events
}
UInt_t AliGFWFilter::calculateEventFlag() {
  UInt_t retFlag = 0;
  for(Int_t i=0;i<fNEvMasks;i++) if(EB(fEventMasks[i])) retFlag|=(1<<i);
  return retFlag;
};
UInt_t AliGFWFilter::calculateTrackFlag() {
  UInt_t retFlag = 0;
  for(Int_t i=0;i<fNTrMasks;i++) if(TB(fTrackMasks[i])) retFlag|=(1<<i);
  return retFlag;
}
<commit_msg>GFWFilter: nTPCCluster cut is not >=70, as opposed to >70 (or any other number)<commit_after>#include "AliGFWFilter.h"
using namespace GFWFlags;
AliGFWFilter::AliGFWFilter():
  fRetFlags(0),
  flTrFlag(0),
  fEventFlag(0),
  fTrackMasks({}),
  fNTrMasks(0),
  fEventMasks({}),
  fNEvMasks(0),
  fAODTrack(0),
  fEventCuts(0),
  fPtMin(0.2),
  fPtMax(3.0),
  fEtaMin(-0.8),
  fEtaMax(0.8)
{
};
AliGFWFilter::~AliGFWFilter() {
};
void AliGFWFilter::CleanUp() {
};
Bool_t AliGFWFilter::AcceptVertex(AliAODEvent *inEv, Double_t *lvtxXYZ) {
  const AliAODVertex* vtx = dynamic_cast<const AliAODVertex*>(inEv->GetPrimaryVertex());
  if(!vtx || vtx->GetNContributors() < 1)
    return kFALSE;
  const AliAODVertex* vtxSPD = dynamic_cast<const AliAODVertex*>(inEv->GetPrimaryVertexSPD());
  Double_t dMaxResol = 0.25; // suggested from DPG
  Double_t cov[6] = {0};
  vtxSPD->GetCovarianceMatrix(cov);
  Double_t zRes = TMath::Sqrt(cov[5]);
  if ( vtxSPD->IsFromVertexerZ() && (zRes > dMaxResol)) return kFALSE;
  const Double_t aodVtxZ = vtx->GetZ();
  vtx->GetXYZ(lvtxXYZ);
  return kTRUE;
};
void AliGFWFilter::CheckEvent(AliVEvent* inEv) {
  AliAODEvent *fAOD = dynamic_cast<AliAODEvent*>(inEv);
  // AliESDEvent *fESD = dynamic_cast<AliESDEvent*>(inEv); //ESD not implemented yet
  if(!fRetFlags) {fRetFlags = new AliGFWFlags(); }
  else fRetFlags->CleanUp();
  if(fAOD) {
    fEventFlag=0;
    //If event cuts are set, then only consider events that pass the event selection
    if(fEventCuts)  { if(fEventCuts->AcceptEvent(fAOD)) AddEv(klEventCuts); else return; }
    else AddEv(klEventCuts); //Otherwise, mark all as passed (assuming ES is done outside)
    Double_t vtxXYZ[3];
    if(AcceptVertex(fAOD,vtxXYZ)) AddEv(klVtxOK);
    else return; //If vertex ain't accepted, no point to continue
    Double_t lvtxz = TMath::Abs(fAOD->GetPrimaryVertex()->GetZ());
    if(lvtxz<5)  AddEv(klVtxZ5);
    if(lvtxz<7)  AddEv(klVtxZ7);
    if(lvtxz<9)  AddEv(klVtxZ9);
    if(lvtxz<10) AddEv(klVtxZ10);
    UInt_t evfl = calculateEventFlag();
    fRetFlags->SetEventFlags(evfl);
    Double_t pt, eta, trXYZ[3], trDCAxy;
    UShort_t nTPCCLSsh, nTPCcl;
    for(Int_t i=0;i<fAOD->GetNumberOfTracks();i++) {
      fAODTrack = (AliAODTrack*)fAOD->GetTrack(i);
      if(!fAODTrack) continue;
      pt = fAODTrack->Pt();
      eta = fAODTrack->Eta();
      if(pt<fPtMin || pt>fPtMax) continue;
      if(eta<fEtaMin || eta>fEtaMax) continue;
      flTrFlag=0;
      //Testing filter bits:
      if(fAODTrack->TestFilterBit(32)) AddTr(klFB32);
      if(fAODTrack->TestFilterBit(64)) AddTr(klFB64);
      if(fAODTrack->TestFilterBit(256)) AddTr(klFB256);
      if(fAODTrack->TestFilterBit(512)) AddTr(klFB512);
      //Testing shared clusters
      nTPCCLSsh = fAODTrack->GetTPCnclsS();
      nTPCcl    = fAODTrack->GetTPCncls();
      if(nTPCCLSsh*1.0/nTPCcl <= 0.4) AddTr(klSharedClusters);
      //Testing hit on first layer SDD
      if(fAODTrack->HasPointOnITSLayer(4)) AddTr(klHitOnSDD); //2xSPD, 2xSSD, 2xSDD
      if(!fAODTrack->HasPointOnITSLayer(0) && !fAODTrack->HasPointOnITSLayer(1)) AddTr(klNoSPD); //No hits in SPD -> Necessary for FB 96<->768 overlap
      //Calculating DCAs:
      fAODTrack->GetXYZ(trXYZ);
      trXYZ[0] -= vtxXYZ[0];
      trXYZ[1] -= vtxXYZ[1];
      trXYZ[2] -= vtxXYZ[2];
      trDCAxy = TMath::Sqrt(trXYZ[0]*trXYZ[0] + trXYZ[1]*trXYZ[1]);
      //Checking DCAz:
      if(TMath::Abs(trXYZ[2])<2) AddTr(klDCAz20);
      if(TMath::Abs(trXYZ[2])<1) AddTr(klDCAz10);
      if(TMath::Abs(trXYZ[2])<0.5) AddTr(klDCAz05);
      //Checking DCAxy:
      Double_t dcaCut2010 = f_DCAxy2010(pt);
      Double_t dcaCut2011 = f_DCAxy2011(pt);
      if(trDCAxy<dcaCut2010*7) AddTr(klDCAxy2010);
      if(trDCAxy<dcaCut2011*7) AddTr(klDCAxy2011);
      if(trDCAxy<dcaCut2011*4) AddTr(klDCAxy4Sigma);
      if(trDCAxy<dcaCut2011*8) AddTr(klDCAxy8Sigma);
      if(trDCAxy<dcaCut2011*10) AddTr(klDCAxy10Sigma);
      //Checking TPC chi2 per cluster:
      Double_t tpcChi2PerCluster = fAODTrack->GetTPCchi2perCluster();
      if(tpcChi2PerCluster<=2.) AddTr(klTPCchi2PC20);
      if(tpcChi2PerCluster<=2.5) AddTr(klTPCchi2PC25);
      if(tpcChi2PerCluster<=3.0) AddTr(klTPCchi2PC30);
      if(tpcChi2PerCluster<=4.0) AddTr(klTPCchi2PC40);
      //Checking number of TPC clusters:
      UShort_t nTPCCls = fAODTrack->GetTPCNclsF();
      if(nTPCCls>=70) AddTr(klNTPCcls70);
      if(nTPCCls>=80) AddTr(klNTPCcls80);
      if(nTPCCls>=90) AddTr(klNTPCcls90);
      if(nTPCCls>=100) AddTr(klNTPCcls100);
      //Derived track cuts -- only for diff. modifications of filter bits, where OR is required
      if(TSB(klFB32)||TSB(klFB64)) AddTr(klFB96);
      if(TSB(klFB96)&&TSB(klSharedClusters)) AddTr(klFB96Tuned); //Tuned to overlap with 768 (modified)
      if(TSB(klFB256)||TSB(klFB512)) AddTr(klFB768);
      if(TSB(klFB256)||TB(klFB512+klNoSPD+klHitOnSDD)) AddTr(klFB768Tuned); //Tuned to overlap with 96 (modified). Second part is that only second part requires hit in SDD
      UInt_t flagToAdd = calculateTrackFlag();
      if(flagToAdd) fRetFlags->AddTrackFlags(i,flagToAdd); //Only count ones that pass any cuts
    };
  };
};
//klFB32, klFB64, klFB256, klFB512, klFB96, klFB96Tuned, klFB768, klFB768Tuned,
//klSharedClusters, klHitOnSDD, -- included in *Tuned fb's already
//klDCAz20, klDCAz10, klDCAz05,
//klDCAxy2010, klDCAxy2011, klDCAxy8Sigma, klDCAxy4Sigma, klDCAxy10Sigma,
//klTPCchi2PC25, klTPCchi2PC20, klTPCchi2PC30, klTPCchi2PC40
//klNTPCcls70, klNTPCcls80, klNTPCcls90, klNTPCcls100
void AliGFWFilter::CreateStandardCutMasks(kLocalTrackFlags lStandardChi2Cut) {
  //Standard cuts:
  //Nominal -- FB96:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768:
  fTrackMasks.push_back(klFB768 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |dcaZ| < 1:
  fTrackMasks.push_back(klFB96 + klDCAz10 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |dcaZ| < 0.5:
  fTrackMasks.push_back(klFB96 + klDCAz05 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB96, |DCAxy| 4 sigma:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy4Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB96, |DCAxy| 10 sigma:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy10Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB96, chi2 per cluster <2:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + klTPCchi2PC20 + klNTPCcls70);
  //FB96, chi2 per cluster <3:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + klTPCchi2PC30 + klNTPCcls70);
  //FB96, Ntpc clusters > 80:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls80);
  //FB96, Ntpc clusters > 90:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls90);
  //FB96, Ntpc clusters > 100:
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls100);
  //More reasonable ones:
  //Nominal, tuned to overlap with 768
  fTrackMasks.push_back(klFB96Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned to overlap with 96
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, smaller DCAz cut
  fTrackMasks.push_back(klFB768Tuned + klDCAz05 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, DCAxy 4 sigma
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy4Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB768 tuned, DCAxy 10 sigma
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy10Sigma + lStandardChi2Cut + klNTPCcls70);
  //FB768tunes tuned, TPC chi2 <2
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + klTPCchi2PC20 + klNTPCcls70);
  //FB768tunes tuned, TPC chi2 <3
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + klTPCchi2PC30 + klNTPCcls70);
  //FB768tunes tuned, nTPC clusters >90
  fTrackMasks.push_back(klFB768Tuned + klDCAz20 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls90);
  //FB96 with 2010 AND 2011 DCAxy
  fTrackMasks.push_back(klFB96 + klDCAz20 + klDCAxy2010 + klDCAxy2011 + lStandardChi2Cut + klNTPCcls70);

  //Event cuts:
  // if(!fEventMasks) fEventMasks = new UInt_t[gNEventFlags];
  //Nominal:
  fEventMasks.push_back(klVtxZ10 + klEventCuts);
  //vtx z<9
  fEventMasks.push_back(klVtxZ9 + klEventCuts);
  //vtx z<7
  fEventMasks.push_back(klVtxZ7 + klEventCuts);
  //vtx z<5
  fEventMasks.push_back(klVtxZ5 + klEventCuts);

  fNTrMasks = (Int_t)fTrackMasks.size(); //fetch number of track cuts actually added, also so that we don't need to check the size for each track
  fNEvMasks = (Int_t)fEventMasks.size(); //same as above, but for events
};
void AliGFWFilter::AddCustomCuts(Bool_t cleanFirst, UInt_t lEv, UInt_t lTr) {
  if(cleanFirst) {fEventMasks.clear(); fTrackMasks.clear(); };
  fTrackMasks.push_back(lTr);
  fEventMasks.push_back(lEv);
  fNTrMasks = (Int_t)fTrackMasks.size(); //fetch number of track cuts actually added, also so that we don't need to check the size for each track
  fNEvMasks = (Int_t)fEventMasks.size(); //same as above, but for events
}
UInt_t AliGFWFilter::calculateEventFlag() {
  UInt_t retFlag = 0;
  for(Int_t i=0;i<fNEvMasks;i++) if(EB(fEventMasks[i])) retFlag|=(1<<i);
  return retFlag;
};
UInt_t AliGFWFilter::calculateTrackFlag() {
  UInt_t retFlag = 0;
  for(Int_t i=0;i<fNTrMasks;i++) if(TB(fTrackMasks[i])) retFlag|=(1<<i);
  return retFlag;
}
<|endoftext|>


<commit_before>/*
  //
  // Function to dump recursivally in human readable format, content of the objects + example use case
  //
  //
  .L  $mcProd/dumpObject.C+
  ExampleUse(); > AliTPCClusterParam.dump
  AliTPCRecoParam param;
  DumpObjectRecursive(&param); >> AliTPCRecoParam.dump

  Use case examples
  1.) compare oontent of alignent OCDB files for differnt yers
  2.) compare ClusterParam for different periods

=================================================================================================================
  // 1.)
  // Compare alignment example:
  // Compare TPC alignemnt 2013 and 2010
  //
  DumpOCDBFile("/cvmfs/alice.gsi.de/alice/data/2013/OCDB/TPC/Align/Data/Run0_999999999_v1_s0.root","TPCalign2013.dump",1);
  DumpOCDBFile("/cvmfs/alice.gsi.de/alice/data/2010/OCDB/TPC/Align/Data/Run0_999999999_v1_s0.root","TPCalign2010.dump",1);
  diff  TPCalign2013.dump TPCalign2010.dump > TPCalign2013_TPCalign2010.diff
  //
  //
=================================================================================================================
//  2.)
  // Compare CluterParam OCDB etry
  //
  DumpOCDBFile("/cvmfs/alice.gsi.de/alice/data/2010/OCDB/TPC/Calib/ClusterParam/Run131541_999999999_v2_s0.root","2010_TPC_Calib_ClusterParam_Run131541_999999999_v2_s0.dump",1);
  DumpOCDBFile("/cvmfs/alice.gsi.de/alice/data/2010/OCDB/TPC/Calib/ClusterParam/Run0_999999999_v1_s0.root","2010_TPC_Calib_ClusterParam_Run0_999999999_v1_s0.dump",1);
  DumpOCDBFile("/cvmfs/alice.gsi.de/alice/data/2013/OCDB/TPC/Calib/ClusterParam/Run0_999999999_v1_s0.root","2013_TPC_Calib_ClusterParam_Run0_999999999_v1_s0.dump",1);

  diff 2010_TPC_Calib_ClusterParam_Run131541_999999999_v2_s0.dump 2010_TPC_Calib_ClusterParam_Run0_999999999_v1_s0.dump

*/
#if !defined(__CINT__) || defined(__MAKECINT__)
#include "TMath.h"
#include "TFile.h"
#include "TTree.h"
#include <TVectorF.h>
#include <TLinearFitter.h>
#include <TH1F.h>
#include <TH3F.h>
#include <TProfile2D.h>
#include <TVectorD.h>
#include <TObjArray.h>
#include "THnBase.h"
#include "TRealData.h"
#include "TDataMember.h"
#include "TClass.h"
#include "AliCDBEntry.h"
#include "TObjArray.h"
#include "TNamed.h"
#include "TROOT.h"
#endif

void DumpObjectRecursive(TObject *obj);
void DumpObjectRecursive(TObject *obj, TString prefix, Int_t &counterRec);

void ExampleUse(){
  //
  //
  //
  TFile *f = TFile::Open("/cvmfs/alice.gsi.de/alice/simulation/2008/v4-15-Release/Residual/TPC/Calib/ClusterParam/Run127712_130850_v3_s0.root");
  //TFile *f = TFile::Open("./OCDB_NoClustersBelowThreshold/TPC/Calib/RecoParam/Run127712_130850_v0_s0.root");
  AliCDBEntry * entry = (AliCDBEntry*)f->Get("AliCDBEntry");
  TObject  *obj = ( TObject*)entry->GetObject();
  DumpObjectRecursive(obj);
  //
  //
}

void DumpOCDBFile(const char *finput , const char *foutput, Bool_t dumpMetaData, Bool_t xml){
  //
  //
  //  DumpOCDBFile("$ALICE_ROOT/OCDB/ITS/Align/Data/Run0_999999999_v0_s0.root", "ITS_Align_Data_Run0_999999999_v0_s0.dump")
  //
  if (finput==0) return ;
  TFile *falignITS  = TFile::Open(finput);
  AliCDBEntry *entry  = (AliCDBEntry*)falignITS->Get("AliCDBEntry");
  if (!entry) return;
  TObject *obj = ((AliCDBEntry*)falignITS->Get("AliCDBEntry"))->GetObject();

  //
  if (!xml){
    if (dumpMetaData) gROOT->ProcessLine(TString::Format("((TObject*)%p)->Dump(); >%s",entry, foutput).Data());
    if (!obj) return;
    gROOT->ProcessLine(TString::Format("DumpObjectRecursive((TObject*)%p); >>%s",obj, foutput).Data());
  }
  if (xml){
    TFile * f = TFile::Open(TString::Format("%s.xml",foutput).Data(),"recreate");
    if (dumpMetaData) entry->Write("AliCDBEntry");
    else obj->Write("AliCDBEntry");
    f->Close();
  }
}

void DumpObjectRecursive(TObject *obj){
  //
  //
  //
  Int_t counterRec=0;
  printf("==> Dumping object at: %p, name=%s, class=%s)\n", obj, obj->GetName(), (obj->IsA()->GetName()));
  DumpObjectRecursive(obj, TString(obj->IsA()->GetName())+".",counterRec);
}

//
//
//
void DumpObjectRecursive(TObject *obj, TString prefix, Int_t &counterRec){
  //
  // Recursive dump of the TObject
  // Dump all basic types and follow pointers to the objects
  // current limitation:
  //    a.) clases and structures not derived from TObject not followed (to fix)
  //    b.) dynamic arrays not followed
  //    c.) std maps,array ....  not followed
  //
  //
  if (!obj) return;
  //
  // Special case of Collection classes
  //
  if (obj->IsA()->InheritsFrom(TCollection::Class())) {
    TIter myiter((TCollection*)obj);
    TObject  *arObject=0;
    Int_t counter=0;
    while ((arObject = (TObject*)myiter.Next())) {
      TString prefixArr = TString::Format("%s[%d]",prefix.Data(),counter);
      DumpObjectRecursive(arObject,prefixArr,counterRec);
      counter++;
    }
    counterRec++;
    return;
  }

  TClass * cl = obj->IsA();
  if (!(cl->GetListOfRealData())) cl->BuildRealData();
  TRealData* rd = 0;
  TIter next(cl->GetListOfRealData());
  while ((rd = (TRealData*) next())) {
    counterRec++;
    TDataMember* dm = rd->GetDataMember();
    TDataType* dtype = dm->GetDataType();
    Int_t offset = rd->GetThisOffset();
    char* pointer = ((char*) obj) + offset;

    if (dm->IsaPointer()) {
      // We have a pointer to an object or a pointer to an array of basic types.
      TClass* clobj = 0;
      if (!dm->IsBasic()) {
	clobj = TClass::GetClass(dm->GetTypeName());
      }
      if (clobj) {
	// We have a pointer to an object.
	//
	if (!clobj->InheritsFrom(TObject::Class())) {
	  // It must be a TObject object.
	  continue;
	}
	char** apointer = (char**) pointer;
	TObject* robj = (TObject*) *apointer;
	//
	if(!robj)
	  printf("M:%s%s\n",prefix.Data(),dm->GetName()); // Missing - 0 pointer
	else{
	  printf("T:%s\t%s%s\n", clobj->GetName(),prefix.Data(), dm->GetName());
	  TString prefixNew=prefix;
	  prefixNew+=dm->GetName();
	  prefixNew+=".";
	  if (robj!=obj) DumpObjectRecursive(robj,prefixNew,counterRec);  // trivial check
	  if (robj==obj){
	    printf("R:%s\t%s%s\n",clobj->GetName(),prefix.Data(), dm->GetName());
	  }
	}
      }
    } else if (dm->IsBasic()) {
      //
      // Basic data type
      //
      const char* index = dm->GetArrayIndex();
      if (dm->GetArrayDim()==0){
	printf("B:\t%s%s\t%s\n", prefix.Data(),rd->GetName(), dtype->AsString(pointer));
      }
      //
      // Basic array - fixed length
      //
      //      if (dm->GetArrayDim()>0 && strlen(index) != 0){
      if (dm->GetArrayDim()>0 ){
	printf("A:\t%s%s\t",prefix.Data(),rd->GetName());
	Int_t counter=0;
	for  (Int_t idim=0; idim<dm->GetArrayDim(); idim++){
	  //printf("A:%d\t%d\n", dm->GetArrayDim(),dm->GetMaxIndex(idim));
	  for (Int_t j=0; j<dm->GetMaxIndex(idim); j++){
	    printf("%s\t",dtype->AsString(pointer+dm->GetUnitSize()*counter));
	    counter++;
	    if (counter%5==0) printf("\nA:\t%s%s\t",prefix.Data(),rd->GetName());
	  }
	}
	printf("\n");
      }
      //
      // Basic array - dynamic length
      //
      if (dm->GetArrayDim()>0 && strlen(index) != 0){
	//
	// Dump first only for the moment
	//
	printf("B:\t%s%s\t%s\n",prefix.Data(),rd->GetName(), dtype->AsString(pointer));
      }
    } else {
    }
  }
}

//
// Small checks to test the TRealData and TDataType
//

void DumpDataSimple(){
  //
  // Dump example for elenatr data types
  //
  TObject *obj = new TVectorD(20);
  TClass * cl = obj->IsA();
  if (!cl->GetListOfRealData()) cl->BuildRealData();
  //
  TRealData* rd = 0;
  rd = (TRealData*)(cl->GetListOfRealData()->FindObject("fNrows"));
  TDataMember* dm = rd->GetDataMember();
  TDataType* dtype = dm->GetDataType();
  //
  Int_t offset = rd->GetThisOffset();
  char* pointer = ((char*) obj) + offset;
  printf("%s\n",dtype->AsString(pointer));

}

void DumpDataArray(){
  //
  // print array example
  //
  TObject *obj = new TVectorD(20);
  TClass * cl = obj->IsA();
  if (!cl->GetListOfRealData()) cl->BuildRealData();
  TRealData* rd = 0;
  rd = (TRealData*)(cl->GetListOfRealData()->FindObject("*fElements"));
  TDataMember* dm = rd->GetDataMember();
  TDataType* dtype = dm->GetDataType();
  dtype->Print();
  //
  Int_t offset = rd->GetThisOffset();
  char* pointer = ((char*) obj) + offset;
  printf("%s\n",dtype->AsString(pointer));
}

void DumpTObjectArray(){
  //
  //
  //
  TObjArray *array = new TObjArray(10);
  for (Int_t i=0; i<10; i++) array->AddLast(new TNamed(Form("n%d",i), Form("n%d",i)));
  DumpObjectRecursive(array);
  //
  //
  TObject *obj = array;
  TClass * cl = obj->IsA();
  if (!cl->GetListOfRealData()) cl->BuildRealData();
  TRealData* rd = 0;
  rd = (TRealData*)(cl->GetListOfRealData()->FindObject("*fCont"));
  TDataMember* dm = rd->GetDataMember();
  TDataType* dtype = dm->GetDataType();
  //
  Int_t offset = rd->GetThisOffset();
  char* pointer = ((char*) obj) + offset;
  char** apointer = (char**) pointer;
  //we have pointer to pointer here
  TObject** ppobj = (TObject**) *apointer;
  (*ppobj)->Print();
  //
  TIter myiter(array);
  TObject  *arObject;
  dtype->Print();
  while ((arObject = (TObject*)myiter.Next())) {
    DumpObjectRecursive(arObject);
  }

}
<commit_msg>Equivalent code in the official  AliRoot<commit_after><|endoftext|>


<commit_before>#pragma once

#include <algorithm>   // fill
#include <cassert>
#include <functional>  // hash
#include <tuple>
#include <type_traits> // enable_if
#include <utility>     // make_pair, pair

#include "sdd/util/next_power.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace mem {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief It must be stored by the hash table's data as a member named 'hook'.
template <typename Data>
struct intrusive_member_hook
{
  /// @brief Store the next data in a bucket.
  mutable Data* next = nullptr;
};

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief An intrusive hash table.
///
/// It's modeled after boost::intrusive. Only the interfaces needed by the libsdd are implemented.
/// It uses chaining to handle collisions.
template <typename Data, bool Rehash = true>
class hash_table
{
public:

  /// @brief Used by insert_check
  struct insert_commit_data
  {
    Data** bucket;
  };

private:

  /// @brief
  std::size_t nb_buckets_;

  /// @brief
  std::size_t size_;

  /// @brief
  Data** buckets_;

  /// @brief The maximal allowed load factor.
  const double max_load_factor_;

  /// @brief The number of times this hash table has been rehashed.
  std::size_t nb_rehash_;

public:

  hash_table(std::size_t size, double max_load_factor = 0.75)
    : nb_buckets_(util::next_power_of_2(size))
    , size_(0)
    , buckets_(new Data*[nb_buckets_])
    , max_load_factor_(max_load_factor)
    , nb_rehash_(0)
  {
    std::fill(buckets_, buckets_ + nb_buckets_, nullptr);
  }

  ~hash_table()
  {
    delete[] buckets_;
  }

  template <typename T, typename EqT>
  std::pair<Data*, bool>
  insert_check(const T& x, EqT eq, insert_commit_data& commit_data)
  const noexcept(noexcept(std::hash<T>()(x)))
  {
    static_assert(not Rehash, "Use with fixed-size hash table only");

    const std::size_t pos = std::hash<T>()(x) & (nb_buckets_ - 1);

    Data* current = buckets_[pos];
    commit_data.bucket = buckets_ + pos;

    while (current != nullptr)
    {
      if (eq(x, *current))
      {
        return {current, false};
      }
      current = current->hook.next;
    }

    return {current, true};
  }

  void
  insert_commit(Data* x, insert_commit_data& commit_data)
  noexcept
  {
    static_assert(not Rehash, "Use with fixed-size hash table only");
    assert(x != nullptr);

    Data* previous = nullptr;
    Data* current = *commit_data.bucket;

    // We append x at the end of the bucket, it seems to be faster than appending it directly
    // in front.
    while (current != nullptr)
    {
      previous = current;
      current = current->hook.next;
    }

    if (previous != nullptr)
    {
      previous->hook.next = x;
    }
    else
    {
      *commit_data.bucket = x;
    }

    ++size_;
  }

  /// @brief Insert an element.
  std::pair<Data*, bool>
  insert(Data* x)
  {
    auto res = insert_impl(x, buckets_, nb_buckets_);
    rehash<Rehash>();
    return res;
  }

  /// @brief Return the number of elements.
  std::size_t
  size()
  const noexcept
  {
    return size_;
  }

  /// @brief Return the number of buckets.
  std::size_t
  bucket_count()
  const noexcept
  {
    return nb_buckets_;
  }

  /// @brief Remove an element given its value.
  void
  erase(const Data* x)
  noexcept
  {
    const std::size_t pos = std::hash<Data>()(*x) & (nb_buckets_ - 1);
    Data* previous = nullptr;
    Data* current = buckets_[pos];
    while (current != nullptr)
    {
      if (*x == *current)
      {
        if (previous == nullptr) // first element in bucket
        {
          buckets_[pos] = current->hook.next;
        }
        else
        {
          previous->hook.next = current->hook.next;
        }
        --size_;
        return;
      }
      previous = current;
      current = current->hook.next;
    }
    assert(false && "Data to erase not found");
  }

  /// @brief Clear the whole table.
  template <typename Disposer>
  void
  clear_and_dispose(Disposer disposer)
  {
    for (std::size_t i = 0; i < nb_buckets_; ++i)
    {
      Data* current = buckets_[i];
      while (current != nullptr)
      {
        const auto to_erase = current;
        current = current->hook.next;
        disposer(to_erase);
      }
      buckets_[i] = nullptr;
    }
    size_ = 0;
  }

  /// @brief Get the load factor of the internal hash table.
  double
  load_factor()
  const noexcept
  {
    return static_cast<double>(size()) / static_cast<double>(bucket_count());
  }

  /// @brief The number of times this hash table has been rehashed.
  std::size_t
  nb_rehash()
  const noexcept
  {
    return nb_rehash_;
  }

  /// @brief The number of collisions.
  std::tuple<std::size_t /* collisions */, std::size_t /* alone */, std::size_t /* empty */>
  collisions()
  const noexcept
  {
    std::size_t col = 0;
    std::size_t alone = 0;
    std::size_t empty = 0;
    for (auto i = 0ul; i < nb_buckets_; ++i)
    {
      std::size_t nb = 0;
      auto current = buckets_[i];
      while (current != nullptr)
      {
        ++nb;
        current = current->hook.next;
      }
      if      (nb == 0) ++empty;
      else if (nb == 1) ++alone;
      else if (nb > 1)  ++col;
    }
    return std::make_tuple(col, alone, empty);
  }

private:

  template<bool DoRehash>
  std::enable_if_t<DoRehash, void>
  rehash()
  {
    if (load_factor() < max_load_factor_) // no need to rehash
    {
      return;
    }
    ++nb_rehash_;
    auto new_nb_buckets = nb_buckets_ * 2;
    auto new_buckets = new Data*[new_nb_buckets];
    std::fill(new_buckets, new_buckets + new_nb_buckets, nullptr);
    size_ = 0;
    for (std::size_t i = 0; i < nb_buckets_; ++i)
    {
      Data* data_ptr = buckets_[i];
      while (data_ptr)
      {
        Data* next = data_ptr->hook.next;
        data_ptr->hook.next = nullptr;
        insert_impl(data_ptr, new_buckets, new_nb_buckets);
        data_ptr = next;
      }
      // else empty bucket
    }
    std::swap(new_buckets, buckets_);
    std::swap(new_nb_buckets, nb_buckets_);
    delete[] new_buckets;
  }

  template<bool DoRehash>
  std::enable_if_t<not DoRehash, void>
  rehash()
  noexcept
  {}

  /// @brief Insert an element.
  std::pair<Data*, bool>
  insert_impl(Data* x, Data** buckets, std::size_t nb_buckets)
  noexcept(noexcept(std::hash<Data>()(*x)))
  {
    const std::size_t pos = std::hash<Data>()(*x) & (nb_buckets - 1);

    Data* current = buckets[pos];

    while (current != nullptr)
    {
      if (*x == *current)
      {
        return {current, false /* no insertion */};
      }
      current = current->hook.next;
    }

    // Push in front of the list.
    x->hook.next = buckets[pos];
    buckets[pos] = x;

    current = x;
    ++size_;
    return {current, true /* insertion */};
  }
};

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::mem
<commit_msg>Remove useless affectation<commit_after>#pragma once

#include <algorithm>   // fill
#include <cassert>
#include <functional>  // hash
#include <tuple>
#include <type_traits> // enable_if
#include <utility>     // make_pair, pair

#include "sdd/util/next_power.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace mem {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief It must be stored by the hash table's data as a member named 'hook'.
template <typename Data>
struct intrusive_member_hook
{
  /// @brief Store the next data in a bucket.
  mutable Data* next = nullptr;
};

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief An intrusive hash table.
///
/// It's modeled after boost::intrusive. Only the interfaces needed by the libsdd are implemented.
/// It uses chaining to handle collisions.
template <typename Data, bool Rehash = true>
class hash_table
{
public:

  /// @brief Used by insert_check
  struct insert_commit_data
  {
    Data** bucket;
  };

private:

  /// @brief
  std::size_t nb_buckets_;

  /// @brief
  std::size_t size_;

  /// @brief
  Data** buckets_;

  /// @brief The maximal allowed load factor.
  const double max_load_factor_;

  /// @brief The number of times this hash table has been rehashed.
  std::size_t nb_rehash_;

public:

  hash_table(std::size_t size, double max_load_factor = 0.75)
    : nb_buckets_(util::next_power_of_2(size))
    , size_(0)
    , buckets_(new Data*[nb_buckets_])
    , max_load_factor_(max_load_factor)
    , nb_rehash_(0)
  {
    std::fill(buckets_, buckets_ + nb_buckets_, nullptr);
  }

  ~hash_table()
  {
    delete[] buckets_;
  }

  template <typename T, typename EqT>
  std::pair<Data*, bool>
  insert_check(const T& x, EqT eq, insert_commit_data& commit_data)
  const noexcept(noexcept(std::hash<T>()(x)))
  {
    static_assert(not Rehash, "Use with fixed-size hash table only");

    const std::size_t pos = std::hash<T>()(x) & (nb_buckets_ - 1);

    Data* current = buckets_[pos];
    commit_data.bucket = buckets_ + pos;

    while (current != nullptr)
    {
      if (eq(x, *current))
      {
        return {current, false};
      }
      current = current->hook.next;
    }

    return {current, true};
  }

  void
  insert_commit(Data* x, insert_commit_data& commit_data)
  noexcept
  {
    static_assert(not Rehash, "Use with fixed-size hash table only");
    assert(x != nullptr);

    Data* previous = nullptr;
    Data* current = *commit_data.bucket;

    // We append x at the end of the bucket, it seems to be faster than appending it directly
    // in front.
    while (current != nullptr)
    {
      previous = current;
      current = current->hook.next;
    }

    if (previous != nullptr)
    {
      previous->hook.next = x;
    }
    else
    {
      *commit_data.bucket = x;
    }

    ++size_;
  }

  /// @brief Insert an element.
  std::pair<Data*, bool>
  insert(Data* x)
  {
    auto res = insert_impl(x, buckets_, nb_buckets_);
    rehash<Rehash>();
    return res;
  }

  /// @brief Return the number of elements.
  std::size_t
  size()
  const noexcept
  {
    return size_;
  }

  /// @brief Return the number of buckets.
  std::size_t
  bucket_count()
  const noexcept
  {
    return nb_buckets_;
  }

  /// @brief Remove an element given its value.
  void
  erase(const Data* x)
  noexcept
  {
    const std::size_t pos = std::hash<Data>()(*x) & (nb_buckets_ - 1);
    Data* previous = nullptr;
    Data* current = buckets_[pos];
    while (current != nullptr)
    {
      if (*x == *current)
      {
        if (previous == nullptr) // first element in bucket
        {
          buckets_[pos] = current->hook.next;
        }
        else
        {
          previous->hook.next = current->hook.next;
        }
        --size_;
        return;
      }
      previous = current;
      current = current->hook.next;
    }
    assert(false && "Data to erase not found");
  }

  /// @brief Clear the whole table.
  template <typename Disposer>
  void
  clear_and_dispose(Disposer disposer)
  {
    for (std::size_t i = 0; i < nb_buckets_; ++i)
    {
      Data* current = buckets_[i];
      while (current != nullptr)
      {
        const auto to_erase = current;
        current = current->hook.next;
        disposer(to_erase);
      }
      buckets_[i] = nullptr;
    }
    size_ = 0;
  }

  /// @brief Get the load factor of the internal hash table.
  double
  load_factor()
  const noexcept
  {
    return static_cast<double>(size()) / static_cast<double>(bucket_count());
  }

  /// @brief The number of times this hash table has been rehashed.
  std::size_t
  nb_rehash()
  const noexcept
  {
    return nb_rehash_;
  }

  /// @brief The number of collisions.
  std::tuple<std::size_t /* collisions */, std::size_t /* alone */, std::size_t /* empty */>
  collisions()
  const noexcept
  {
    std::size_t col = 0;
    std::size_t alone = 0;
    std::size_t empty = 0;
    for (auto i = 0ul; i < nb_buckets_; ++i)
    {
      std::size_t nb = 0;
      auto current = buckets_[i];
      while (current != nullptr)
      {
        ++nb;
        current = current->hook.next;
      }
      if      (nb == 0) ++empty;
      else if (nb == 1) ++alone;
      else if (nb > 1)  ++col;
    }
    return std::make_tuple(col, alone, empty);
  }

private:

  template<bool DoRehash>
  std::enable_if_t<DoRehash, void>
  rehash()
  {
    if (load_factor() < max_load_factor_) // no need to rehash
    {
      return;
    }
    ++nb_rehash_;
    auto new_nb_buckets = nb_buckets_ * 2;
    auto new_buckets = new Data*[new_nb_buckets];
    std::fill(new_buckets, new_buckets + new_nb_buckets, nullptr);
    size_ = 0;
    for (std::size_t i = 0; i < nb_buckets_; ++i)
    {
      Data* data_ptr = buckets_[i];
      while (data_ptr)
      {
        Data* next = data_ptr->hook.next;
        data_ptr->hook.next = nullptr;
        insert_impl(data_ptr, new_buckets, new_nb_buckets);
        data_ptr = next;
      }
      // else empty bucket
    }
    std::swap(new_buckets, buckets_);
    std::swap(new_nb_buckets, nb_buckets_);
    delete[] new_buckets;
  }

  template<bool DoRehash>
  std::enable_if_t<not DoRehash, void>
  rehash()
  noexcept
  {}

  /// @brief Insert an element.
  std::pair<Data*, bool>
  insert_impl(Data* x, Data** buckets, std::size_t nb_buckets)
  noexcept(noexcept(std::hash<Data>()(*x)))
  {
    const std::size_t pos = std::hash<Data>()(*x) & (nb_buckets - 1);

    Data* current = buckets[pos];

    while (current != nullptr)
    {
      if (*x == *current)
      {
        return {current, false /* no insertion */};
      }
      current = current->hook.next;
    }

    // Push in front of the list.
    x->hook.next = buckets[pos];
    buckets[pos] = x;

    ++size_;
    return {x, true /* insertion */};
  }
};

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::mem
<|endoftext|>