<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.11  2007/04/04 10:29:18  jgrosseo
1) Storing of files to the Grid is now done _after_ your preprocessors succeeded. This is transparent, which means that you can still use the same functions (Store, StoreReferenceData) to store files to the Grid. However, the Shuttle first stores them locally and transfers them after the preprocessor finished. The return code of these two functions has changed from UInt_t to Bool_t which gives you the success of the storing.
In case of an error with the Grid, the Shuttle will retry the storing later, the preprocessor does not need to be run again.

2) The meaning of the return code of the preprocessor has changed. 0 is now success and any other value means failure. This value is stored in the log and you can use it to keep details about the error condition.

3) New function StoreReferenceFile to _directly_ store a file (without opening it) to the reference storage.

4) The memory usage of the preprocessor is monitored. If it exceeds 2 GB it is terminated.

5) New function AliPreprocessor::ProcessDCS(). If you do not need to have DCS data in all cases, you can skip the processing by implemting this function and returning kFALSE under certain conditions. E.g. if there is a certain run type.
If you always need DCS data (like before), you do not need to implement it.

6) The run type has been added to the monitoring page

Revision 1.9  2007/02/28 10:42:58  acolla
Run type field added in SHUTTLE framework. Run type is read from "run type" logbook and retrieved by
AliPreprocessor::GetRunType() function.

Revision 1.7  2006/11/06 14:24:21  jgrosseo
reading of run parameters from the logbook
online offline naming conversion

Revision 1.6  2006/10/02 12:57:48  jgrosseo
Small interface change of function StoreReferenceData in Shuttle

Revision 1.5  2006/09/04 17:42:34  hristov
Changes required by Effective C++

Revision 1.4  2006/08/08 14:20:49  jgrosseo
Update to shuttle classes (Alberto)

- Possibility to set the full object's path in the Preprocessor's and
Shuttle's  Store functions
- Possibility to extend the object's run validity in the same classes
("startValidity" and "validityInfinite" parameters)
- Implementation of the StoreReferenceData function to store reference
data in a dedicated CDB storage.

Revision 1.3  2006/07/11 12:42:43  jgrosseo
adding parameters for extended validity range of data produced by preprocessor

Revision 1.2  2006/06/06 16:36:49  jgrosseo
minor changes in AliShuttleInterface and AliPreprocessor

Revision 1.1  2006/06/02 14:14:36  hristov
Separate library for CDB (Jan)

Revision 1.2  2006/03/07 07:52:34  hristov
New version (B.Yordanov)

Revision 1.3  2005/11/17 17:47:34  byordano
TList changed to TObjArray

Revision 1.2  2005/11/17 14:43:22  byordano
import to local CVS

Revision 1.1.1.1  2005/10/28 07:33:58  hristov
Initial import as subdirectory in AliRoot

Revision 1.1.1.1  2005/09/12 22:11:40  byordano
SHUTTLE package

Revision 1.2  2005/08/29 21:15:47  byordano
some docs added

*/

// Description:
// This class is the CDBPreProcessor interface,
// supposed to be implemented by any detector
// interested in immediate processing of data
// which is retrieved from DCS.
// For every particular run set of aliases and
// their corespoding value sets are returned.
// Usage schema:
//	1) virtual void Initialize(Int_t run, UInt_t startTime, UInt_t endTime)
//	This method is called at the begining of data retrieval.
//	run: run number
//	startTime: when the run started
//	endTime: when the run finished
//
//	2) virtual void Process()
//
//	This method is called and passed a list of retrieved values from DCS
//
//

#include "AliPreprocessor.h"

#include <TString.h>
#include <TList.h>
#include <TMap.h>

#include "AliLog.h"
#include "AliCDBMetaData.h"
#include "AliCDBStorage.h"
#include "AliCDBId.h"
#include "AliCDBPath.h"
#include "AliCDBEntry.h"
#include "AliShuttleInterface.h"

ClassImp(AliPreprocessor)

//______________________________________________________________________________________________
AliPreprocessor::AliPreprocessor(const char* detector, AliShuttleInterface* shuttle) :
  TNamed(detector, ""),
  fRun(-1),
  fStartTime(0),
  fEndTime(0),
  fShuttle(shuttle)
{
	SetTitle(Form("AliPreprocessor for %s subdetector.", detector));

  if (!fShuttle)
  {
    AliFatal("Initialized without Shuttle instance.");
    return;
  }

  fShuttle->RegisterPreprocessor(this);
}

//______________________________________________________________________________________________
AliPreprocessor::~AliPreprocessor()
{
}

//______________________________________________________________________________________________
void AliPreprocessor::Initialize(Int_t run, UInt_t startTime,	UInt_t endTime)
{
  // Sets the information of the run which is currently processed
  // can be overriden for special behaviour, make sure that you call base class
  // function

  fRun = run;
  fStartTime = startTime;
  fEndTime = endTime;
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::Store(const char* pathLevel2, const char* pathLevel3, TObject* object,
		AliCDBMetaData* metaData, Int_t validityStart, Bool_t validityInfinite)
{
  // Stores a CDB object in the storage for offline reconstruction. Objects that are not needed for
  // offline reconstruction, but should be stored anyway (e.g. for debugging) should NOT be stored
  // using this function. Use StoreReferenceData instead!
  //
  // This function should be called at the end of the preprocessor cycle
  //
  // The parameters are
  //   1, 2) the 2nd and 3rd level of the object's path. The first level is the detector name which is provided
  //         by the Preprocessor and converted to the Offline name. Thus the object's path is "DET/level2/level3"
  //   3) the object to be stored
  //   4) the metaData to be associated with the object
  //   5) the validity start run number w.r.t. the current run,
  //      if the data is valid only for this run leave the default 0
  //   6) specifies if the calibration data is valid for infinity (this means until updated),
  //      typical for calibration runs, the default is kFALSE
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if(!offlineDetName) return 0;

  return fShuttle->Store(AliCDBPath(offlineDetName, pathLevel2, pathLevel3), object,
  		metaData, validityStart, validityInfinite);
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::StoreReferenceData(const char* pathLevel2, const char* pathLevel3, TObject* object,
		AliCDBMetaData* metaData)
{
  // Stores a CDB object in the storage for reference data. This objects will not be available during
  // offline reconstrunction. Use this function for reference data only!
  //
  // This function should be called at the end of the preprocessor cycle
  //
  // The parameters are
  //   1, 2) the 2nd and 3rd level of the object's path. The first level is the detector name which is provided
  //         by the Preprocessor and converted to the Offline name. Thus the object's path is "DET/level2/level3"
  //   3) the object to be stored
  //   4) the metaData to be associated with the object
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if(!offlineDetName) return 0;

  return fShuttle->StoreReferenceData(AliCDBPath(offlineDetName, pathLevel2, pathLevel3), object,
  		metaData);
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::StoreReferenceFile(const char* localFile, const char* gridFileName)
{
	//
	// Stores a file directly (without opening it) in the reference storage in the Grid
	//
	// The call is delegated to AliShuttleInterface

	const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  	if(!offlineDetName) return 0;
	return fShuttle->StoreReferenceFile(GetName(), localFile, gridFileName);
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetFile(Int_t system, const char* id, const char* source)
{
  // This function retrieves a file from the given system (kDAQ, kDCS, kHLT) with the given file id
  // and from the given source in the system.
  // The function returnes the path to the local file.
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetFile(system, GetName(), id, source);
}

//______________________________________________________________________________________________
TList* AliPreprocessor::GetFileSources(Int_t system, const char* id)
{
  // Returns a list of sources in a given system that saved a file with the given id
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetFileSources(system, GetName(), id);
}

//______________________________________________________________________________________________
void AliPreprocessor::Log(const char* message)
{
  // Adds a log message to the Shuttle log of this preprocessor
  //
  // The call is delegated to AliShuttleInterface

  fShuttle->Log(GetName(), message);
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetRunParameter(const char* param)
{
  // Return run parameter read from run logbook
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetRunParameter(param);
}

//______________________________________________________________________________________________
AliCDBEntry* AliPreprocessor::GetFromOCDB(const char* pathLevel2, const char* pathLevel3)
{
  // Return object from OCDB valid for current run
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if (!offlineDetName) return 0;

  return dynamic_cast<AliCDBEntry*>
  	(fShuttle->GetFromOCDB(GetName(), AliCDBPath(offlineDetName, pathLevel2, pathLevel3)));
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetRunType()
{
  // Return run type string read from "run type" logbook
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetRunType();
}
<commit_msg>updated commment<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.12  2007/04/05 08:05:55  acolla
Conversion from online to offline detector name in StoreReferenceFile

Revision 1.11  2007/04/04 10:29:18  jgrosseo
1) Storing of files to the Grid is now done _after_ your preprocessors succeeded. This is transparent, which means that you can still use the same functions (Store, StoreReferenceData) to store files to the Grid. However, the Shuttle first stores them locally and transfers them after the preprocessor finished. The return code of these two functions has changed from UInt_t to Bool_t which gives you the success of the storing.
In case of an error with the Grid, the Shuttle will retry the storing later, the preprocessor does not need to be run again.

2) The meaning of the return code of the preprocessor has changed. 0 is now success and any other value means failure. This value is stored in the log and you can use it to keep details about the error condition.

3) New function StoreReferenceFile to _directly_ store a file (without opening it) to the reference storage.

4) The memory usage of the preprocessor is monitored. If it exceeds 2 GB it is terminated.

5) New function AliPreprocessor::ProcessDCS(). If you do not need to have DCS data in all cases, you can skip the processing by implemting this function and returning kFALSE under certain conditions. E.g. if there is a certain run type.
If you always need DCS data (like before), you do not need to implement it.

6) The run type has been added to the monitoring page

Revision 1.9  2007/02/28 10:42:58  acolla
Run type field added in SHUTTLE framework. Run type is read from "run type" logbook and retrieved by
AliPreprocessor::GetRunType() function.

Revision 1.7  2006/11/06 14:24:21  jgrosseo
reading of run parameters from the logbook
online offline naming conversion

Revision 1.6  2006/10/02 12:57:48  jgrosseo
Small interface change of function StoreReferenceData in Shuttle

Revision 1.5  2006/09/04 17:42:34  hristov
Changes required by Effective C++

Revision 1.4  2006/08/08 14:20:49  jgrosseo
Update to shuttle classes (Alberto)

- Possibility to set the full object's path in the Preprocessor's and
Shuttle's  Store functions
- Possibility to extend the object's run validity in the same classes
("startValidity" and "validityInfinite" parameters)
- Implementation of the StoreReferenceData function to store reference
data in a dedicated CDB storage.

Revision 1.3  2006/07/11 12:42:43  jgrosseo
adding parameters for extended validity range of data produced by preprocessor

Revision 1.2  2006/06/06 16:36:49  jgrosseo
minor changes in AliShuttleInterface and AliPreprocessor

Revision 1.1  2006/06/02 14:14:36  hristov
Separate library for CDB (Jan)

Revision 1.2  2006/03/07 07:52:34  hristov
New version (B.Yordanov)

Revision 1.3  2005/11/17 17:47:34  byordano
TList changed to TObjArray

Revision 1.2  2005/11/17 14:43:22  byordano
import to local CVS

Revision 1.1.1.1  2005/10/28 07:33:58  hristov
Initial import as subdirectory in AliRoot

Revision 1.1.1.1  2005/09/12 22:11:40  byordano
SHUTTLE package

Revision 1.2  2005/08/29 21:15:47  byordano
some docs added

*/

// Description:
// This class is the CDBPreProcessor interface,
// supposed to be implemented by any detector
// interested in immediate processing of data
// which is retrieved from DCS.
// For every particular run set of aliases and
// their corespoding value sets are returned.
// Usage schema:
//	1) virtual void Initialize(Int_t run, UInt_t startTime, UInt_t endTime)
//	This method is called at the begining of data retrieval.
//	run: run number
//	startTime: when the run started
//	endTime: when the run finished
//
//	2) virtual void Process()
//
//	This method is called and passed a list of retrieved values from DCS
//
//

#include "AliPreprocessor.h"

#include <TString.h>
#include <TList.h>
#include <TMap.h>

#include "AliLog.h"
#include "AliCDBMetaData.h"
#include "AliCDBStorage.h"
#include "AliCDBId.h"
#include "AliCDBPath.h"
#include "AliCDBEntry.h"
#include "AliShuttleInterface.h"

ClassImp(AliPreprocessor)

//______________________________________________________________________________________________
AliPreprocessor::AliPreprocessor(const char* detector, AliShuttleInterface* shuttle) :
  TNamed(detector, ""),
  fRun(-1),
  fStartTime(0),
  fEndTime(0),
  fShuttle(shuttle)
{
	SetTitle(Form("AliPreprocessor for %s subdetector.", detector));

  if (!fShuttle)
  {
    AliFatal("Initialized without Shuttle instance.");
    return;
  }

  fShuttle->RegisterPreprocessor(this);
}

//______________________________________________________________________________________________
AliPreprocessor::~AliPreprocessor()
{
}

//______________________________________________________________________________________________
void AliPreprocessor::Initialize(Int_t run, UInt_t startTime,	UInt_t endTime)
{
  // Sets the information of the run which is currently processed
  // can be overriden for special behaviour, make sure that you call base class
  // function

  fRun = run;
  fStartTime = startTime;
  fEndTime = endTime;
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::Store(const char* pathLevel2, const char* pathLevel3, TObject* object,
		AliCDBMetaData* metaData, Int_t validityStart, Bool_t validityInfinite)
{
  // Stores a CDB object in the storage for offline reconstruction. Objects that are not needed for
  // offline reconstruction, but should be stored anyway (e.g. for debugging) should NOT be stored
  // using this function. Use StoreReferenceData instead!
  //
  // This function should be called at the end of the preprocessor cycle
  //
  // The parameters are
  //   1, 2) the 2nd and 3rd level of the object's path. The first level is the detector name which is provided
  //         by the Preprocessor and converted to the Offline name. Thus the object's path is "DET/level2/level3"
  //   3) the object to be stored
  //   4) the metaData to be associated with the object
  //   5) the validity start run number w.r.t. the current run,
  //      if the data is valid only for this run leave the default 0
  //   6) specifies if the calibration data is valid for infinity (this means until updated),
  //      typical for calibration runs, the default is kFALSE
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if(!offlineDetName) return 0;

  return fShuttle->Store(AliCDBPath(offlineDetName, pathLevel2, pathLevel3), object,
  		metaData, validityStart, validityInfinite);
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::StoreReferenceData(const char* pathLevel2, const char* pathLevel3, TObject* object,
		AliCDBMetaData* metaData)
{
  // Stores a CDB object in the storage for reference data. This objects will not be available during
  // offline reconstrunction. Use this function for reference data only!
  //
  // This function should be called at the end of the preprocessor cycle
  //
  // The parameters are
  //   1, 2) the 2nd and 3rd level of the object's path. The first level is the detector name which is provided
  //         by the Preprocessor and converted to the Offline name. Thus the object's path is "DET/level2/level3"
  //   3) the object to be stored
  //   4) the metaData to be associated with the object
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if(!offlineDetName) return 0;

  return fShuttle->StoreReferenceData(AliCDBPath(offlineDetName, pathLevel2, pathLevel3), object,
  		metaData);
}

//______________________________________________________________________________________________
Bool_t AliPreprocessor::StoreReferenceFile(const char* localFile, const char* gridFileName)
{
	//
	// Stores a file directly (without opening it) in the reference storage in the Grid
	//
	// The file is stored under the following location:
	// <base folder of reference storage>/<DET>/<RUN#>_<gridFileName>
	// where <gridFileName> is the second parameter given to the function
	//
	// The call is delegated to AliShuttleInterface

	const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  	if(!offlineDetName) return 0;
	return fShuttle->StoreReferenceFile(GetName(), localFile, gridFileName);
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetFile(Int_t system, const char* id, const char* source)
{
  // This function retrieves a file from the given system (kDAQ, kDCS, kHLT) with the given file id
  // and from the given source in the system.
  // The function returnes the path to the local file.
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetFile(system, GetName(), id, source);
}

//______________________________________________________________________________________________
TList* AliPreprocessor::GetFileSources(Int_t system, const char* id)
{
  // Returns a list of sources in a given system that saved a file with the given id
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetFileSources(system, GetName(), id);
}

//______________________________________________________________________________________________
void AliPreprocessor::Log(const char* message)
{
  // Adds a log message to the Shuttle log of this preprocessor
  //
  // The call is delegated to AliShuttleInterface

  fShuttle->Log(GetName(), message);
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetRunParameter(const char* param)
{
  // Return run parameter read from run logbook
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetRunParameter(param);
}

//______________________________________________________________________________________________
AliCDBEntry* AliPreprocessor::GetFromOCDB(const char* pathLevel2, const char* pathLevel3)
{
  // Return object from OCDB valid for current run
  //
  // The call is delegated to AliShuttleInterface

  const char* offlineDetName = AliShuttleInterface::GetOfflineDetName(GetName());
  if (!offlineDetName) return 0;

  return dynamic_cast<AliCDBEntry*>
  	(fShuttle->GetFromOCDB(GetName(), AliCDBPath(offlineDetName, pathLevel2, pathLevel3)));
}

//______________________________________________________________________________________________
const char* AliPreprocessor::GetRunType()
{
  // Return run type string read from "run type" logbook
  //
  // The call is delegated to AliShuttleInterface

  return fShuttle->GetRunType();
}
<|endoftext|>


<commit_before>
#include <cstdint>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>

#include "lw/pp.hpp"

namespace lw {
namespace event {

// Declares event types.
#define LW_DECLARE_EVENT(_event_name) struct LW_CONCAT(_event_name, _t) {};
#define LW_DECLARE_EVENTS(...) LW_FOR_EACH(LW_DECLARE_EVENT, __VA_ARGS__)

// Defines a single event type.
#define LW_DEFINE_EVENT(_event_name, ...) \
    typedef ::lw::event::Event<LW_CONCAT(_event_name, _t), __VA_ARGS__> LW_CONCAT(_event_name, _event_t);
#define LW_DEFINE_EVENTS(...) LW_FOR_EACH(LW_DEFINE_EVENT, __VA_ARGS__)

// Creates an event emitter class using the given events.
#define _LW_EVENT_TYPE(_event_name, ...) ::lw::event::Event<LW_CONCAT(_event_name, _t), __VA_ARGS__>,
#define _LW_IMPORT_EVENT(_event_name, ...) static constexpr LW_CONCAT(_event_name, _t) _event_name{};
#define _LW_EVENT_STRING_CALL(_event_name, ...)             \
    if (event == LW_STRINGIFY(_event_name)) {               \
        on(_event_name, std::forward<Listener>(listener));  \
        return;                                             \
    }
#define LW_DEFINE_EMITTER(_emitter_name, ...)                                           \
    class _emitter_name :                                                               \
        public ::lw::event::Emitter<LW_FOR_EACH(_LW_EVENT_TYPE, __VA_ARGS__) nullptr_t> \
    {                                                                                \
    public:                                                                             \
        struct event { LW_FOR_EACH(_LW_IMPORT_EVENT, __VA_ARGS__) };                    \
                                                                                \
        template<typename Listener>                                                     \
        void on(const std::string& event, Listener&& listener){                         \
            LW_FOR_EACH(_LW_EVENT_STRING_CALL, __VA_ARGS__)                             \
        }                                                                               \
    };

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

template<typename EventId, typename... EventArgs>
class Event {
public:
    typedef EventId event_id_type;
    typedef std::tuple<EventArgs...> event_argument_types;
    typedef std::function<void(EventArgs&&...)> listener_type;

private:
    std::list<listener_type> m_listeners;
};

template<
    std::size_t I,
    typename EventId,
    typename Event,
    typename OtherEvents...,
    typename = typename std::enable_if<
        !std::is_same<EventId, typename Event::event_id_type>::value
    >::type
>
struct EventIndexImpl : public EventIndexImpl<I + 1, EventId, OtherEvents...> {};

template<
    std::size_t I,
    typename EventId,
    typename Event,
    typename OtherEvents...,
    typename = typename std::enable_if<
        std::is_same<EventId, typename Event::event_id_type>::value
    >::type
>
struct EventIndexImpl : public std::integral_constant<std::size_t, I> {};

template<typename EventId, typename... Events>
struct EventIndex : public EventIndexImpl<0, EventId, Events...> {};

template<typename EventId, typename... Events>
struct GetEvent {
    typedef EventIndex<EventId, Events...> event_idx_type;
    typedef std::tuple<Events...> event_tuple_type;
    typedef typename std::tuple_element<event_idx_type::value, event_tuple_type>::type event_type;

    static event_type& from(event_tuple_type& events){
        return std::get<event_idx_type::value>(events);
    }

    static const event_type& from(const event_tuple_type& events){
        return std::get<event_idx_type::value>(events);
    }
};

template<typename Func, typename Args>
struct IsCallable : public std::false_type {};

template<typename Func, typename... Args, typename = typename std::result_of<Func(Args&&...)>::type>
struct IsCallback<Func, std::tuple<Args...>> : public std::true_type {};

template<typename Listener, typename Event>
struct EventListenerCallable : public IsCallable<Listener, typename Event::event_argument_types> {};

template<typename... Events>
class Emitter {
public:
    typedef std::tuple<Events...> event_types;

    template<
        typename EventId,
        typename Listener,
        typename = typename std::enable_if<
            EventListenerCallable<Listener, typename GetEvent<EventId, Events...>::type>::value
        >::type
    >
    void on(const EventId&, Listener&& listener){
        GetEvent<EventId, Events...>::from(m_events).add_listener(std::forward<Listener>(listener));
    }

private:
    event_types m_events;
};

}
}
<commit_msg>Documentation<commit_after>
#include <cstdint>
#include <functional>
#include <list>
#include <map>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>

#include "lw/pp.hpp"

namespace lw {
namespace event {

/// @brief Implementation details for event emitters.
namespace _details {
    template<
        std::size_t I,
        typename EventId,
        typename Event,
        typename OtherEvents...,
        typename = typename std::enable_if<
            !std::is_same<EventId, typename Event::event_id_type>::value
        >::type
    >
    struct EventIndexImpl : public EventIndexImpl<I + 1, EventId, OtherEvents...> {};

    template<
        std::size_t I,
        typename EventId,
        typename Event,
        typename OtherEvents...,
        typename = typename std::enable_if<
            std::is_same<EventId, typename Event::event_id_type>::value
        >::type
    >
    struct EventIndexImpl : public std::integral_constant<std::size_t, I> {};

    template<typename EventId, typename... Events>
    struct EventIndex : public EventIndexImpl<0, EventId, Events...> {};

    template<typename EventId, typename... Events>
    struct GetEvent {
        typedef EventIndex<EventId, Events...> event_idx_type;
        typedef std::tuple<Events...> event_tuple_type;
        typedef typename std::tuple_element<event_idx_type::value, event_tuple_type>::type event_type;

        static event_type& from(event_tuple_type& events){
            return std::get<event_idx_type::value>(events);
        }

        static const event_type& from(const event_tuple_type& events){
            return std::get<event_idx_type::value>(events);
        }
    };

    template<typename Func, typename Args>
    struct IsCallable : public std::false_type {};

    template<typename Func, typename... Args, typename = typename std::result_of<Func(Args&&...)>::type>
    struct IsCallback<Func, std::tuple<Args...>> : public std::true_type {};

    template<typename Listener, typename Event>
    struct EventListenerCallable : public IsCallable<Listener, typename Event::event_argument_types> {};
}

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

/// @brief Maintains all information about a single event, including bound listeners.
///
/// @tparam EventArgs The arguments listeners expected with this event.
template<typename... EventArgs>
class Event {
public:
    typedef std::tuple<EventArgs...> event_argument_types;      ///< The event arguments.
    typedef std::function<void(EventArgs&&...)> listener_type;  ///< The type for storing listeners.

    /// @brief Adds a new event listener to the back of the list.
    ///
    /// @tparam Listener The event listener type which must conform to `listener_type`.
    ///
    /// @param listener The event listener being added.
    template<typename Listener>
    void emplace_back(Listener&& listener){
        m_listeners.emplace_back(std::forward<Listener>(listener));
    }

    /// @copydoc emplace_back
    template<typename Listener>
    void push_back(Listener&& listener){
        m_listeners.push_back(std::forward<Listener>(listener));
    }

    /// @brief Calls all the listeners with the provided arguments.
    ///
    /// @tparam CalledArgs
    ///     The types of the provided arguements. Must be compatible with `event_argument_types`.
    ///
    /// @param args The argument values being passed to each listener.
    template<typename... CalledArgs>
    void operator()(CalledArgs&&... args){
        for (auto&& listener : m_listeners) {
            listener(args...);
        }
    }

    /// @brief Removes any listeners for which the predicate returns true.
    ///
    /// @tparam Pred A unary predicate type which takes a `listener_type` instance.
    ///
    /// @param pred
    ///     The predicate receiving each listener in turn. If it returns `true` the listener will be
    ///     removed from the event.
    template<typename Pred>
    void remove_if(Pred&& pred){
        m_listeners.remove_if(std::forward<Pred>(pred));
    }

    /// @brief Removes any listeners equal to the one provided.
    ///
    /// @tparam Listener The listener type to remove.
    ///
    /// @param listener The value to check for.
    template<typename Listener>
    void remove(Listener&& listener){
        m_listeners.remove(std::forward<Listener>(listener));
    }

    /// @brief Removes all listeners from the event.
    void clear(void){
        m_listeners.clear();
    }

    /// @brief Returns the number of listeners bound to this event.
    std::size_t count(void) const {
        return m_listeners.count();
    }

    /// @brief Returns true if no listeners are bound to this event.
    bool empty(void) const {
        return m_listeners.empty();
    }

private:
    std::list<listener_type> m_listeners; ///< The list of event listeners.
};

/// @brief Adds a type-safe method for identifying events.
///
/// These are the event types used by the `Emitter` class.
///
/// @tparam EventId The type used to identify this event.
template<typename EventId, typename... EventArgs>
class IdEvent : public Event<EventArgs...> {
public:
    typedef EventId event_id_type; ///< The event Id type.
};

/// @brief A class which can emit several different event types.
///
/// @tparam Events All the events this emitter will support. Must be derived from `IdEvent`.
template<typename... Events>
class Emitter {
public:
    typedef std::tuple<Events...> event_types; ///< The events supported by the emitter.

    /// @brief
    template<
        typename EventId,
        typename Listener,
        typename = typename std::enable_if<
            _details::EventListenerCallable<
                Listener, typename _details::GetEvent<EventId, Events...>::type
            >::value
        >::type
    >
    void on(const EventId&, Listener&& listener){
        _details::GetEvent<EventId, Events...>::from(m_events)
            .emplace_back(std::forward<Listener>(listener));
    }

    template<typename EventId, typename Listener>
    void emplace(const EventId& e, Listener&& listener){
        on(e, std::forward<Listener>(listener));
    }

    template<
        typename EventId,
        typename Listener,
        typename = typename std::enable_if<
            _details::EventListenerCallable<
                Listener, typename _details::GetEvent<EventId, Events...>::type
            >::value
        >::type
    >
    void insert(const EventId&, Listener&& listener){
        _details::GetEvent<EventId, Events...>::from(m_events)
            .push_back(std::forward<Listener>(listener));
    }

    template<typename EventId, typename Pred>
    void remove_if(const EventId&, Pred&& pred){
        _details::GetEvent<EventId, Events...>::from(m_events).remove_if(std::forward<Pred>(pred));
    }

    template<typename EventId, typename Listener>
    void remove(const EventId&, Listener&& listener){
        _details::GetEvent<EventId, Events...>::from(m_events)
            .remove(std::forward<Listener>(listener));
    }

    template<typename EventId>
    void remove_all(const EventId&){
        _details::GetEvent<EventId, Events...>::from(m_events).remove_all();
    }

    void remove_all(const EventId&){
        ....???
    }

    template<typename EventId>
    void clear(const EventId&){
        _details::GetEvent<EventId, Events...>::from(m_events).clear();
    }

    void clear(void){
        ....???
    }

    bool empty(void) const {
        ....???
    }

    template<typename EventId>
    std::size_t count(const EventId&) const {
        return _details::GetEvent<EventId, Events...>::from(m_events).count();
    }

protected:
    template<typename EventId, typename... Args>
    void emit(const EventId&, Args&&...){
        _details::GetEvent<EventId, Events...>::from(m_events)(std::forward<Args>(args)...);
    }

private:
    event_types m_events;
};

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

// Declares event types.
#define LW_DECLARE_EVENT(_event_name) struct LW_CONCAT(_event_name, _t) {};
#define LW_DECLARE_EVENTS(...) LW_FOR_EACH(LW_DECLARE_EVENT, __VA_ARGS__)

// Defines a single event type.
#define LW_DEFINE_EVENT(_event_name, ...) \
    typedef ::lw::event::Event<LW_CONCAT(_event_name, _t), __VA_ARGS__> LW_CONCAT(_event_name, _event_t);
#define LW_DEFINE_EVENTS(...) LW_FOR_EACH(LW_DEFINE_EVENT, __VA_ARGS__)

// Creates an event emitter class using the given events.
#define _LW_EVENT_TYPE(_event_name, ...) ::lw::event::IdEvent<LW_CONCAT(_event_name, _t), __VA_ARGS__>,
#define _LW_IMPORT_EVENT(_event_name, ...) static constexpr LW_CONCAT(_event_name, _t) _event_name{};
#define LW_DEFINE_EMITTER(_emitter_name, ...)                                           \
    class _emitter_name :                                                               \
        public ::lw::event::Emitter<LW_FOR_EACH(_LW_EVENT_TYPE, __VA_ARGS__) nullptr_t> \
    {                                                                                \
    public:                                                                             \
        struct event { LW_FOR_EACH(_LW_IMPORT_EVENT, __VA_ARGS__) };                    \
    };

}
}
<|endoftext|>


<commit_before>#include "facepreprocessor.h"

#include <vector>
#include <algorithm>
#include <limits>
#include <cstdint>

#include <opencv2/imgproc/imgproc.hpp>

#include <QDebug>

static const double PI = std::atan(1.0) * 4;

using namespace cv;

FacePreprocessor::FacePreprocessor(FaceClassifiers classifiers, const Mat& input)  throw(std::invalid_argument)
    : input(input),
      result(Mat(input.rows, input.cols, CV_8UC1)),
      classifiers(classifiers)
{
    if (classifiers.face.get() == nullptr)
        throw std::invalid_argument("face classifier");
    else if (classifiers.face->empty())
        throw std::invalid_argument("face classifier");
    else if (classifiers.eye.get() == nullptr)
        throw std::invalid_argument("eye classifier");
    else if (classifiers.eye->empty())
        throw std::invalid_argument("eye classifier");
}

unsigned int FacePreprocessor::GetMinSize() const
{
    int minDim = std::min(input.rows, input.cols);
    return static_cast<unsigned int>(minDim / 5.0);
}

Rect FacePreprocessor::LargestRect(const std::vector<Rect>& rects)
{
    if(rects.empty())
        return Rect();
    Rect largest = *std::max_element(rects.begin(), rects.end(), [](const Rect& a, const Rect& b)
    {
        return a.area() < b.area();
    }
    );
    return largest;
}

const double FacePreprocessor::MAX_ROTATE_ANGLE = 20.0;

double FacePreprocessor::GetRotation(cv::Rect left, cv::Rect right)
{
    Point direction;
    direction.x = right.x - left.x;
    direction.y = right.y - left.y;
    double angle = std::atan2(direction.y, direction.x) * 180.0 / PI;
    return angle;
}

std::vector<Rect> FacePreprocessor::GetEyesAlternateMethod()
{
    static std::vector<Rect> empty;
    std::vector<Rect> eyes;
    eyes.reserve(2);
    classifiers.eyePair->detectMultiScale(result, eyes, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(eyes.empty())
        return empty;
    qDebug() << "eye pair was found";
    rectangle(result, eyes.front(), 1);

    std::vector<Rect> lefts;
    std::vector<Rect> rights;
    Rect cRect = eyes.front();
    cRect.width /= 2;
    classifiers.eyeLeft->detectMultiScale(result(cRect), lefts, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(lefts.empty())
    {
        qDebug () << "left wasnt found";
        return empty;
    }
    cRect.x += cRect.width;
    classifiers.eyeLeft->detectMultiScale(result(cRect), rights, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(rights.empty())
    {
        qDebug () << "right wasnt found";
        return empty;
    }
    rights.front().x += cRect.width;

    gotEyes = true;

    lefts.front().x += eyes.front().x;
    lefts.front().y += eyes.front().y;
    rights.front().x += eyes.front().x;
    rights.front().y += eyes.front().y;
    rectangle(result, lefts.front(), 1);
    rectangle(result, rights.front(), 1);

    eyes.clear();
    eyes.push_back(lefts.front());
    eyes.push_back(rights.front());
    return eyes;
}

std::vector<Rect> FacePreprocessor::GetEyes()
{
    int maxSize = static_cast<int>(std::ceil(std::max(result.rows, result.cols) / 6.0));
    int minSize = std::max(static_cast<int>(std::floor(std::min(result.rows, result.cols) / 20.0)), 5);
    Rect upperHalfOfFace(0, 0, face.width, static_cast<int>(face.height / 1.8));
    std::vector<Rect> eyes;
    std::vector<Rect> eyePairR;
    //classifiers.eyePair->detectMultiScale(result(upperHalfOfFace), eyePairR, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(eyePairR.empty())
    {
        classifiers.eye->detectMultiScale(result(upperHalfOfFace), eyes, 1.1, 6, 0, Size(minSize, minSize), Size(maxSize, maxSize));
    }
    else
    {
        classifiers.eye->detectMultiScale(result(eyePairR.front()), eyes, 1.1, 6, 0, Size(minSize, minSize), Size(maxSize, maxSize));
        rectangle(result, eyePairR.front(), 255);
    }
    for (auto eye : eyes)
    {
        if(!eyePairR.empty())
        {
            eye.x += eyePairR.front().x;
            eye.y += eyePairR.front().y;
        }
        rectangle(result, eye, 1);
    }
    if(eyes.size() < 2)
    {
        qDebug() << "only" << eyes.size() << "eyes were found";
        eyes.clear();
        return eyes;
    }
    gotEyes = true;

    if(eyes.size() > 2)
    {
        // finding the pair with lowest angle
        std::vector<std::pair<uint16_t, uint16_t>> helper;
        helper.reserve(eyes.size() * eyes.size() - eyes.size());
        for(auto i = eyes.begin(); i != eyes.end(); i++)
        {
            for(auto j = eyes.begin(); j != eyes.end(); j++)
            {
                if (i != j)
                    helper.push_back(std::make_pair(std::distance(eyes.begin(), i), std::distance(eyes.begin(), j)));
            }
        }

        std::sort(helper.begin(), helper.end(), [&eyes](const std::pair<uint16_t, uint16_t>& a, const std::pair<uint16_t, uint16_t>& b)
        {
            double angleA = std::abs(GetRotation(eyes[a.first], eyes[a.second]));
            double angleB = std::abs(GetRotation(eyes[b.first], eyes[b.second]));
            return angleA < angleB;
        });

        assert(helper.front().first != helper.front().second);

        std::swap(eyes[0], eyes[helper.front().first]);
        std::swap(eyes[1], eyes[helper.front().second]);
    }

    std::sort(eyes.begin(), eyes.begin() + 2, [](const Rect& a, const Rect& b) { return a.x < b.x; });
    eyes.resize(2);
    return eyes;
}

void FacePreprocessor::RotateFace()
{
    std::vector<Rect> eyes = GetEyes();
    if(eyes.size() < 2)
    {
        return;
    }

    double angle = GetRotation(eyes[0], eyes[1]);
    qDebug() << "rotation angle: " << angle;
    if (std::abs(angle) < std::numeric_limits<double>::epsilon() * 3 || std::abs(angle) > MAX_ROTATE_ANGLE)
        return;

    int size = std::max(result.cols, result.rows);
    int fullSize = std::max(normalized.cols, normalized.rows);
    Point2f pt(size/2.0f + face.x, size/2.0f + face.y);
    Mat r = getRotationMatrix2D(pt, angle, 1.0);

    warpAffine(normalized, rotated, r, Size(fullSize, fullSize), CV_INTER_LANCZOS4);

    result = rotated(face);
}

void FacePreprocessor::ScaleFace()
{
    Rect aspected = face;
    if(face.width < face.height)
    {
        aspected.width = face.height;
    }
    else
    {
        aspected.height = face.width;
    }

    Mat scaled = result.clone();

    copyMakeBorder(scaled, scaled, 0, aspected.height, 0, aspected.width, BORDER_REPLICATE);

    aspected.x = 0;
    aspected.y = 0;

    result = scaled(aspected);
    resize(result, result, Size(512, 512), 0.0, 0.0, CV_INTER_LANCZOS4);
}

double FacePreprocessor::GetAccuracy() const
{
    double accuracy = 0.0;
    if(face.width > 0 && face.height > 0)
        accuracy += 0.5;
    if(gotEyes)
        accuracy += 0.5;
    return accuracy;
}

Mat FacePreprocessor::Preprocess() throw (NoFaceFoundException)
{
    if(input.type() == CV_8UC3)
        cvtColor(input, result, CV_BGR2GRAY);
    else
        result = input;
    equalizeHist(result, normalized);

    result = normalized;

    std::vector<Rect> faces;
    Size minSize(GetMinSize(), GetMinSize());
    classifiers.face->detectMultiScale(result, faces, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT, minSize);

    if (!faces.empty())
    {
        face = LargestRect(faces);

        result = result(face);
    }
    else
    {
        throw NoFaceFoundException();
    }

    RotateFace();

    static uint64_t cntr = 0;
    static uint64_t cntr2 = 0;

    cntr2++;

    if(!gotEyes)
        qDebug() << "no eyes were found on the face -- this is odd :(" << ++cntr << "/" << cntr2;
    else
        qDebug() << "is rotated? " << !rotated.empty() << (cntr2 - cntr) << "/" << cntr2;

    ScaleFace();

    return result;
}
<commit_msg>constructor checks the additional classifiers<commit_after>#include "facepreprocessor.h"

#include <vector>
#include <algorithm>
#include <limits>
#include <cstdint>

#include <opencv2/imgproc/imgproc.hpp>

#include <QDebug>

static const double PI = std::atan(1.0) * 4;

using namespace cv;

FacePreprocessor::FacePreprocessor(FaceClassifiers classifiers, const Mat& input)  throw(std::invalid_argument)
    : input(input),
      result(Mat(input.rows, input.cols, CV_8UC1)),
      classifiers(classifiers)
{
    if (classifiers.face.get() == nullptr)
        throw std::invalid_argument("face classifier");
    else if (classifiers.face->empty())
        throw std::invalid_argument("face classifier");
    else if (classifiers.eye.get() == nullptr)
        throw std::invalid_argument("eye classifier");
    else if (classifiers.eye->empty())
        throw std::invalid_argument("eye classifier");
    else if (classifiers.eyePair.get() == nullptr)
        throw std::invalid_argument("eyepair classifier");
    else if (classifiers.eyePair->empty())
        throw std::invalid_argument("eyepair classifier");
    else if (classifiers.eyeLeft.get() == nullptr)
        throw std::invalid_argument("left eye classifier");
    else if (classifiers.eyeLeft->empty())
        throw std::invalid_argument("left eye classifier");
    else if (classifiers.eyeRight.get() == nullptr)
        throw std::invalid_argument("right eye classifier");
    else if (classifiers.eyeRight->empty())
        throw std::invalid_argument("right eye classifier");
}

unsigned int FacePreprocessor::GetMinSize() const
{
    int minDim = std::min(input.rows, input.cols);
    return static_cast<unsigned int>(minDim / 5.0);
}

Rect FacePreprocessor::LargestRect(const std::vector<Rect>& rects)
{
    if(rects.empty())
        return Rect();
    Rect largest = *std::max_element(rects.begin(), rects.end(), [](const Rect& a, const Rect& b)
    {
        return a.area() < b.area();
    }
    );
    return largest;
}

const double FacePreprocessor::MAX_ROTATE_ANGLE = 20.0;

double FacePreprocessor::GetRotation(cv::Rect left, cv::Rect right)
{
    Point direction;
    direction.x = right.x - left.x;
    direction.y = right.y - left.y;
    double angle = std::atan2(direction.y, direction.x) * 180.0 / PI;
    return angle;
}

std::vector<Rect> FacePreprocessor::GetEyesAlternateMethod()
{
    static std::vector<Rect> empty;
    std::vector<Rect> eyes;
    eyes.reserve(2);
    classifiers.eyePair->detectMultiScale(result, eyes, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(eyes.empty())
        return empty;
    qDebug() << "eye pair was found";
    rectangle(result, eyes.front(), 1);

    std::vector<Rect> lefts;
    std::vector<Rect> rights;
    Rect cRect = eyes.front();
    cRect.width /= 2;
    classifiers.eyeLeft->detectMultiScale(result(cRect), lefts, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(lefts.empty())
    {
        qDebug () << "left wasnt found";
        return empty;
    }
    cRect.x += cRect.width;
    classifiers.eyeLeft->detectMultiScale(result(cRect), rights, 1.1, 4, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(rights.empty())
    {
        qDebug () << "right wasnt found";
        return empty;
    }
    rights.front().x += cRect.width;

    gotEyes = true;

    lefts.front().x += eyes.front().x;
    lefts.front().y += eyes.front().y;
    rights.front().x += eyes.front().x;
    rights.front().y += eyes.front().y;
    rectangle(result, lefts.front(), 1);
    rectangle(result, rights.front(), 1);

    eyes.clear();
    eyes.push_back(lefts.front());
    eyes.push_back(rights.front());
    return eyes;
}

std::vector<Rect> FacePreprocessor::GetEyes()
{
    int maxSize = static_cast<int>(std::ceil(std::max(result.rows, result.cols) / 6.0));
    int minSize = std::max(static_cast<int>(std::floor(std::min(result.rows, result.cols) / 20.0)), 5);
    Rect upperHalfOfFace(0, 0, face.width, static_cast<int>(face.height / 1.8));
    std::vector<Rect> eyes;
    std::vector<Rect> eyePairR;
    //classifiers.eyePair->detectMultiScale(result(upperHalfOfFace), eyePairR, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT);
    if(eyePairR.empty())
    {
        classifiers.eye->detectMultiScale(result(upperHalfOfFace), eyes, 1.1, 6, 0, Size(minSize, minSize), Size(maxSize, maxSize));
    }
    else
    {
        classifiers.eye->detectMultiScale(result(eyePairR.front()), eyes, 1.1, 6, 0, Size(minSize, minSize), Size(maxSize, maxSize));
        rectangle(result, eyePairR.front(), 255);
    }
    for (auto eye : eyes)
    {
        if(!eyePairR.empty())
        {
            eye.x += eyePairR.front().x;
            eye.y += eyePairR.front().y;
        }
        rectangle(result, eye, 1);
    }
    if(eyes.size() < 2)
    {
        qDebug() << "only" << eyes.size() << "eyes were found";
        eyes.clear();
        return eyes;
    }
    gotEyes = true;

    if(eyes.size() > 2)
    {
        // finding the pair with lowest angle
        std::vector<std::pair<uint16_t, uint16_t>> helper;
        helper.reserve(eyes.size() * eyes.size() - eyes.size());
        for(auto i = eyes.begin(); i != eyes.end(); i++)
        {
            for(auto j = eyes.begin(); j != eyes.end(); j++)
            {
                if (i != j)
                    helper.push_back(std::make_pair(std::distance(eyes.begin(), i), std::distance(eyes.begin(), j)));
            }
        }

        std::sort(helper.begin(), helper.end(), [&eyes](const std::pair<uint16_t, uint16_t>& a, const std::pair<uint16_t, uint16_t>& b)
        {
            double angleA = std::abs(GetRotation(eyes[a.first], eyes[a.second]));
            double angleB = std::abs(GetRotation(eyes[b.first], eyes[b.second]));
            return angleA < angleB;
        });

        assert(helper.front().first != helper.front().second);

        std::swap(eyes[0], eyes[helper.front().first]);
        std::swap(eyes[1], eyes[helper.front().second]);
    }

    std::sort(eyes.begin(), eyes.begin() + 2, [](const Rect& a, const Rect& b) { return a.x < b.x; });
    eyes.resize(2);
    return eyes;
}

void FacePreprocessor::RotateFace()
{
    std::vector<Rect> eyes = GetEyes();
    if(eyes.size() < 2)
    {
        return;
    }

    double angle = GetRotation(eyes[0], eyes[1]);
    qDebug() << "rotation angle: " << angle;
    if (std::abs(angle) < std::numeric_limits<double>::epsilon() * 3 || std::abs(angle) > MAX_ROTATE_ANGLE)
        return;

    int size = std::max(result.cols, result.rows);
    int fullSize = std::max(normalized.cols, normalized.rows);
    Point2f pt(size/2.0f + face.x, size/2.0f + face.y);
    Mat r = getRotationMatrix2D(pt, angle, 1.0);

    warpAffine(normalized, rotated, r, Size(fullSize, fullSize), CV_INTER_LANCZOS4);

    result = rotated(face);
}

void FacePreprocessor::ScaleFace()
{
    Rect aspected = face;
    if(face.width < face.height)
    {
        aspected.width = face.height;
    }
    else
    {
        aspected.height = face.width;
    }

    Mat scaled = result.clone();

    copyMakeBorder(scaled, scaled, 0, aspected.height, 0, aspected.width, BORDER_REPLICATE);

    aspected.x = 0;
    aspected.y = 0;

    result = scaled(aspected);
    resize(result, result, Size(512, 512), 0.0, 0.0, CV_INTER_LANCZOS4);
}

double FacePreprocessor::GetAccuracy() const
{
    double accuracy = 0.0;
    if(face.width > 0 && face.height > 0)
        accuracy += 0.5;
    if(gotEyes)
        accuracy += 0.5;
    return accuracy;
}

Mat FacePreprocessor::Preprocess() throw (NoFaceFoundException)
{
    if(input.type() == CV_8UC3)
        cvtColor(input, result, CV_BGR2GRAY);
    else
        result = input;
    equalizeHist(result, normalized);

    result = normalized;

    std::vector<Rect> faces;
    Size minSize(GetMinSize(), GetMinSize());
    classifiers.face->detectMultiScale(result, faces, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT, minSize);

    if (!faces.empty())
    {
        face = LargestRect(faces);

        result = result(face);
    }
    else
    {
        throw NoFaceFoundException();
    }

    RotateFace();

    static uint64_t cntr = 0;
    static uint64_t cntr2 = 0;

    cntr2++;

    if(!gotEyes)
        qDebug() << "no eyes were found on the face -- this is odd :(" << ++cntr << "/" << cntr2;
    else
        qDebug() << "is rotated? " << !rotated.empty() << (cntr2 - cntr) << "/" << cntr2;

    ScaleFace();

    return result;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "csvmodelwriter.h"

#include <QAbstractItemModel>
#include <QFile>
#include <QTextStream>

CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
    QObject(parent),
    filename(filename), model(0)
{
}

void CSVModelWriter::setModel(const QAbstractItemModel *model)
{
    this->model = model;
}

void CSVModelWriter::addColumn(const QString &title, int column, int role)
{
    Column col;
    col.title = title;
    col.column = column;
    col.role = role;

    columns.append(col);
}

static void writeValue(QTextStream &f, const QString &value)
{
    QString escaped = value;
    escaped.replace('"', "\"\"");
    f << "\"" << escaped << "\"";
}

static void writeSep(QTextStream &f)
{
    f << ",";
}

static void writeNewline(QTextStream &f)
{
    f << "\n";
}

bool CSVModelWriter::write()
{
    QFile file(filename);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;
    QTextStream out(&file);

    int numRows = 0;
    if(model)
    {
        numRows = model->rowCount();
    }

    // Header row
    for(int i=0; i<columns.size(); ++i)
    {
        if(i!=0)
        {
            writeSep(out);
        }
        writeValue(out, columns[i].title);
    }
    writeNewline(out);

    // Data rows
    for(int j=0; j<numRows; ++j)
    {
        for(int i=0; i<columns.size(); ++i)
        {
            if(i!=0)
            {
                writeSep(out);
            }
            QVariant data = model->index(j, columns[i].column).data(columns[i].role);
            writeValue(out, data.toString());
        }
        writeNewline(out);
    }

    file.close();

    return file.error() == QFile::NoError;
}

<commit_msg>Update csvmodelwriter.cpp<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "csvmodelwriter.h"

#include <QAbstractItemModel>
#include <QFile>
#include <QTextStream>

CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
    QObject(parent),
    filename(filename), model(0)
{
}

void CSVModelWriter::setModel(const QAbstractItemModel *model)
{
    this->model = model;
}

void CSVModelWriter::addColumn(const QString &title, int column, int role)
{
    Column col;
    col.title = title;
    col.column = column;
    col.role = role;

    columns.append(col);
}

static void writeValue(QTextStream &f, const QString &value)
{
    QString escaped = value;
    escaped.replace('"', "\"\"");
    f << "\"" << escaped << "\"";
}

static void writeSep(QTextStream &f)
{
    f << ",";
}

static void writeNewline(QTextStream &f)
{
    f << "\n";
}

bool CSVModelWriter::write()
{
    QFile file(filename);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;
    QTextStream out(&file);

    int numRows = 0;
    if(model)
    {
        numRows = model->rowCount();
    }

    // Header row
    for(int i=0; i<columns.size(); ++i)
    {
        if(i!=0)
        {
            writeSep(out);
        }
        writeValue(out, columns[i].title);
    }
    writeNewline(out);

    // Data rows
    for(int j=0; j<numRows; ++j)
    {
        for(int i=0; i<columns.size(); ++i)
        {
            if(i!=0)
            {
                writeSep(out);
            }
            QVariant data = model->index(j, columns[i].column).data(columns[i].role);
            writeValue(out, data.toString());
        }
        writeNewline(out);
    }

    file.close();

    return file.error() == QFile::NoError;
}

<|endoftext|>


<commit_before>#include "ObjectCodeGenerator.h"
#include "TableManager.h"

ObjectCodeGenerator::ObjectCodeGenerator(string objectFileName) {
	outputFileName = objectFileName.append(".o");
}

ObjectCodeGenerator::~ObjectCodeGenerator() {
}

void ObjectCodeGenerator::WriteInstruction(int opCode, const vector<ArgumentInfo>& arguments) {
	string line = "";
	tableRealocation << "0"; //do opcode

	for (auto arg : arguments) {
		line += line.empty() ? std::to_string(arg.RealValue) : " " + std::to_string(arg.RealValue);
		tableRealocation << arg.Extern ? "0" : "1";
	}

	if(code.rdbuf() -> in_avail() == 0) {
		code << line;
	} else {
		code << " " + line;
	}
}

void ObjectCodeGenerator::WriteDirective(WrittenDirectivesType directive, int vlr) {
	switch (directive) {
		case ObjectCodeGenerator::SPACE:
			for (size_t i = 0; i < vlr; i++) {
				code << " 00";
			}
			break;
		case ObjectCodeGenerator::CONST:
			code << " "+std::to_string(vlr);
			break;
		default:
			break;
	}
}

void ObjectCodeGenerator::GenerateFile(GenerationType type) {
	fstream file;
	file.open(outputFileName, std::fstream::out);

	switch (type) {
		case ObjectCodeGenerator::Direct:
			file << code.rdbuf();
			break;
		case ObjectCodeGenerator::Modular:
			GenerateModularFile(file);
			break;
		default:
			break;
	}
}

void ObjectCodeGenerator::WriteTableDefinition() {
	const auto& defTable = TableManager::GetDefinitionTable();
	for (auto definition : defTable) {
		tableUse << definition.first + " " + std::to_string(definition.second) + "\n";
	}
}

void ObjectCodeGenerator::WriteTableUse() {
	const auto& useTable = TableManager::GetUseTable();
	for (auto use : useTable) {
		tableDefinition << use.first + " " + std::to_string(use.second) + "\n";
	}
}

void ObjectCodeGenerator::GenerateModularFile(fstream & file) {
}
<commit_msg>Concluida implementação do objectCodeGenerator<commit_after>#include "ObjectCodeGenerator.h"
#include "TableManager.h"

ObjectCodeGenerator::ObjectCodeGenerator(string objectFileName) {
	outputFileName = objectFileName.append(".o");
}

ObjectCodeGenerator::~ObjectCodeGenerator() {
}

void ObjectCodeGenerator::WriteInstruction(int opCode, const vector<ArgumentInfo>& arguments) {
	string line = "";
	tableRealocation << "0"; //do opcode

	for (auto arg : arguments) {
		line += line.empty() ? std::to_string(arg.RealValue) : " " + std::to_string(arg.RealValue);
		tableRealocation << arg.Extern ? "0" : "1";
	}

	if(code.rdbuf() -> in_avail() == 0) {
		code << line;
	} else {
		code << " " + line;
	}
}

void ObjectCodeGenerator::WriteDirective(WrittenDirectivesType directive, int vlr) {
	switch (directive) {
		case ObjectCodeGenerator::SPACE:
			for (size_t i = 0; i < vlr; i++) {
				code << " 00";
				tableRealocation << "0";
			}
			break;
		case ObjectCodeGenerator::CONST:
			code << " "+std::to_string(vlr);
			tableRealocation << "0";
			break;
		default:
			break;
	}
}

void ObjectCodeGenerator::GenerateFile(GenerationType type) {
	fstream file;
	file.open(outputFileName, std::fstream::out);

	switch (type) {
		case ObjectCodeGenerator::Direct:
			file << code.rdbuf();
			break;
		case ObjectCodeGenerator::Modular:
			GenerateModularFile(file);
			break;
		default:
			break;
	}
	file.close();
}

void ObjectCodeGenerator::WriteTableDefinition() {
	const auto& defTable = TableManager::GetDefinitionTable();
	for (auto definition : defTable) {
		tableUse << definition.first + " " + std::to_string(definition.second) + "\n";
	}
}

void ObjectCodeGenerator::WriteTableUse() {
	const auto& useTable = TableManager::GetUseTable();
	for (auto use : useTable) {
		tableDefinition << use.first + " " + std::to_string(use.second) + "\n";
	}
}

void ObjectCodeGenerator::GenerateModularFile(fstream & file) {
	WriteTableDefinition();
	WriteTableUse();

	file << "TABLE USE\n";
	file << tableUse.rdbuf();
	file << "\nTABLE DEFINITION\n";
	file << tableDefinition.rdbuf();
	file << "\nTABLE REALOCATION\n";
	file << tableRealocation.rdbuf();
	file << "\nCODE\n";
	file << code.rdbuf();

}
<|endoftext|>


<commit_before>#include "xchainer/cuda/cuda_backend.h"

#include <stdlib.h>  // NOLINT

#include <tuple>

#include <cuda_runtime.h>
#include <gtest/gtest.h>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/cuda/cuda_runtime.h"
#include "xchainer/device.h"
#include "xchainer/indexable_array.h"
#include "xchainer/indexer.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/routines/creation.h"
#include "xchainer/testing/util.h"

namespace xchainer {
namespace cuda {
namespace {

template <typename T>
void ExpectDataEqual(const std::shared_ptr<void>& expected, const std::shared_ptr<void>& actual, size_t size) {
    auto expected_raw_ptr = static_cast<const T*>(expected.get());
    auto actual_raw_ptr = static_cast<const T*>(actual.get());
    for (size_t i = 0; i < size; ++i) {
        EXPECT_EQ(expected_raw_ptr[i], actual_raw_ptr[i]);
    }
}

void ExpectArraysEqual(const Array& expected, const Array& actual) {
    EXPECT_EQ(expected.dtype(), actual.dtype());
    EXPECT_EQ(expected.shape(), actual.shape());

    VisitDtype(expected.dtype(), [&expected, &actual](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> expected_iarray{expected};
        IndexableArray<const T> actual_iarray{actual};
        Indexer<> indexer{expected.shape()};

        actual.device().Synchronize();
        expected.device().Synchronize();

        for (auto it = indexer.It(0); it; ++it) {
            EXPECT_EQ(expected_iarray[it], actual_iarray[it]);
        }
    });
}

TEST(CudaBackendTest, GetDeviceCount) {
    Context ctx;
    int count = 0;
    CheckCudaError(cudaGetDeviceCount(&count));
    EXPECT_EQ(count, CudaBackend(ctx).GetDeviceCount());
}

TEST(CudaBackendTest, GetDevice) {
    Context ctx;
    CudaBackend backend{ctx};

    Device& device = backend.GetDevice(0);
    EXPECT_EQ(&backend, &device.backend());
    EXPECT_EQ(0, device.index());
}

TEST(CudaBackendTest, GetDeviceSecondDevice) {
    Context ctx;
    CudaBackend backend{ctx};
    XCHAINER_REQUIRE_DEVICE(backend, 2);

    Device& device1 = backend.GetDevice(1);
    EXPECT_EQ(&backend, &device1.backend());
    EXPECT_EQ(1, device1.index());
}

TEST(CudaBackendTest, GetDeviceOutOfRange) {
    Context ctx;
    CudaBackend backend{ctx};

    EXPECT_THROW(backend.GetDevice(-1), std::out_of_range);
    EXPECT_THROW(backend.GetDevice(backend.GetDeviceCount() + 1), std::out_of_range);
}

TEST(CudaBackendTest, GetName) {
    Context ctx;
    EXPECT_EQ("cuda", CudaBackend(ctx).GetName());
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentContexts) {
    Context ctx0;
    Context ctx1;
    CudaBackend backend0{ctx0};
    CudaBackend backend1{ctx1};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferNativeBackends) {
    Context ctx;
    CudaBackend cuda_backend{ctx};
    native::NativeBackend native_backend0{ctx};
    native::NativeBackend native_backend1{ctx};
    Device& device0 = native_backend0.GetDevice(0);
    Device& device1 = native_backend1.GetDevice(0);
    EXPECT_FALSE(cuda_backend.SupportsTransfer(device0, device1));
}

template <int N>
class DerivedCudaBackend : public CudaBackend {
public:
    using CudaBackend::CudaBackend;
    std::string GetName() const override { return "derived" + std::to_string(N); }
};

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentCudaBackends) {
    Context ctx;
    DerivedCudaBackend<0> backend0{ctx};
    DerivedCudaBackend<1> backend1{ctx};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

// Data transfer test
class CudaBackendTransferTest : public ::testing::TestWithParam<::testing::tuple<std::string, std::string, int>> {};

INSTANTIATE_TEST_CASE_P(
        Devices,
        CudaBackendTransferTest,
        ::testing::Values(
                // 3rd parameter is the number of required CUDA devices to run the test.
                std::make_tuple("cuda:0", "cuda:0", 1),  // cuda:0 <-> cuda:0
                std::make_tuple("cuda:0", "cuda:1", 2),  // cuda:0 <-> cuda:1
                std::make_tuple("cuda:0", "native:0", 1)));  // cuda:0 <-> native:0

TEST_P(CudaBackendTransferTest, SupportsTransfer) {
    Context ctx;
    Backend& backend = ctx.GetBackend("cuda");
    XCHAINER_REQUIRE_DEVICE(backend, ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));
    EXPECT_TRUE(backend.SupportsTransfer(device0, device1));
}

TEST_P(CudaBackendTransferTest, MemoryCopyFrom) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyFromZeroByte) {
    size_t size = 0;
    size_t bytesize = 0;
    std::shared_ptr<void> src_orig(nullptr, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyTo) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyToZeroByte) {
    size_t size = 0;
    size_t bytesize = 0;
    std::shared_ptr<void> src_orig(nullptr, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, TransferDataFrom) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device1.Allocate(bytesize);

    // Transfer
    std::shared_ptr<void> trans_data = device0.TransferDataFrom(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), trans_data.get(), bytesize));

    // Destination is ALWAYS CUDA device
    cudaPointerAttributes attr = {};
    CheckCudaError(cudaPointerGetAttributes(&attr, trans_data.get()));
    EXPECT_TRUE(attr.isManaged);
    EXPECT_EQ(device0.index(), attr.device);
}

TEST_P(CudaBackendTransferTest, TransferDataTo) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device0.Allocate(bytesize);

    // Transfer
    std::shared_ptr<void> trans_data = device0.TransferDataTo(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), trans_data.get(), bytesize));

    if (nullptr != dynamic_cast<CudaBackend*>(&device1.backend())) {
        // Destination is CUDA device
        cudaPointerAttributes attr = {};
        CheckCudaError(cudaPointerGetAttributes(&attr, trans_data.get()));
        EXPECT_TRUE(attr.isManaged);
        EXPECT_EQ(device1.index(), attr.device);
    } else {
        // Destination is native device
        EXPECT_FALSE(IsPointerCudaMemory(trans_data.get()));
    }
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceFrom) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = xchainer::internal::FromContiguousHostData({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device1);

    // Transfer
    Array b = a.ToDevice(device0);

    EXPECT_EQ(&b.device(), &device0);
    EXPECT_EQ(&a.device(), &device1);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same native device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get())
                << "Array::ToDevice() must not return alias when transferring to different native device.";
    }
    ExpectArraysEqual(a, b);
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceTo) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = xchainer::internal::FromContiguousHostData({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device0);

    // Transfer
    Array b = a.ToDevice(device1);

    EXPECT_EQ(&b.device(), &device1);
    EXPECT_EQ(&a.device(), &device0);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same CUDA device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get()) << "Array::ToDevice() must not return alias when transferring to a different device.";
    }
    ExpectArraysEqual(a, b);
}

class EnvVarScope {
public:
    EnvVarScope(const std::string& name, const std::string& value) : name_(name) {
        const char* old_value = getenv(name_.c_str());
        if (old_value) {
            old_value_ = std::string(old_value);
        }
        setenv(name_.c_str(), value.c_str(), 1);
    }

    ~EnvVarScope() {
        if (old_value_) {
            setenv(name_.c_str(), old_value_->c_str(), 1);
        } else {
            unsetenv(name_.c_str());
        }
    }

private:
    const std::string name_{};
    nonstd::optional<std::string> old_value_{};
};

TEST(CudaBackendTest, GetCudnnMaxWorkspaceSize) {
    Context ctx;
    {
        CudaBackend backend{ctx};
        EXPECT_EQ(CudaBackend::kCudnnDefaultMaxWorkspaceSize, backend.GetCudnnMaxWorkspaceSize());
    }
    {
        CudaBackend backend{ctx};
        backend.SetCudnnMaxWorkspaceSize(10);
        EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        backend.SetCudnnMaxWorkspaceSize(0);
        EXPECT_EQ(size_t{0}, backend.GetCudnnMaxWorkspaceSize());
    }
    {
        CudaBackend backend{ctx};
        {
            EnvVarScope scope{CudaBackend::kCudnnMaxWorkspaceSizeEnvVarName, "10"};
            EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        }
        {
            // env is cached on the first access, so not reflected.
            EnvVarScope scope{CudaBackend::kCudnnMaxWorkspaceSizeEnvVarName, "0"};
            EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        }
    }
}

}  // namespace
}  // namespace cuda
}  // namespace xchainer
<commit_msg>fix clang-tidy<commit_after>#include "xchainer/cuda/cuda_backend.h"

#include <stdlib.h>  // NOLINT

#include <tuple>

#include <cuda_runtime.h>
#include <gtest/gtest.h>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/cuda/cuda_runtime.h"
#include "xchainer/device.h"
#include "xchainer/indexable_array.h"
#include "xchainer/indexer.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/routines/creation.h"
#include "xchainer/testing/util.h"

namespace xchainer {
namespace cuda {
namespace {

template <typename T>
void ExpectDataEqual(const std::shared_ptr<void>& expected, const std::shared_ptr<void>& actual, size_t size) {
    auto expected_raw_ptr = static_cast<const T*>(expected.get());
    auto actual_raw_ptr = static_cast<const T*>(actual.get());
    for (size_t i = 0; i < size; ++i) {
        EXPECT_EQ(expected_raw_ptr[i], actual_raw_ptr[i]);
    }
}

void ExpectArraysEqual(const Array& expected, const Array& actual) {
    EXPECT_EQ(expected.dtype(), actual.dtype());
    EXPECT_EQ(expected.shape(), actual.shape());

    VisitDtype(expected.dtype(), [&expected, &actual](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> expected_iarray{expected};
        IndexableArray<const T> actual_iarray{actual};
        Indexer<> indexer{expected.shape()};

        actual.device().Synchronize();
        expected.device().Synchronize();

        for (auto it = indexer.It(0); it; ++it) {
            EXPECT_EQ(expected_iarray[it], actual_iarray[it]);
        }
    });
}

TEST(CudaBackendTest, GetDeviceCount) {
    Context ctx;
    int count = 0;
    CheckCudaError(cudaGetDeviceCount(&count));
    EXPECT_EQ(count, CudaBackend(ctx).GetDeviceCount());
}

TEST(CudaBackendTest, GetDevice) {
    Context ctx;
    CudaBackend backend{ctx};

    Device& device = backend.GetDevice(0);
    EXPECT_EQ(&backend, &device.backend());
    EXPECT_EQ(0, device.index());
}

TEST(CudaBackendTest, GetDeviceSecondDevice) {
    Context ctx;
    CudaBackend backend{ctx};
    XCHAINER_REQUIRE_DEVICE(backend, 2);

    Device& device1 = backend.GetDevice(1);
    EXPECT_EQ(&backend, &device1.backend());
    EXPECT_EQ(1, device1.index());
}

TEST(CudaBackendTest, GetDeviceOutOfRange) {
    Context ctx;
    CudaBackend backend{ctx};

    EXPECT_THROW(backend.GetDevice(-1), std::out_of_range);
    EXPECT_THROW(backend.GetDevice(backend.GetDeviceCount() + 1), std::out_of_range);
}

TEST(CudaBackendTest, GetName) {
    Context ctx;
    EXPECT_EQ("cuda", CudaBackend(ctx).GetName());
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentContexts) {
    Context ctx0;
    Context ctx1;
    CudaBackend backend0{ctx0};
    CudaBackend backend1{ctx1};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferNativeBackends) {
    Context ctx;
    CudaBackend cuda_backend{ctx};
    native::NativeBackend native_backend0{ctx};
    native::NativeBackend native_backend1{ctx};
    Device& device0 = native_backend0.GetDevice(0);
    Device& device1 = native_backend1.GetDevice(0);
    EXPECT_FALSE(cuda_backend.SupportsTransfer(device0, device1));
}

template <int N>
class DerivedCudaBackend : public CudaBackend {
public:
    using CudaBackend::CudaBackend;
    std::string GetName() const override { return "derived" + std::to_string(N); }
};

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentCudaBackends) {
    Context ctx;
    DerivedCudaBackend<0> backend0{ctx};
    DerivedCudaBackend<1> backend1{ctx};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

// Data transfer test
class CudaBackendTransferTest : public ::testing::TestWithParam<::testing::tuple<std::string, std::string, int>> {};

INSTANTIATE_TEST_CASE_P(
        Devices,
        CudaBackendTransferTest,
        ::testing::Values(
                // 3rd parameter is the number of required CUDA devices to run the test.
                std::make_tuple("cuda:0", "cuda:0", 1),  // cuda:0 <-> cuda:0
                std::make_tuple("cuda:0", "cuda:1", 2),  // cuda:0 <-> cuda:1
                std::make_tuple("cuda:0", "native:0", 1)));  // cuda:0 <-> native:0

TEST_P(CudaBackendTransferTest, SupportsTransfer) {
    Context ctx;
    Backend& backend = ctx.GetBackend("cuda");
    XCHAINER_REQUIRE_DEVICE(backend, ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));
    EXPECT_TRUE(backend.SupportsTransfer(device0, device1));
}

TEST_P(CudaBackendTransferTest, MemoryCopyFrom) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyFromZeroByte) {
    size_t size = 0;
    size_t bytesize = 0;
    std::shared_ptr<void> src_orig(nullptr, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyTo) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyToZeroByte) {
    size_t size = 0;
    size_t bytesize = 0;
    std::shared_ptr<void> src_orig(nullptr, [](float*) {});

    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromHostMemory(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, TransferDataFrom) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device1.Allocate(bytesize);

    // Transfer
    std::shared_ptr<void> trans_data = device0.TransferDataFrom(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), trans_data.get(), bytesize));

    // Destination is ALWAYS CUDA device
    cudaPointerAttributes attr = {};
    CheckCudaError(cudaPointerGetAttributes(&attr, trans_data.get()));
    EXPECT_TRUE(attr.isManaged);
    EXPECT_EQ(device0.index(), attr.device);
}

TEST_P(CudaBackendTransferTest, TransferDataTo) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device0.Allocate(bytesize);

    // Transfer
    std::shared_ptr<void> trans_data = device0.TransferDataTo(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), trans_data.get(), bytesize));

    if (nullptr != dynamic_cast<CudaBackend*>(&device1.backend())) {
        // Destination is CUDA device
        cudaPointerAttributes attr = {};
        CheckCudaError(cudaPointerGetAttributes(&attr, trans_data.get()));
        EXPECT_TRUE(attr.isManaged);
        EXPECT_EQ(device1.index(), attr.device);
    } else {
        // Destination is native device
        EXPECT_FALSE(IsPointerCudaMemory(trans_data.get()));
    }
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceFrom) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = xchainer::internal::FromContiguousHostData({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device1);

    // Transfer
    Array b = a.ToDevice(device0);

    EXPECT_EQ(&b.device(), &device0);
    EXPECT_EQ(&a.device(), &device1);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same native device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get())
                << "Array::ToDevice() must not return alias when transferring to different native device.";
    }
    ExpectArraysEqual(a, b);
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceTo) {
    Context ctx;
    XCHAINER_REQUIRE_DEVICE(ctx.GetBackend("cuda"), ::testing::get<2>(GetParam()));
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = xchainer::internal::FromContiguousHostData({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device0);

    // Transfer
    Array b = a.ToDevice(device1);

    EXPECT_EQ(&b.device(), &device1);
    EXPECT_EQ(&a.device(), &device0);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same CUDA device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get()) << "Array::ToDevice() must not return alias when transferring to a different device.";
    }
    ExpectArraysEqual(a, b);
}

class EnvVarScope {
public:
    EnvVarScope(std::string name, const std::string& value) : name_(std::move(name)) {
        const char* old_value = getenv(name_.c_str());
        if (old_value) {
            old_value_ = std::string(old_value);
        }
        setenv(name_.c_str(), value.c_str(), 1);
    }

    ~EnvVarScope() {
        if (old_value_) {
            setenv(name_.c_str(), old_value_->c_str(), 1);
        } else {
            unsetenv(name_.c_str());
        }
    }

private:
    const std::string name_{};
    nonstd::optional<std::string> old_value_{};
};

TEST(CudaBackendTest, GetCudnnMaxWorkspaceSize) {
    Context ctx;
    {
        CudaBackend backend{ctx};
        EXPECT_EQ(CudaBackend::kCudnnDefaultMaxWorkspaceSize, backend.GetCudnnMaxWorkspaceSize());
    }
    {
        CudaBackend backend{ctx};
        backend.SetCudnnMaxWorkspaceSize(10);
        EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        backend.SetCudnnMaxWorkspaceSize(0);
        EXPECT_EQ(size_t{0}, backend.GetCudnnMaxWorkspaceSize());
    }
    {
        CudaBackend backend{ctx};
        {
            EnvVarScope scope{CudaBackend::kCudnnMaxWorkspaceSizeEnvVarName, "10"};
            EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        }
        {
            // env is cached on the first access, so not reflected.
            EnvVarScope scope{CudaBackend::kCudnnMaxWorkspaceSizeEnvVarName, "0"};
            EXPECT_EQ(size_t{10}, backend.GetCudnnMaxWorkspaceSize());
        }
    }
}

}  // namespace
}  // namespace cuda
}  // namespace xchainer
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TYPE_HPP
#define REALM_COLUMN_TYPE_HPP

namespace realm {

// Note: Enumeration value assignments must be kept in sync with
// <realm/data_type.hpp>.
enum ColumnType {
    // Column types
    col_type_Int         =  0,
    col_type_Bool        =  1,
    col_type_String      =  2,
    col_type_StringEnum  =  3, // double refs
    col_type_Binary      =  4,
    col_type_Table       =  5,
    col_type_Mixed       =  6,
    col_type_DateTime    =  7,
    col_type_Reserved1   =  8, // new date
    col_type_Float       =  9,
    col_type_Double      = 10,
    col_type_Reserved4   = 11, // Decimal
    col_type_Link        = 12,
    col_type_LinkList    = 13,
    col_type_BackLink    = 14,
    col_type_NewDate     = 15 // FIXME, can it be moved up?

};

// Column attributes can be combined using bitwise or.
enum ColumnAttr {
    col_attr_None = 0,
    col_attr_Indexed = 1,

    /// Specifies that this column forms a unique constraint. It requires
    /// `col_attr_Indexed`.
    col_attr_Unique = 2,

    /// Reserved for future use.
    col_attr_Reserved = 4,

    /// Specifies that the links of this column are strong, not weak. Applies
    /// only to link columns (`type_Link` and `type_LinkList`).
    col_attr_StrongLinks = 8,

    /// Specifies that elements in the column can be null.
    col_attr_Nullable = 16
};

} // namespace realm

#endif // REALM_COLUMN_TYPE_HPP
<commit_msg>fixed col_type_NewDate<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TYPE_HPP
#define REALM_COLUMN_TYPE_HPP

namespace realm {

// Note: Enumeration value assignments must be kept in sync with
// <realm/data_type.hpp>.
enum ColumnType {
    // Column types
    col_type_Int         =  0,
    col_type_Bool        =  1,
    col_type_String      =  2,
    col_type_StringEnum  =  3, // double refs
    col_type_Binary      =  4,
    col_type_Table       =  5,
    col_type_Mixed       =  6,
    col_type_DateTime    =  7,
    col_type_NewDate     =  8, // new date
    col_type_Float       =  9,
    col_type_Double      = 10,
    col_type_Reserved4   = 11, // Decimal
    col_type_Link        = 12,
    col_type_LinkList    = 13,
    col_type_BackLink    = 14
};

// Column attributes can be combined using bitwise or.
enum ColumnAttr {
    col_attr_None = 0,
    col_attr_Indexed = 1,

    /// Specifies that this column forms a unique constraint. It requires
    /// `col_attr_Indexed`.
    col_attr_Unique = 2,

    /// Reserved for future use.
    col_attr_Reserved = 4,

    /// Specifies that the links of this column are strong, not weak. Applies
    /// only to link columns (`type_Link` and `type_LinkList`).
    col_attr_StrongLinks = 8,

    /// Specifies that elements in the column can be null.
    col_attr_Nullable = 16
};

} // namespace realm

#endif // REALM_COLUMN_TYPE_HPP
<|endoftext|>