<commit_before>/*!
 * \page StandardAirlineITTestSuite_cpp Command-Line Test to Demonstrate How To Extend StdAir BOM
 * \code
 */
// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <sstream>
#include <fstream>
#include <string>
// Boost MPL
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
// Boost Unit Test Framework (UTF)
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE StdAirTest
#if BOOST_VERSION >= 103900
#include <boost/test/unit_test.hpp>
#else  // BOOST_VERSION >= 103900
#include <boost/test/test_tools.hpp>
#include <boost/test/results_reporter.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/output_test_stream.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/unit_test_parameters.hpp>
#endif // BOOST_VERSION >= 103900
// Boost Serialisation
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
// StdAir
#include <stdair/stdair_inventory_types.hpp>
#include <stdair/service/Logger.hpp>
#include <stdair/STDAIR_Service.hpp>
#include <stdair/basic/float_utils.hpp>
#include <stdair/bom/BomDisplay.hpp>
#include <stdair/bom/BomRoot.hpp>
#include <stdair/bom/BomManager.hpp>
#include <stdair/factory/FacBom.hpp>
#include <stdair/factory/FacBomManager.hpp>
// StdAir Test Suite
#include <test/stdair/StdairTestLib.hpp>
#include <test/stdair/MPInventory.hpp>

namespace boost_utf = boost::unit_test;

#if BOOST_VERSION >= 103900

// (Boost) Unit Test XML Report
std::ofstream utfReportStream ("StandardAirlineITTestSuite_utfresults.xml");

/**
 * Configuration for the Boost Unit Test Framework (UTF)
 */
struct UnitTestConfig {
  /** Constructor. */
  UnitTestConfig() {
    boost_utf::unit_test_log.set_stream (utfReportStream);
    boost_utf::unit_test_log.set_format (boost_utf::XML);
    boost_utf::unit_test_log.set_threshold_level (boost_utf::log_test_units);
    // boost_utf::unit_test_log.set_threshold_level (boost_utf::log_successful_tests);
  }

  /** Destructor. */
  ~UnitTestConfig() {
  }
};

// /////////////// Main: Unit Test Suite //////////////

// Set the UTF configuration (re-direct the output to a specific file)
BOOST_GLOBAL_FIXTURE (UnitTestConfig);

// Start the test suite
BOOST_AUTO_TEST_SUITE (master_test_suite)

/**
 * Test the comparison of two floating point numbers, first the Boost way,
 * then the Google way.
 */
BOOST_AUTO_TEST_CASE (float_comparison_test) {
  float a = 0.2f;
  a = 5*a;
  const float b = 1.0f;

  // Test the Boost way
  BOOST_CHECK_MESSAGE (a == b, "The two floats (" << a << " and " << b
                       << ") should be equal, but are not");
  BOOST_CHECK_CLOSE (a, b, 0.0001);

  // Test the Google way
  const FloatingPoint<float> lhs (a), rhs (b);
  BOOST_CHECK_MESSAGE (lhs.AlmostEquals (rhs),
                       "The two floats (" << a << " and " << b
                       << ") should be equal, but are not");
}

/**
 * Test MPL-based type handling, just as a proof-of-concept. It does
 * not use StdAir BOM.
 */
BOOST_AUTO_TEST_CASE (mpl_structure_test) {
  const stdair::ClassCode_T lBookingClassCodeA ("A");
  const stdair_test::BookingClass lA (lBookingClassCodeA);
  const stdair_test::Cabin lCabin (lA);

  BOOST_CHECK_EQUAL (lCabin.toString(), lBookingClassCodeA);
  BOOST_CHECK_MESSAGE (lCabin.toString() == lBookingClassCodeA,
                       "The cabin key, '" << lCabin.toString()
                       << "' is not equal to '" << lBookingClassCodeA << "'");

  // MPL
  typedef boost::mpl::vector<stdair_test::BookingClass> MPL_BookingClass;
  typedef boost::mpl::push_back<MPL_BookingClass,
                                stdair_test::Cabin>::type types;

  if (boost::is_same<stdair_test::BookingClass,
                     stdair_test::Cabin::child>::value == false) {
    BOOST_ERROR ("The two types mut be equal, but are not");
  }

  if (boost::is_same<boost::mpl::at_c<types, 1>::type,
                     stdair_test::Cabin>::value == false) {
    BOOST_ERROR ("The type must be stdair_test::Cabin, but is not");
  }
}

/**
 * Test the initialisation of the Standard Airline IT base library.
 */
BOOST_AUTO_TEST_CASE (stdair_service_initialisation_test) {
  // Output log File
  const std::string lLogFilename ("StandardAirlineITTestSuite_init.log");

  // Set the log parameters
  std::ofstream logOutputFile;

  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the stdair BOM
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  stdair::STDAIR_Service stdairService (lLogParams);

  // Retrieve (a reference on) the top of the BOM tree
  stdair::BomRoot& lBomRoot = stdairService.getBomRoot();

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string& lBomRootKeyStr = lBomRoot.describeKey();
  const std::string lBomRootString (" -- ROOT -- ");

  // DEBUG
  STDAIR_LOG_DEBUG ("The BOM root key is '" << lBomRootKeyStr
                    << "'. It should be equal to '" << lBomRootString << "'");

  BOOST_CHECK_EQUAL (lBomRootKeyStr, lBomRootString);
  BOOST_CHECK_MESSAGE (lBomRootKeyStr == lBomRootString,
                       "The BOM root key, '" << lBomRootKeyStr
                       << "', should be equal to '" << lBomRootString
                       << "', but is not.");

  // Build a sample BOM tree
  stdairService.buildSampleBom();

  // DEBUG: Display the whole BOM tree
  const std::string& lCSVDump = stdairService.csvDisplay();
  STDAIR_LOG_DEBUG (lCSVDump);

  // Close the Log outputFile
  logOutputFile.close();
}

/**
 * Test the initialisation of Standard Airline IT BOM objects.
 */
BOOST_AUTO_TEST_CASE (bom_structure_instantiation_test) {
  // Step 0.0: initialisation
  // Create the root of the Bom tree (i.e., a BomRoot object)
  stdair::BomRoot& lBomRoot =
    stdair::FacBom<stdair::BomRoot>::instance().create();

  // Step 0.1: Inventory level
  // Create an Inventory (BA)
  const stdair::AirlineCode_T lBAAirlineCode ("BA");
  const stdair::InventoryKey lBAKey (lBAAirlineCode);
  myprovider::Inventory& lBAInv =
    stdair::FacBom<myprovider::Inventory>::instance().create (lBAKey);
  stdair::FacBomManager::addToList (lBomRoot, lBAInv);

  BOOST_CHECK_EQUAL (lBAInv.describeKey(), lBAAirlineCode);
  BOOST_CHECK_MESSAGE (lBAInv.describeKey() == lBAAirlineCode,
                       "The inventory key, '" << lBAInv.describeKey()
                       << "', should be equal to '" << lBAAirlineCode
                       << "', but is not");

  // Create an Inventory for AF
  const stdair::AirlineCode_T lAFAirlineCode ("AF");
  const stdair::InventoryKey lAFKey (lAFAirlineCode);
  myprovider::Inventory& lAFInv =
    stdair::FacBom<myprovider::Inventory>::instance().create (lAFKey);
  stdair::FacBomManager::addToList (lBomRoot, lAFInv);

  BOOST_CHECK_EQUAL (lAFInv.describeKey(), lAFAirlineCode);
  BOOST_CHECK_MESSAGE (lAFInv.describeKey() == lAFAirlineCode,
                       "The inventory key, '" << lAFInv.describeKey()
                       << "', should be equal to '" << lAFAirlineCode
                       << "', but is not");

  // Browse the inventories
  const myprovider::InventoryList_T& lInventoryList =
      stdair::BomManager::getList<myprovider::Inventory> (lBomRoot);
  const std::string lInventoryKeyArray[2] = {lBAAirlineCode, lAFAirlineCode};
  short idx = 0;
  for (myprovider::InventoryList_T::const_iterator itInv =
         lInventoryList.begin(); itInv != lInventoryList.end();
       ++itInv, ++idx) {
    const myprovider::Inventory* lInv_ptr = *itInv;
    BOOST_REQUIRE (lInv_ptr != NULL);

    BOOST_CHECK_EQUAL (lInventoryKeyArray[idx], lInv_ptr->describeKey());
    BOOST_CHECK_MESSAGE (lInventoryKeyArray[idx] == lInv_ptr->describeKey(),
                         "They inventory key, '" << lInventoryKeyArray[idx]
                         << "', does not match that of the Inventory object: '"
                         << lInv_ptr->describeKey() << "'");
  }
}

/**
 * Test the serialisation of Standard Airline IT BOM objects.
 */
BOOST_AUTO_TEST_CASE (bom_structure_serialisation_test) {

  // Backup (thanks to Boost.Serialisation) file
  const std::string lBackupFilename = "StandardAirlineITTestSuite_serial.txt";

  // Output log File
  const std::string lLogFilename ("StandardAirlineITTestSuite_serial.log");

  // Set the log parameters
  std::ofstream logOutputFile;

  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the stdair BOM
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  stdair::STDAIR_Service stdairService (lLogParams);

  // Build a sample BOM tree
  stdairService.buildSampleBom();

  // DEBUG: Display the whole BOM tree
  const std::string& lCSVDump = stdairService.csvDisplay();
  STDAIR_LOG_DEBUG (lCSVDump);

  // Clone the persistent BOM
  stdairService.clonePersistentBom ();

  // Retrieve (a reference on) the top of the BOM tree
  stdair::BomRoot& lBomRoot = stdairService.getBomRoot();

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string lBAInvKeyStr ("BA");
  stdair::Inventory* lBAInv_ptr = lBomRoot.getInventory (lBAInvKeyStr);

  // DEBUG
  STDAIR_LOG_DEBUG ("There should be an Inventory object corresponding to the '"
                    << lBAInvKeyStr << "' key.");

  BOOST_REQUIRE_MESSAGE (lBAInv_ptr != NULL,
                         "An Inventory object should exist with the key, '"
                         << lBAInvKeyStr << "'.");

  // create and open a character archive for output
  std::ofstream ofs (lBackupFilename.c_str());

  // save data to archive
  {
    boost::archive::text_oarchive oa (ofs);
    // write class instance to archive
    oa << lBomRoot;
    // archive and stream closed when destructors are called
  }

  // ... some time later restore the class instance to its orginal state
  stdair::BomRoot& lRestoredBomRoot =
    stdair::FacBom<stdair::BomRoot>::instance().create();
  {
    // create and open an archive for input
    std::ifstream ifs (lBackupFilename.c_str());
    boost::archive::text_iarchive ia(ifs);
    // read class state from archive
    ia >> lRestoredBomRoot;
    // archive and stream closed when destructors are called
  }

  // DEBUG: Display the whole BOM tree
  std::ostringstream oRestoredCSVDumpStr;
  stdair::BomDisplay::csvDisplay (oRestoredCSVDumpStr, lRestoredBomRoot);
  STDAIR_LOG_DEBUG (oRestoredCSVDumpStr.str());

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string& lBomRootKeyStr = lRestoredBomRoot.describeKey();
  const std::string lBomRootString (" -- ROOT -- ");

  // DEBUG
  STDAIR_LOG_DEBUG ("The BOM root key is '" << lBomRootKeyStr
                    << "'. It should be equal to '" << lBomRootString << "'");

  BOOST_CHECK_EQUAL (lBomRootKeyStr, lBomRootString);
  BOOST_CHECK_MESSAGE (lBomRootKeyStr == lBomRootString,
                       "The BOM root key, '" << lBomRootKeyStr
                       << "', should be equal to '" << lBomRootString
                       << "', but is not.");

  // Retrieve the Inventory
  stdair::Inventory* lRestoredBAInv_ptr =
    lRestoredBomRoot.getInventory (lBAInvKeyStr);

  // DEBUG
  STDAIR_LOG_DEBUG ("There should be an Inventory object corresponding to the '"
                    << lBAInvKeyStr << "' key.");

  BOOST_CHECK_MESSAGE (lRestoredBAInv_ptr != NULL,
                       "An Inventory object should exist with the key, '"
                       << lBAInvKeyStr << "'.");

  // Close the Log outputFile
  logOutputFile.close();
}

// End the test suite
BOOST_AUTO_TEST_SUITE_END()

#else // BOOST_VERSION >= 103900
boost_utf::test_suite* init_unit_test_suite (int, char* []) {
  boost_utf::test_suite* test = BOOST_TEST_SUITE ("Unit test example 1");
  return test;
}
#endif // BOOST_VERSION >= 103900

/*!
 * \endcode
 */
<commit_msg>[Test] Added a test to check the cloning process of Standard Airline IT BOM objects.<commit_after>/*!
 * \page StandardAirlineITTestSuite_cpp Command-Line Test to Demonstrate How To Extend StdAir BOM
 * \code
 */
// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <sstream>
#include <fstream>
#include <string>
// Boost MPL
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
// Boost Unit Test Framework (UTF)
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE StdAirTest
#if BOOST_VERSION >= 103900
#include <boost/test/unit_test.hpp>
#else  // BOOST_VERSION >= 103900
#include <boost/test/test_tools.hpp>
#include <boost/test/results_reporter.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/output_test_stream.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/unit_test_parameters.hpp>
#endif // BOOST_VERSION >= 103900
// Boost Serialisation
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
// StdAir
#include <stdair/stdair_inventory_types.hpp>
#include <stdair/service/Logger.hpp>
#include <stdair/STDAIR_Service.hpp>
#include <stdair/basic/float_utils.hpp>
#include <stdair/bom/BomDisplay.hpp>
#include <stdair/bom/BomRoot.hpp>
#include <stdair/bom/BomManager.hpp>
#include <stdair/factory/FacBom.hpp>
#include <stdair/factory/FacBomManager.hpp>
// StdAir Test Suite
#include <test/stdair/StdairTestLib.hpp>
#include <test/stdair/MPInventory.hpp>

namespace boost_utf = boost::unit_test;

#if BOOST_VERSION >= 103900

// (Boost) Unit Test XML Report
std::ofstream utfReportStream ("StandardAirlineITTestSuite_utfresults.xml");

/**
 * Configuration for the Boost Unit Test Framework (UTF)
 */
struct UnitTestConfig {
  /** Constructor. */
  UnitTestConfig() {
    boost_utf::unit_test_log.set_stream (utfReportStream);
    boost_utf::unit_test_log.set_format (boost_utf::XML);
    boost_utf::unit_test_log.set_threshold_level (boost_utf::log_test_units);
    // boost_utf::unit_test_log.set_threshold_level (boost_utf::log_successful_tests);
  }

  /** Destructor. */
  ~UnitTestConfig() {
  }
};

// /////////////// Main: Unit Test Suite //////////////

// Set the UTF configuration (re-direct the output to a specific file)
BOOST_GLOBAL_FIXTURE (UnitTestConfig);

// Start the test suite
BOOST_AUTO_TEST_SUITE (master_test_suite)

/**
 * Test the comparison of two floating point numbers, first the Boost way,
 * then the Google way.
 */
BOOST_AUTO_TEST_CASE (float_comparison_test) {
  float a = 0.2f;
  a = 5*a;
  const float b = 1.0f;

  // Test the Boost way
  BOOST_CHECK_MESSAGE (a == b, "The two floats (" << a << " and " << b
                       << ") should be equal, but are not");
  BOOST_CHECK_CLOSE (a, b, 0.0001);

  // Test the Google way
  const FloatingPoint<float> lhs (a), rhs (b);
  BOOST_CHECK_MESSAGE (lhs.AlmostEquals (rhs),
                       "The two floats (" << a << " and " << b
                       << ") should be equal, but are not");
}

/**
 * Test MPL-based type handling, just as a proof-of-concept. It does
 * not use StdAir BOM.
 */
BOOST_AUTO_TEST_CASE (mpl_structure_test) {
  const stdair::ClassCode_T lBookingClassCodeA ("A");
  const stdair_test::BookingClass lA (lBookingClassCodeA);
  const stdair_test::Cabin lCabin (lA);

  BOOST_CHECK_EQUAL (lCabin.toString(), lBookingClassCodeA);
  BOOST_CHECK_MESSAGE (lCabin.toString() == lBookingClassCodeA,
                       "The cabin key, '" << lCabin.toString()
                       << "' is not equal to '" << lBookingClassCodeA << "'");

  // MPL
  typedef boost::mpl::vector<stdair_test::BookingClass> MPL_BookingClass;
  typedef boost::mpl::push_back<MPL_BookingClass,
                                stdair_test::Cabin>::type types;

  if (boost::is_same<stdair_test::BookingClass,
                     stdair_test::Cabin::child>::value == false) {
    BOOST_ERROR ("The two types mut be equal, but are not");
  }

  if (boost::is_same<boost::mpl::at_c<types, 1>::type,
                     stdair_test::Cabin>::value == false) {
    BOOST_ERROR ("The type must be stdair_test::Cabin, but is not");
  }
}

/**
 * Test the initialisation of the Standard Airline IT base library.
 */
BOOST_AUTO_TEST_CASE (stdair_service_initialisation_test) {
  // Output log File
  const std::string lLogFilename ("StandardAirlineITTestSuite_init.log");

  // Set the log parameters
  std::ofstream logOutputFile;

  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the stdair BOM
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  stdair::STDAIR_Service stdairService (lLogParams);

  // Retrieve (a reference on) the top of the persistent BOM tree
  stdair::BomRoot& lPersistentBomRoot = stdairService.getPersistentBomRoot();

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string& lBomRootKeyStr = lPersistentBomRoot.describeKey();
  const std::string lBomRootString (" -- ROOT -- ");

  // DEBUG
  STDAIR_LOG_DEBUG ("The BOM root key is '" << lBomRootKeyStr
                    << "'. It should be equal to '" << lBomRootString << "'");

  BOOST_CHECK_EQUAL (lBomRootKeyStr, lBomRootString);
  BOOST_CHECK_MESSAGE (lBomRootKeyStr == lBomRootString,
                       "The BOM root key, '" << lBomRootKeyStr
                       << "', should be equal to '" << lBomRootString
                       << "', but is not.");

  // Build a sample BOM tree
  stdairService.buildSampleBom();

  // DEBUG: Display the whole BOM tree
  const std::string& lCSVDump = stdairService.csvDisplay(lPersistentBomRoot);
  STDAIR_LOG_DEBUG (lCSVDump);

  // Close the Log outputFile
  logOutputFile.close();
}

/**
 * Test the initialisation of Standard Airline IT BOM objects.
 */
BOOST_AUTO_TEST_CASE (bom_structure_instantiation_test) {
  // Step 0.0: initialisation
  // Create the root of a Bom tree (i.e., a BomRoot object)
  stdair::BomRoot& lBomRoot =
    stdair::FacBom<stdair::BomRoot>::instance().create();

  // Step 0.1: Inventory level
  // Create an Inventory (BA)
  const stdair::AirlineCode_T lBAAirlineCode ("BA");
  const stdair::InventoryKey lBAKey (lBAAirlineCode);
  myprovider::Inventory& lBAInv =
    stdair::FacBom<myprovider::Inventory>::instance().create (lBAKey);
  stdair::FacBomManager::addToList (lBomRoot, lBAInv);

  BOOST_CHECK_EQUAL (lBAInv.describeKey(), lBAAirlineCode);
  BOOST_CHECK_MESSAGE (lBAInv.describeKey() == lBAAirlineCode,
                       "The inventory key, '" << lBAInv.describeKey()
                       << "', should be equal to '" << lBAAirlineCode
                       << "', but is not");

  // Create an Inventory for AF
  const stdair::AirlineCode_T lAFAirlineCode ("AF");
  const stdair::InventoryKey lAFKey (lAFAirlineCode);
  myprovider::Inventory& lAFInv =
    stdair::FacBom<myprovider::Inventory>::instance().create (lAFKey);
  stdair::FacBomManager::addToList (lBomRoot, lAFInv);

  BOOST_CHECK_EQUAL (lAFInv.describeKey(), lAFAirlineCode);
  BOOST_CHECK_MESSAGE (lAFInv.describeKey() == lAFAirlineCode,
                       "The inventory key, '" << lAFInv.describeKey()
                       << "', should be equal to '" << lAFAirlineCode
                       << "', but is not");

  // Browse the inventories
  const myprovider::InventoryList_T& lInventoryList =
      stdair::BomManager::getList<myprovider::Inventory> (lBomRoot);
  const std::string lInventoryKeyArray[2] = {lBAAirlineCode, lAFAirlineCode};
  short idx = 0;
  for (myprovider::InventoryList_T::const_iterator itInv =
         lInventoryList.begin(); itInv != lInventoryList.end();
       ++itInv, ++idx) {
    const myprovider::Inventory* lInv_ptr = *itInv;
    BOOST_REQUIRE (lInv_ptr != NULL);

    BOOST_CHECK_EQUAL (lInventoryKeyArray[idx], lInv_ptr->describeKey());
    BOOST_CHECK_MESSAGE (lInventoryKeyArray[idx] == lInv_ptr->describeKey(),
                         "They inventory key, '" << lInventoryKeyArray[idx]
                         << "', does not match that of the Inventory object: '"
                         << lInv_ptr->describeKey() << "'");
  }
}

/**
 * Test the serialisation of Standard Airline IT BOM objects.
 */
BOOST_AUTO_TEST_CASE (bom_structure_serialisation_test) {

  // Backup (thanks to Boost.Serialisation) file
  const std::string lBackupFilename = "StandardAirlineITTestSuite_serial.txt";

  // Output log File
  const std::string lLogFilename ("StandardAirlineITTestSuite_serial.log");

  // Set the log parameters
  std::ofstream logOutputFile;

  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the stdair BOM
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  stdair::STDAIR_Service stdairService (lLogParams);

  // Build a sample BOM tree
  stdairService.buildSampleBom();

  // Retrieve (a reference on) the top of the persistent BOM tree
  stdair::BomRoot& lPersistentBomRoot = stdairService.getPersistentBomRoot();

  // DEBUG: Display the whole BOM tree
  const std::string& lCSVDump = stdairService.csvDisplay(lPersistentBomRoot);
  STDAIR_LOG_DEBUG (lCSVDump);

  // Clone the persistent BOM
  stdairService.clonePersistentBom ();

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string lBAInvKeyStr ("BA");
  stdair::Inventory* lBAInv_ptr =
    lPersistentBomRoot.getInventory (lBAInvKeyStr);

  // DEBUG
  STDAIR_LOG_DEBUG ("There should be an Inventory object corresponding to the '"
                    << lBAInvKeyStr << "' key.");

  BOOST_REQUIRE_MESSAGE (lBAInv_ptr != NULL,
                         "An Inventory object should exist with the key, '"
                         << lBAInvKeyStr << "'.");

  // create and open a character archive for output
  std::ofstream ofs (lBackupFilename.c_str());

  // save data to archive
  {
    boost::archive::text_oarchive oa (ofs);
    // write class instance to archive
    oa << lPersistentBomRoot;
    // archive and stream closed when destructors are called
  }

  // ... some time later restore the class instance to its orginal state
  stdair::BomRoot& lRestoredBomRoot =
    stdair::FacBom<stdair::BomRoot>::instance().create();
  {
    // create and open an archive for input
    std::ifstream ifs (lBackupFilename.c_str());
    boost::archive::text_iarchive ia(ifs);
    // read class state from archive
    ia >> lRestoredBomRoot;
    // archive and stream closed when destructors are called
  }

  // DEBUG: Display the whole restored BOM tree
  const std::string& lRestoredCSVDump =
    stdairService.csvDisplay(lRestoredBomRoot);
  STDAIR_LOG_DEBUG (lRestoredCSVDump);

  // Retrieve the BomRoot key, and compare it to the expected one
  const std::string& lBomRootKeyStr = lRestoredBomRoot.describeKey();
  const std::string lBomRootString (" -- ROOT -- ");

  // DEBUG
  STDAIR_LOG_DEBUG ("The BOM root key is '" << lBomRootKeyStr
                    << "'. It should be equal to '" << lBomRootString << "'");

  BOOST_CHECK_EQUAL (lBomRootKeyStr, lBomRootString);
  BOOST_CHECK_MESSAGE (lBomRootKeyStr == lBomRootString,
                       "The BOM root key, '" << lBomRootKeyStr
                       << "', should be equal to '" << lBomRootString
                       << "', but is not.");

  // Retrieve the Inventory
  stdair::Inventory* lRestoredBAInv_ptr =
    lRestoredBomRoot.getInventory (lBAInvKeyStr);

  // DEBUG
  STDAIR_LOG_DEBUG ("There should be an Inventory object corresponding to the '"
                    << lBAInvKeyStr << "' key in the restored BOM root.");

  BOOST_CHECK_MESSAGE (lRestoredBAInv_ptr != NULL,
                       "An Inventory object should exist with the key, '"
                       << lBAInvKeyStr << "' in the restored BOM root.");

  // Close the Log outputFile
  logOutputFile.close();
}

/**
 * Test the clone of Standard Airline IT BOM objects.
 */
BOOST_AUTO_TEST_CASE (bom_structure_clone_test) {

  // Output log File
  const std::string lLogFilename ("StandardAirlineITTestSuite_clone.log");

  // Set the log parameters
  std::ofstream logOutputFile;

  // Open and clean the log outputfile
  logOutputFile.open (lLogFilename.c_str());
  logOutputFile.clear();

  // Initialise the stdair BOM
  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
  stdair::STDAIR_Service stdairService (lLogParams);

  // Build a sample BOM tree
  stdairService.buildSampleBom();

  // Retrieve (a constant reference on) the top of the persistent BOM tree
  const stdair::BomRoot& lPersistentBomRoot =
    stdairService.getPersistentBomRoot();

  // DEBUG: Display the whole persistent BOM tree
  const std::string& lCSVDump = stdairService.csvDisplay(lPersistentBomRoot);
  STDAIR_LOG_DEBUG ("Display the persistent BOM tree.");
  STDAIR_LOG_DEBUG (lCSVDump);

  // Retrieve (a reference on) the top of the clone BOM tree
  stdair::BomRoot& lCloneBomRoot = stdairService.getBomRoot();

  // DEBUG: Display the clone BOM tree before the clone process.
  const std::string& lBeforeCloneCSVDump =
    stdairService.csvDisplay(lCloneBomRoot);
  STDAIR_LOG_DEBUG ("Display the clone BOM tree before the clone process.");
  STDAIR_LOG_DEBUG (lBeforeCloneCSVDump);

  // Clone the persistent BOM
  stdairService.clonePersistentBom ();

  // DEBUG: Display the clone BOM tree after the clone process.
  const std::string& lAfterCloneCSVDump =
    stdairService.csvDisplay(lCloneBomRoot);
  STDAIR_LOG_DEBUG ("Display the clone BOM tree after the clone process.");
  STDAIR_LOG_DEBUG (lAfterCloneCSVDump);

  // Retrieve the clone BomRoot key, and compare it to the persistent BomRoot
  // key.
  const std::string& lCloneBomRootKeyStr = lCloneBomRoot.describeKey();
  const std::string& lPersistentBomRootKeyStr =
    lPersistentBomRoot.describeKey();

  // DEBUG
  STDAIR_LOG_DEBUG ("The clone BOM root key is '" << lCloneBomRootKeyStr
                    << "'. It should be equal to '"
		    << lPersistentBomRootKeyStr << "'");

  BOOST_CHECK_EQUAL (lCloneBomRootKeyStr, lPersistentBomRootKeyStr);
  BOOST_CHECK_MESSAGE (lCloneBomRootKeyStr == lPersistentBomRootKeyStr,
                       "The clone BOM root key, '" << lCloneBomRootKeyStr
                       << "', should be equal to '" << lPersistentBomRootKeyStr
                       << "', but is not.");

  // Retrieve the BA inventory in the clone BOM root
  const std::string lBAInvKeyStr ("BA");
  stdair::Inventory* lCloneBAInv_ptr =
    lCloneBomRoot.getInventory (lBAInvKeyStr);

  // DEBUG
  STDAIR_LOG_DEBUG ("There should be an Inventory object corresponding to the '"
                    << lBAInvKeyStr << "' key in the clone BOM root.");

  BOOST_CHECK_MESSAGE (lCloneBAInv_ptr != NULL,
                       "An Inventory object should exist with the key, '"
                       << lBAInvKeyStr << "' in the clone BOM root.");

  // Close the Log outputFile
  logOutputFile.close();
}

// End the test suite
BOOST_AUTO_TEST_SUITE_END()

#else // BOOST_VERSION >= 103900
boost_utf::test_suite* init_unit_test_suite (int, char* []) {
  boost_utf::test_suite* test = BOOST_TEST_SUITE ("Unit test example 1");
  return test;
}
#endif // BOOST_VERSION >= 103900

/*!
 * \endcode
 */
<|endoftext|>


<commit_before>/**
 * \file demoFunctionApproximatorTraining.cpp
 * \author Freek Stulp
 * \brief Demonstrates how to train all functionapproximators with 1D and 2D data.
 *
 * \ingroup Demos
 * \ingroup FunctionApproximators
 *
 * This file is part of DmpBbo, a set of libraries and programs for the
 * black-box optimization of dynamical movement primitives.
 * Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
 *
 * DmpBbo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * DmpBbo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <ctime>
#include <boost/filesystem.hpp>

#include "functionapproximators/FunctionApproximator.hpp"
#include "functionapproximators/MetaParametersLWR.hpp"
#include "functionapproximators/FunctionApproximatorLWR.hpp"
#include "functionapproximators/MetaParametersGMR.hpp"
#include "functionapproximators/FunctionApproximatorGMR.hpp"
#include "functionapproximators/MetaParametersRRRFF.hpp"
#include "functionapproximators/FunctionApproximatorRRRFF.hpp"
#include "functionapproximators/MetaParametersGPR.hpp"
#include "functionapproximators/FunctionApproximatorGPR.hpp"
#include "functionapproximators/MetaParametersRBFN.hpp"
#include "functionapproximators/FunctionApproximatorRBFN.hpp"
#ifdef USE_LWPR
#include "functionapproximators/MetaParametersLWPR.hpp"
#include "functionapproximators/FunctionApproximatorLWPR.hpp"
#endif // USE_LWPR

//#include "getFunctionApproximatorsVector.hpp"
#include "targetFunction.hpp"

using namespace std;
using namespace Eigen;
using namespace DmpBbo;

FunctionApproximator* getFunctionApproximatorByName(std::string name, int input_dim)
{

  FunctionApproximator* fa = NULL;
  if (name.compare("LWR")==0)
  {
    // Locally Weighted Regression
    double intersection = 0.6;
    Eigen::VectorXi num_rfs_per_dim = Eigen::VectorXi::Constant(input_dim,9);
    if (input_dim==2) {
      num_rfs_per_dim[0] = 7;
      num_rfs_per_dim[1] = 5;
    }
    double regularization = 0.0;
    MetaParametersLWR* meta_params = new MetaParametersLWR(input_dim,num_rfs_per_dim,intersection,regularization);
    fa = new FunctionApproximatorLWR(meta_params);
  }
  else if (name.compare("GMR")==0)
  {
    // Gaussian Mixture Regression
    int number_of_gaussians = 10;
    if (input_dim==2) number_of_gaussians = 10;
    MetaParametersGMR* meta_params = new MetaParametersGMR(input_dim,number_of_gaussians);
    fa = new FunctionApproximatorGMR(meta_params);
  }
  else if (name.compare("RRRFF")==0)
  {
    // RRRFF
    int number_of_basis_functions=18;
    if (input_dim==2) number_of_basis_functions = 100;
    double regularization=0.2;
    double gamma=5;
    MetaParametersRRRFF* meta_params = new MetaParametersRRRFF(input_dim,number_of_basis_functions,regularization,gamma);
    fa = new FunctionApproximatorRRRFF(meta_params);
  }
  else if (name.compare("RBFN")==0)
  {
    // Radial Basis Function Network
    double intersection = 0.7;
    int n_rfs = 9;
    if (input_dim==2) n_rfs = 5;
    Eigen::VectorXi num_rfs_per_dim = Eigen::VectorXi::Constant(input_dim,n_rfs);
    double regularization = 0.0;
    MetaParametersRBFN* meta_params = new MetaParametersRBFN(input_dim,num_rfs_per_dim,intersection,regularization);
    fa = new FunctionApproximatorRBFN(meta_params);
  }
  else if (name.compare("GPR")==0)
  {
    // Gaussian Process Regression
    double maximum_covariance = 1.1*1.1;
    double length = 0.1;
    if (input_dim==2)
    {
      maximum_covariance = 0.1*0.1;
      length = 0.2;
    }
    MetaParametersGPR* meta_params = new MetaParametersGPR(input_dim,maximum_covariance,length);
    fa = new FunctionApproximatorGPR(meta_params);
  }
  else if (name.compare("LWPR")==0)
  {
    // Locally Weighted Projection Regression
#ifdef USE_LWPR
    double   w_gen=0.2;
    double   w_prune=0.8;
    bool     update_D=true;
    double   init_alpha=0.1;
    double   penalty=0.005;
    Eigen::VectorXd init_D=Eigen::VectorXd::Constant(input_dim,200);
    MetaParametersLWPR* meta_params = new MetaParametersLWPR(input_dim,init_D,w_gen,w_prune,update_D,init_alpha,penalty);
    fa = new FunctionApproximatorLWPR(dynamic_cast<MetaParametersLWPR*>(meta_params));
#else
    std::cerr << __FILE__ << ":" << __LINE__ << ":";
    std::cerr << "Sorry, LWPR is not available. Is it installed? Returning NULL." << std::endl;
    return NULL;
#endif // USE_LWPR
  }

  if (fa==NULL)
  {
    std::cerr << __FILE__ << ":" << __LINE__ << ":";
    std::cerr << "Function approximator with name '" << name << "' is unknown. Returning NULL." << std::endl;
  }

  return fa;
}

/** Compute mean absolute error for each column of two matrices.
 *  \param[in] mat1 First matrix of data
 *  \param[in] mat2 Second matrix of data
 *  \return Mean absolute error between the matrices (one value for each column)
 */
VectorXd meanAbsoluteErrorPerOutputDimension(const MatrixXd& mat1, const MatrixXd& mat2)
{
  MatrixXd abs_error = (mat1.array()-mat2.array()).abs();
  VectorXd mean_abs_error_per_output_dim = abs_error.colwise().mean();

  cout << fixed << setprecision(5);
  cout << "         Mean absolute error ";
  if (mean_abs_error_per_output_dim.size()>1) cout << " (per dimension)";
  cout << ": " << mean_abs_error_per_output_dim.transpose();
  cout << "   \t(range of target data is " << mat1.colwise().maxCoeff().array()-mat1.colwise().minCoeff().array() << ")" << endl;

  return mean_abs_error_per_output_dim;
}

int main(int n_args, char** args)
{
  // First argument may be optional directory to write data to
  string directory;
  if (n_args>1)
    directory = string(args[1]);

  vector<string> fa_names;
  if (n_args>2)
  {
    for (int aa=2; aa<n_args; aa++)
      fa_names.push_back(string(args[aa]));
  }
  else
  {
    fa_names.push_back("LWR");
    fa_names.push_back("RRRFF");
    fa_names.push_back("LWPR");
    fa_names.push_back("GMR");
  }

  for (int n_input_dims=1; n_input_dims<=2; n_input_dims++)
  {

    // Generate training data
    VectorXi n_samples_per_dim = VectorXi::Constant(1,30); // 25
    if (n_input_dims==2)
      n_samples_per_dim = VectorXi::Constant(2,10); // 2,25

    MatrixXd inputs, targets, outputs;
    targetFunction(n_samples_per_dim,inputs,targets);
    // Add some noise
    //targets = targets + 0.1*VectorXd::Random(targets.rows(),targets.cols());

    for (unsigned int i_name=0; i_name<fa_names.size(); i_name++)
    {

      FunctionApproximator* cur_fa = getFunctionApproximatorByName(fa_names[i_name],n_input_dims);
      if (cur_fa==NULL)
        continue;

      string save_directory;
      if (!directory.empty())
        save_directory = directory+"/"+fa_names[i_name]+"_"+(n_input_dims==1?"1D":"2D");

      bool overwrite = true;
      cout << "Training " << cur_fa->getName() << " on " << n_input_dims << "D data...\t";
      cur_fa->train(inputs,targets,save_directory,overwrite);

      // Do predictions and compute mean absolute error
      outputs.resize(inputs.rows(),cur_fa->getExpectedOutputDim());
      cur_fa->predict(inputs,outputs);

      meanAbsoluteErrorPerOutputDimension(targets,outputs);

#ifdef NDEBUG
      // Here, we time the predict function on single inputs, i.e. typical usage in a
      // real-time loop on a robot.

      // It's better to test this code with -03 instead of -ggdb. That's why its only run
      // when NDEBUG is set.

      MatrixXd input = inputs.row(0);
      MatrixXd output(input.rows(),input.cols());
      int n_calls = 1000000;
      clock_t begin = clock();
      for (int call=0; call<n_calls; call++)
      {
        cur_fa->predict(input,output);
        input(0,0) += 0.1/n_calls;
      }
      clock_t end = clock();
      double time_sec = (double)(end - begin) / static_cast<double>( CLOCKS_PER_SEC );
      cout << "  time for " << n_calls << " calls of predict: "<< time_sec;
      double time_per_call = time_sec/n_calls;
      cout << " => " << (int)(1.0/(time_per_call*1000)) << "kHz" << endl;
#endif

      delete cur_fa;

    }

  }

  return 0;
}

<commit_msg>Removed getFunctionApproximatorByName.cpp (replaced by FunctionApproxitorFactory)<commit_after>/**
 * \file demoFunctionApproximatorTraining.cpp
 * \author Freek Stulp
 * \brief Demonstrates how to train all functionapproximators with 1D and 2D data.
 *
 * \ingroup Demos
 * \ingroup FunctionApproximators
 *
 * This file is part of DmpBbo, a set of libraries and programs for the
 * black-box optimization of dynamical movement primitives.
 * Copyright (C) 2014 Freek Stulp, ENSTA-ParisTech
 *
 * DmpBbo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * DmpBbo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with DmpBbo.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <ctime>
#include <boost/filesystem.hpp>

#include "functionapproximators/FunctionApproximator.hpp"
#include "functionapproximators/MetaParametersLWR.hpp"
#include "functionapproximators/FunctionApproximatorLWR.hpp"
#include "functionapproximators/MetaParametersGMR.hpp"
#include "functionapproximators/FunctionApproximatorGMR.hpp"
#include "functionapproximators/MetaParametersRRRFF.hpp"
#include "functionapproximators/FunctionApproximatorRRRFF.hpp"
#include "functionapproximators/MetaParametersGPR.hpp"
#include "functionapproximators/FunctionApproximatorGPR.hpp"
#include "functionapproximators/MetaParametersRBFN.hpp"
#include "functionapproximators/FunctionApproximatorRBFN.hpp"
#ifdef USE_LWPR
#include "functionapproximators/MetaParametersLWPR.hpp"
#include "functionapproximators/FunctionApproximatorLWPR.hpp"
#endif // USE_LWPR

#include "targetFunction.hpp"

using namespace std;
using namespace Eigen;
using namespace DmpBbo;

FunctionApproximator* getFunctionApproximatorByName(std::string name, int input_dim)
{

  FunctionApproximator* fa = NULL;
  if (name.compare("LWR")==0)
  {
    // Locally Weighted Regression
    double intersection = 0.6;
    Eigen::VectorXi num_rfs_per_dim = Eigen::VectorXi::Constant(input_dim,9);
    if (input_dim==2) {
      num_rfs_per_dim[0] = 7;
      num_rfs_per_dim[1] = 5;
    }
    double regularization = 0.0;
    MetaParametersLWR* meta_params = new MetaParametersLWR(input_dim,num_rfs_per_dim,intersection,regularization);
    fa = new FunctionApproximatorLWR(meta_params);
  }
  else if (name.compare("GMR")==0)
  {
    // Gaussian Mixture Regression
    int number_of_gaussians = 10;
    if (input_dim==2) number_of_gaussians = 10;
    MetaParametersGMR* meta_params = new MetaParametersGMR(input_dim,number_of_gaussians);
    fa = new FunctionApproximatorGMR(meta_params);
  }
  else if (name.compare("RRRFF")==0)
  {
    // RRRFF
    int number_of_basis_functions=18;
    if (input_dim==2) number_of_basis_functions = 100;
    double regularization=0.2;
    double gamma=5;
    MetaParametersRRRFF* meta_params = new MetaParametersRRRFF(input_dim,number_of_basis_functions,regularization,gamma);
    fa = new FunctionApproximatorRRRFF(meta_params);
  }
  else if (name.compare("RBFN")==0)
  {
    // Radial Basis Function Network
    double intersection = 0.7;
    int n_rfs = 9;
    if (input_dim==2) n_rfs = 5;
    Eigen::VectorXi num_rfs_per_dim = Eigen::VectorXi::Constant(input_dim,n_rfs);
    double regularization = 0.0;
    MetaParametersRBFN* meta_params = new MetaParametersRBFN(input_dim,num_rfs_per_dim,intersection,regularization);
    fa = new FunctionApproximatorRBFN(meta_params);
  }
  else if (name.compare("GPR")==0)
  {
    // Gaussian Process Regression
    double maximum_covariance = 1.1*1.1;
    double length = 0.1;
    if (input_dim==2)
    {
      maximum_covariance = 0.1*0.1;
      length = 0.2;
    }
    MetaParametersGPR* meta_params = new MetaParametersGPR(input_dim,maximum_covariance,length);
    fa = new FunctionApproximatorGPR(meta_params);
  }
  else if (name.compare("LWPR")==0)
  {
    // Locally Weighted Projection Regression
#ifdef USE_LWPR
    double   w_gen=0.2;
    double   w_prune=0.8;
    bool     update_D=true;
    double   init_alpha=0.1;
    double   penalty=0.005;
    Eigen::VectorXd init_D=Eigen::VectorXd::Constant(input_dim,200);
    MetaParametersLWPR* meta_params = new MetaParametersLWPR(input_dim,init_D,w_gen,w_prune,update_D,init_alpha,penalty);
    fa = new FunctionApproximatorLWPR(dynamic_cast<MetaParametersLWPR*>(meta_params));
#else
    std::cerr << __FILE__ << ":" << __LINE__ << ":";
    std::cerr << "Sorry, LWPR is not available. Is it installed? Returning NULL." << std::endl;
    return NULL;
#endif // USE_LWPR
  }

  if (fa==NULL)
  {
    std::cerr << __FILE__ << ":" << __LINE__ << ":";
    std::cerr << "Function approximator with name '" << name << "' is unknown. Returning NULL." << std::endl;
  }

  return fa;
}

/** Compute mean absolute error for each column of two matrices.
 *  \param[in] mat1 First matrix of data
 *  \param[in] mat2 Second matrix of data
 *  \return Mean absolute error between the matrices (one value for each column)
 */
VectorXd meanAbsoluteErrorPerOutputDimension(const MatrixXd& mat1, const MatrixXd& mat2)
{
  MatrixXd abs_error = (mat1.array()-mat2.array()).abs();
  VectorXd mean_abs_error_per_output_dim = abs_error.colwise().mean();

  cout << fixed << setprecision(5);
  cout << "         Mean absolute error ";
  if (mean_abs_error_per_output_dim.size()>1) cout << " (per dimension)";
  cout << ": " << mean_abs_error_per_output_dim.transpose();
  cout << "   \t(range of target data is " << mat1.colwise().maxCoeff().array()-mat1.colwise().minCoeff().array() << ")" << endl;

  return mean_abs_error_per_output_dim;
}

int main(int n_args, char** args)
{
  // First argument may be optional directory to write data to
  string directory;
  if (n_args>1)
    directory = string(args[1]);

  vector<string> fa_names;
  if (n_args>2)
  {
    for (int aa=2; aa<n_args; aa++)
      fa_names.push_back(string(args[aa]));
  }
  else
  {
    fa_names.push_back("LWR");
    fa_names.push_back("RRRFF");
    fa_names.push_back("LWPR");
    fa_names.push_back("GMR");
  }

  for (int n_input_dims=1; n_input_dims<=2; n_input_dims++)
  {

    // Generate training data
    VectorXi n_samples_per_dim = VectorXi::Constant(1,30); // 25
    if (n_input_dims==2)
      n_samples_per_dim = VectorXi::Constant(2,10); // 2,25

    MatrixXd inputs, targets, outputs;
    targetFunction(n_samples_per_dim,inputs,targets);
    // Add some noise
    //targets = targets + 0.1*VectorXd::Random(targets.rows(),targets.cols());

    for (unsigned int i_name=0; i_name<fa_names.size(); i_name++)
    {

      FunctionApproximator* cur_fa = getFunctionApproximatorByName(fa_names[i_name],n_input_dims);
      if (cur_fa==NULL)
        continue;

      string save_directory;
      if (!directory.empty())
        save_directory = directory+"/"+fa_names[i_name]+"_"+(n_input_dims==1?"1D":"2D");

      bool overwrite = true;
      cout << "Training " << cur_fa->getName() << " on " << n_input_dims << "D data...\t";
      cur_fa->train(inputs,targets,save_directory,overwrite);

      // Do predictions and compute mean absolute error
      outputs.resize(inputs.rows(),cur_fa->getExpectedOutputDim());
      cur_fa->predict(inputs,outputs);

      meanAbsoluteErrorPerOutputDimension(targets,outputs);

#ifdef NDEBUG
      // Here, we time the predict function on single inputs, i.e. typical usage in a
      // real-time loop on a robot.

      // It's better to test this code with -03 instead of -ggdb. That's why its only run
      // when NDEBUG is set.

      MatrixXd input = inputs.row(0);
      MatrixXd output(input.rows(),input.cols());
      int n_calls = 1000000;
      clock_t begin = clock();
      for (int call=0; call<n_calls; call++)
      {
        cur_fa->predict(input,output);
        input(0,0) += 0.1/n_calls;
      }
      clock_t end = clock();
      double time_sec = (double)(end - begin) / static_cast<double>( CLOCKS_PER_SEC );
      cout << "  time for " << n_calls << " calls of predict: "<< time_sec;
      double time_per_call = time_sec/n_calls;
      cout << " => " << (int)(1.0/(time_per_call*1000)) << "kHz" << endl;
#endif

      delete cur_fa;

    }

  }

  return 0;
}

<|endoftext|>


<commit_before>
#include <QtTest>
#include <QObject>

#include <AST.h>
#include <ASTVisitor.h>
#include <TranslationUnit.h>
#include <CppDocument.h>
#include <LookupContext.h>
#include <Symbols.h>
#include <Overview.h>

CPLUSPLUS_USE_NAMESPACE

class ClassSymbols: protected ASTVisitor,
    public QMap<ClassSpecifierAST *, Class *>
{
public:
    ClassSymbols(Control *control)
        : ASTVisitor(control)
    { }

    void operator()(AST *ast)
    { accept(ast); }

protected:
    virtual bool visit(ClassSpecifierAST *ast)
    {
        Class *classSymbol = ast->class_symbol;
        Q_ASSERT(classSymbol != 0);

        insert(ast, classSymbol);

        return true;
    }
};

class tst_Lookup: public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void base_class_defined_1();
};

void tst_Lookup::base_class_defined_1()
{
    Overview overview;

    const QByteArray source = "\n"
        "class base {};\n"
        "class derived: public base {};\n";

    Document::Ptr doc = Document::create("base_class_defined_1");
    doc->setSource(source);
    doc->parse();
    doc->check();

    QVERIFY(doc->diagnosticMessages().isEmpty());
    QCOMPARE(doc->globalSymbolCount(), 2U);

    Snapshot snapshot;
    snapshot.insert(doc->fileName(), doc);

    Document::Ptr emptyDoc = Document::create("empty");

    Class *baseClass = doc->globalSymbolAt(0)->asClass();
    QVERIFY(baseClass);

    Class *derivedClass = doc->globalSymbolAt(1)->asClass();
    QVERIFY(derivedClass);

    LookupContext ctx(derivedClass, emptyDoc, doc, snapshot);

    const QList<Symbol *> candidates =
        ctx.resolveClass(derivedClass->baseClassAt(0)->name());

    QCOMPARE(candidates.size(), 1);
    QCOMPARE(candidates.at(0), baseClass);

    TranslationUnit *unit = doc->translationUnit();
    QVERIFY(unit != 0);

    TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
    QVERIFY(ast != 0);

    ClassSymbols classSymbols(doc->control());
    classSymbols(ast);

    QCOMPARE(classSymbols.size(), 2);
}

QTEST_APPLESS_MAIN(tst_Lookup)
#include "tst_lookup.moc"
<commit_msg>More testing.<commit_after>
#include <QtTest>
#include <QObject>

#include <AST.h>
#include <ASTVisitor.h>
#include <TranslationUnit.h>
#include <CppDocument.h>
#include <LookupContext.h>
#include <Symbols.h>
#include <Overview.h>

CPLUSPLUS_USE_NAMESPACE

template <template <typename, typename> class _Map, typename _T1, typename _T2>
_Map<_T2, _T1> invert(const _Map<_T1, _T2> &m)
{
    _Map<_T2, _T1> i;
    typename _Map<_T1, _T2>::const_iterator it = m.constBegin();
    for (; it != m.constEnd(); ++it) {
        i.insertMulti(it.value(), it.key());
    }
    return i;
}

class ClassSymbols: protected ASTVisitor,
    public QMap<ClassSpecifierAST *, Class *>
{
public:
    ClassSymbols(Control *control)
        : ASTVisitor(control)
    { }

    QMap<ClassSpecifierAST *, Class *> asMap() const
    { return *this; }

    void operator()(AST *ast)
    { accept(ast); }

protected:
    virtual bool visit(ClassSpecifierAST *ast)
    {
        Class *classSymbol = ast->class_symbol;
        Q_ASSERT(classSymbol != 0);

        insert(ast, classSymbol);

        return true;
    }
};

class tst_Lookup: public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void base_class_defined_1();
};

void tst_Lookup::base_class_defined_1()
{
    Overview overview;

    const QByteArray source = "\n"
        "class base {};\n"
        "class derived: public base {};\n";

    Document::Ptr doc = Document::create("base_class_defined_1");
    doc->setSource(source);
    doc->parse();
    doc->check();

    QVERIFY(doc->diagnosticMessages().isEmpty());
    QCOMPARE(doc->globalSymbolCount(), 2U);

    Snapshot snapshot;
    snapshot.insert(doc->fileName(), doc);

    Document::Ptr emptyDoc = Document::create("<empty>");

    Class *baseClass = doc->globalSymbolAt(0)->asClass();
    QVERIFY(baseClass);

    Class *derivedClass = doc->globalSymbolAt(1)->asClass();
    QVERIFY(derivedClass);

    LookupContext ctx(derivedClass, emptyDoc, doc, snapshot);

    const QList<Symbol *> candidates =
        ctx.resolveClass(derivedClass->baseClassAt(0)->name());

    QCOMPARE(candidates.size(), 1);
    QCOMPARE(candidates.at(0), baseClass);

    TranslationUnit *unit = doc->translationUnit();
    QVERIFY(unit != 0);

    TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
    QVERIFY(ast != 0);

    ClassSymbols classSymbols(doc->control());
    classSymbols(ast);

    QCOMPARE(classSymbols.size(), 2);

    const QMap<Class *, ClassSpecifierAST *> classToAST =
            invert(classSymbols.asMap());

    QVERIFY(classToAST.value(baseClass) != 0);
    QVERIFY(classToAST.value(derivedClass) != 0);
}

QTEST_APPLESS_MAIN(tst_Lookup)
#include "tst_lookup.moc"
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtSystems module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include "qdeviceinfo.h"

QT_USE_NAMESPACE

class tst_QDeviceInfo : public QObject
{
    Q_OBJECT

private slots:
    void tst_imei();
    void tst_lockTypes();
};

void tst_QDeviceInfo::tst_imei()
{
    QDeviceInfo deviceInfo;

    int imeiCount = deviceInfo.imeiCount();
    QVERIFY(imeiCount >= -1);

    QVERIFY(deviceInfo.imei(-1).isEmpty());
    QVERIFY(deviceInfo.imei(imeiCount).isEmpty());

    QRegExp imeiPattern("(\\d{0,0}|\\d{15,15})");
    for (int i = 0; i < imeiCount; ++i)
        QVERIFY(imeiPattern.exactMatch(deviceInfo.imei(i)));
}

void tst_QDeviceInfo::tst_lockTypes()
{
    QDeviceInfo deviceInfo;
    QDeviceInfo::LockTypeFlags enabledLocks = deviceInfo.enabledLocks();
    QDeviceInfo::LockTypeFlags activeLocks = deviceInfo.activatedLocks();
    QVERIFY((activeLocks & enabledLocks) == activeLocks);
    QVERIFY((activeLocks | enabledLocks) == enabledLocks);
}

QTEST_MAIN(tst_QDeviceInfo)
#include "tst_qdeviceinfo.moc"
<commit_msg>added unittests<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtSystems module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include "qdeviceinfo.h"

QT_USE_NAMESPACE

class tst_QDeviceInfo : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void cleanupTestCase();

    void tst_imei();
    void tst_lockTypes();
    void tst_version();
    void tst_manufacturer();
    void tst_model();
    void tst_productName();
    void tst_uniqueDeviceID();
    void tst_hasFeature();
    void tst_thermalState();

private:
    QDeviceInfo *deviceInfo;

};

void tst_QDeviceInfo::initTestCase()
{
    deviceInfo = new QDeviceInfo();
}

void tst_QDeviceInfo::cleanupTestCase()
{
    delete deviceInfo;
}

void tst_QDeviceInfo::tst_imei()
{
    int imeiCount = deviceInfo->imeiCount();
    QVERIFY(imeiCount >= -1);

    QVERIFY(deviceInfo->imei(-1).isEmpty());
    QVERIFY(deviceInfo->imei(imeiCount).isEmpty());

    QRegExp imeiPattern("(\\d{0,0}|\\d{15,15})");
    for (int i = 0; i < imeiCount; ++i)
        QVERIFY(imeiPattern.exactMatch(deviceInfo->imei(i)));
}

void tst_QDeviceInfo::tst_lockTypes()
{
    QDeviceInfo::LockTypeFlags enabledLocks = deviceInfo->enabledLocks();
    QDeviceInfo::LockTypeFlags activeLocks = deviceInfo->activatedLocks();
    QVERIFY((activeLocks & enabledLocks) == activeLocks);
    QVERIFY((activeLocks | enabledLocks) == enabledLocks);
}

void tst_QDeviceInfo::tst_version()
{
    QRegExp osversion(QString::fromAscii("(\\d+(\\.\\d+)*)?"));
    QVERIFY(osversion.exactMatch(deviceInfo->version(QDeviceInfo::Os)));

    QRegExp firmwareversion(QString::fromAscii(".*"));
    QVERIFY(firmwareversion.exactMatch(deviceInfo->version(QDeviceInfo::Firmware)));
}

void tst_QDeviceInfo::tst_manufacturer()
{
    QRegExp manufacturer(".*");
    QVERIFY(manufacturer.exactMatch(deviceInfo->manufacturer()));
}

void tst_QDeviceInfo::tst_model()
{
    QRegExp model(".*");
    QVERIFY(model.exactMatch(deviceInfo->model()));
}

void tst_QDeviceInfo::tst_productName()
{
    QRegExp productName(".*");
    QVERIFY(productName.exactMatch(deviceInfo->productName()));
}

void tst_QDeviceInfo::tst_uniqueDeviceID()
{
    QRegExp uniqueId("\\d*");
    QVERIFY(uniqueId.exactMatch(deviceInfo->uniqueDeviceID()));
}

void tst_QDeviceInfo::tst_hasFeature()
{
    QList<QDeviceInfo::Feature> featureList;
    featureList << QDeviceInfo::Bluetooth
                << QDeviceInfo::Camera
                << QDeviceInfo::FmRadio
                << QDeviceInfo::FmTransmitter
                << QDeviceInfo::Haptics
                << QDeviceInfo::Infrared
                << QDeviceInfo::Led
                << QDeviceInfo::MemoryCard
                << QDeviceInfo::Positioning
                << QDeviceInfo::Sim
                << QDeviceInfo::Usb
                << QDeviceInfo::Vibration
                << QDeviceInfo::VideoOut
                << QDeviceInfo::Wlan;

    foreach (QDeviceInfo::Feature feature, featureList) {
        bool isPresent = deviceInfo->hasFeature(feature);
        QVERIFY(isPresent == true || isPresent == false);
    }
}

void tst_QDeviceInfo::tst_thermalState()
{
    QDeviceInfo::ThermalState state = deviceInfo->thermalState();
    QVERIFY(state == QDeviceInfo::UnknownThermal ||
            state == QDeviceInfo::NormalThermal ||
            state == QDeviceInfo::WarningThermal ||
            state == QDeviceInfo::AlertThermal ||
            state == QDeviceInfo::ErrorThermal);
}

QTEST_MAIN(tst_QDeviceInfo)
#include "tst_qdeviceinfo.moc"
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright © 2019 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

#include <css/ostream.h++>

#include <css/grammar/radial_gradient.h++>

#include "css/test_rule.h++"

#include <boost/fusion/adapted/std_pair.hpp>

#include <utility>

namespace
{
  const auto circle_default = "circle";
  const auto circle_radius = "circle 5 pt";
  const auto circle_extent = "circle closest-corner";

  const auto ellipse_default = "ellipse";
  const auto ellipse_radii = "ellipse 3cm 5rem";
  const auto ellipse_extent = "ellipse farthest-side";

  const auto non_repeating_radial_gradient = "radial-gradient(ellipse at top, red, blue)";
  const auto repeating_radial_gradient = "repeating-radial-gradient(at top right, yellow 30%, green 100vw, black)";
  const auto default_shape_position_radial_gradient = "radial-gradient(#FF00FF, rgb(255,0,0))";

  const auto leading_comma = "radial-gradient(, red)";
  const auto missing_comma = "radial-gradient(at top red)";
}

int main()
{
  using skui::test::check_rule_failure;
  using skui::test::check_rule_success;

  using skui::css::grammar::circle;
  check_rule_success(circle, circle_default,
                     skui::css::radial_gradient::circle{skui::css::radial_gradient::extent::farthest_corner});
  check_rule_success(circle, circle_radius,
                     skui::css::radial_gradient::circle{skui::css::length{5, skui::css::unit::pt}});
  check_rule_success(circle, circle_extent,
                     skui::css::radial_gradient::circle{skui::css::radial_gradient::extent::closest_corner});

  using skui::css::grammar::ellipse;
  check_rule_success(ellipse, ellipse_default,
                     skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner});
  check_rule_success(ellipse, ellipse_radii,
                     skui::css::radial_gradient::ellipse{skui::graphics::size2D<skui::css::length>{{3, skui::css::unit::cm},
                                                                                {5, skui::css::unit::rem}}});
  check_rule_success(ellipse, ellipse_extent,
                     skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_side});

  using skui::css::grammar::radial_gradient;
  check_rule_success(radial_gradient, non_repeating_radial_gradient,
                     skui::css::radial_gradient{{false,
                                                 {{skui::css::colors::red, {}},
                                                  {skui::css::colors::blue, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::top});

  check_rule_success(radial_gradient, repeating_radial_gradient,
                     skui::css::radial_gradient{{true,
                                                 {{skui::css::colors::yellow, {{30, skui::css::unit::percentage}}},
                                                  {skui::css::colors::green, {{100, skui::css::unit::vw}}},
                                                  {skui::css::colors::black, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::top_right});

  check_rule_success(radial_gradient, default_shape_position_radial_gradient,
                     skui::css::radial_gradient{{false,
                                                 {{skui::css::colors::magenta, {}},
                                                  {skui::css::colors::red, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::center});

  check_rule_failure(radial_gradient, leading_comma);
  check_rule_failure(radial_gradient, missing_comma);

  return skui::test::exit_code;
}
<commit_msg>Remove unused include.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright © 2019 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

#include <css/ostream.h++>

#include <css/grammar/radial_gradient.h++>

#include "css/test_rule.h++"

#include <utility>

namespace
{
  const auto circle_default = "circle";
  const auto circle_radius = "circle 5 pt";
  const auto circle_extent = "circle closest-corner";

  const auto ellipse_default = "ellipse";
  const auto ellipse_radii = "ellipse 3cm 5rem";
  const auto ellipse_extent = "ellipse farthest-side";

  const auto non_repeating_radial_gradient = "radial-gradient(ellipse at top, red, blue)";
  const auto repeating_radial_gradient = "repeating-radial-gradient(at top right, yellow 30%, green 100vw, black)";
  const auto default_shape_position_radial_gradient = "radial-gradient(#FF00FF, rgb(255,0,0))";

  const auto leading_comma = "radial-gradient(, red)";
  const auto missing_comma = "radial-gradient(at top red)";
}

int main()
{
  using skui::test::check_rule_failure;
  using skui::test::check_rule_success;

  using skui::css::grammar::circle;
  check_rule_success(circle, circle_default,
                     skui::css::radial_gradient::circle{skui::css::radial_gradient::extent::farthest_corner});
  check_rule_success(circle, circle_radius,
                     skui::css::radial_gradient::circle{skui::css::length{5, skui::css::unit::pt}});
  check_rule_success(circle, circle_extent,
                     skui::css::radial_gradient::circle{skui::css::radial_gradient::extent::closest_corner});

  using skui::css::grammar::ellipse;
  check_rule_success(ellipse, ellipse_default,
                     skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner});
  check_rule_success(ellipse, ellipse_radii,
                     skui::css::radial_gradient::ellipse{skui::graphics::size2D<skui::css::length>{{3, skui::css::unit::cm},
                                                                                {5, skui::css::unit::rem}}});
  check_rule_success(ellipse, ellipse_extent,
                     skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_side});

  using skui::css::grammar::radial_gradient;
  check_rule_success(radial_gradient, non_repeating_radial_gradient,
                     skui::css::radial_gradient{{false,
                                                 {{skui::css::colors::red, {}},
                                                  {skui::css::colors::blue, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::top});

  check_rule_success(radial_gradient, repeating_radial_gradient,
                     skui::css::radial_gradient{{true,
                                                 {{skui::css::colors::yellow, {{30, skui::css::unit::percentage}}},
                                                  {skui::css::colors::green, {{100, skui::css::unit::vw}}},
                                                  {skui::css::colors::black, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::top_right});

  check_rule_success(radial_gradient, default_shape_position_radial_gradient,
                     skui::css::radial_gradient{{false,
                                                 {{skui::css::colors::magenta, {}},
                                                  {skui::css::colors::red, {}}}},
                                                skui::css::radial_gradient::ellipse{skui::css::radial_gradient::extent::farthest_corner},
                                                skui::css::center});

  check_rule_failure(radial_gradient, leading_comma);
  check_rule_failure(radial_gradient, missing_comma);

  return skui::test::exit_code;
}
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "llvm/ADT/STLExtras.h"
#include "mlir/IR/SymbolTable.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassRegistry.h"  // from @llvm-project
#include "mlir/Support/LLVM.h"  // from @llvm-project
#include "mlir/Support/LogicalResult.h"  // from @llvm-project
#include "mlir/Transforms/Utils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"

namespace mlir {
namespace TF {

namespace {

// Clones FuncOp's until they have a single use only (or no users).
//
// The tf-shape-inference pass doesn't support functions that have more than
// a single use. But some real code from frontends does end up creating code
// like that. For example, the same LSTM cell function or loop body function
// will be reused.
//
// This pass clones functions as needed to establish the invariant that all
// functions have a single use. This can in principle cause exponential code
// size bloat, and should in general be guided by a proper cost model.
//
// There are two factors which should be considered by a principled replacement
// to this pass:
//
// 1. TF currently relies on "sufficiently good shape inference" for
// correctness so for now the cost of doing this seems acceptable since
// pathological cases haven't hit us yet.
//
// 2. Cloning functions can help by allowing code to be specialized (much as
// inlining does). In fact, tf-shape-inference attempts to do specialization
// of callees which is difficult if callees have multiple uses.
class GuaranteeAllFuncsOneUse
    : public PassWrapper<GuaranteeAllFuncsOneUse, OperationPass<ModuleOp>> {
 public:
  void runOnOperation() override {
    if (failed(Run())) {
      signalPassFailure();
    }
  }

  LogicalResult Run() {
    auto module = getOperation();

    // Overall strategy:
    // Fixed point iteration, iteratively applying a rule that clones
    // any FuncOp with more than one use to eliminate its uses.
    SymbolTableCollection symbol_table_collection;
    SymbolTable &symbol_table = symbol_table_collection.getSymbolTable(module);
    bool made_changes = false;

    // This value needs to be low enough to actually stop compilation in a
    // reasonable time, but not too low that it blocks real programs.
    // This number was chosen semi-randomly.
    const int k_max_clones = 1000;
    int num_clones = 0;
    do {
      SymbolUserMap symbol_users(symbol_table_collection, module);

      made_changes = false;
      for (auto func : llvm::make_early_inc_range(module.getOps<FuncOp>())) {
        ArrayRef<Operation *> users = symbol_users.getUsers(func);
        if (users.size() <= 1) {
          continue;
        }

        // At this point, we know we are going to change the module.
        made_changes = true;
        for (Operation *user : users.drop_front()) {
          if (num_clones++ > k_max_clones) {
            return func.emitError()
                   << "reached cloning limit (likely recursive call graph or "
                      "repeated diamond-like call structure "
                      "or just very large program)";
          }
          FuncOp new_func = func.clone();
          symbol_table.insert(new_func);
          new_func.setPrivate();
          if (failed(SymbolTable::replaceAllSymbolUses(func, new_func.getName(),
                                                       user))) {
            return func.emitError() << "could not replace symbol use";
          }
        }
      }
    } while (made_changes);

    return success();
  }
};

}  // namespace

std::unique_ptr<OperationPass<ModuleOp>> CreateGuaranteeAllFuncsOneUsePass() {
  return std::make_unique<GuaranteeAllFuncsOneUse>();
}

static PassRegistration<GuaranteeAllFuncsOneUse> pass(
    "tf-guarantee-all-funcs-one-use",
    "Guarantee all FuncOp's have only a single use.");

}  // namespace TF

}  // namespace mlir
<commit_msg>Bump kMaxClones limit up<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "llvm/ADT/STLExtras.h"
#include "mlir/IR/SymbolTable.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassRegistry.h"  // from @llvm-project
#include "mlir/Support/LLVM.h"  // from @llvm-project
#include "mlir/Support/LogicalResult.h"  // from @llvm-project
#include "mlir/Transforms/Utils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"

namespace mlir {
namespace TF {

namespace {

// Clones FuncOp's until they have a single use only (or no users).
//
// The tf-shape-inference pass doesn't support functions that have more than
// a single use. But some real code from frontends does end up creating code
// like that. For example, the same LSTM cell function or loop body function
// will be reused.
//
// This pass clones functions as needed to establish the invariant that all
// functions have a single use. This can in principle cause exponential code
// size bloat, and should in general be guided by a proper cost model.
//
// There are two factors which should be considered by a principled replacement
// to this pass:
//
// 1. TF currently relies on "sufficiently good shape inference" for
// correctness so for now the cost of doing this seems acceptable since
// pathological cases haven't hit us yet.
//
// 2. Cloning functions can help by allowing code to be specialized (much as
// inlining does). In fact, tf-shape-inference attempts to do specialization
// of callees which is difficult if callees have multiple uses.
class GuaranteeAllFuncsOneUse
    : public PassWrapper<GuaranteeAllFuncsOneUse, OperationPass<ModuleOp>> {
 public:
  void runOnOperation() override {
    if (failed(Run())) {
      signalPassFailure();
    }
  }

  LogicalResult Run() {
    auto module = getOperation();

    // Overall strategy:
    // Fixed point iteration, iteratively applying a rule that clones
    // any FuncOp with more than one use to eliminate its uses.
    SymbolTableCollection symbol_table_collection;
    SymbolTable &symbol_table = symbol_table_collection.getSymbolTable(module);
    bool made_changes = false;

    // This value needs to be low enough to actually stop compilation in a
    // reasonable time, but not too low that it blocks real programs.
    // This number was chosen semi-randomly.
    // TODO(jpienaar): Switch to a more context aware heuristic.
    const int kMaxClones = 10000;
    int num_clones = 0;
    do {
      SymbolUserMap symbol_users(symbol_table_collection, module);

      made_changes = false;
      for (auto func : llvm::make_early_inc_range(module.getOps<FuncOp>())) {
        ArrayRef<Operation *> users = symbol_users.getUsers(func);
        if (users.size() <= 1) {
          continue;
        }

        // At this point, we know we are going to change the module.
        made_changes = true;
        for (Operation *user : users.drop_front()) {
          if (num_clones++ > kMaxClones) {
            return func.emitError()
                   << "reached cloning limit (likely recursive call graph or "
                      "repeated diamond-like call structure "
                      "or just very large program)";
          }
          FuncOp new_func = func.clone();
          symbol_table.insert(new_func);
          new_func.setPrivate();
          if (failed(SymbolTable::replaceAllSymbolUses(func, new_func.getName(),
                                                       user))) {
            return func.emitError() << "could not replace symbol use";
          }
        }
      }
    } while (made_changes);

    return success();
  }
};

}  // namespace

std::unique_ptr<OperationPass<ModuleOp>> CreateGuaranteeAllFuncsOneUsePass() {
  return std::make_unique<GuaranteeAllFuncsOneUse>();
}

static PassRegistration<GuaranteeAllFuncsOneUse> pass(
    "tf-guarantee-all-funcs-one-use",
    "Guarantee all FuncOp's have only a single use.");

}  // namespace TF

}  // namespace mlir
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// <vector>

// template <class InputIter> vector(InputIter first, InputIter last);

#include <vector>
#include <cassert>
#include <cstddef>

#include "test_macros.h"
#include "test_iterators.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"
#if TEST_STD_VER >= 11
#include "emplace_constructible.h"
#include "container_test_types.h"
#endif

template <class C, class Iterator>
void test(Iterator first, Iterator last) {
  C c(first, last);
  LIBCPP_ASSERT(c.__invariants());
  assert(c.size() == static_cast<std::size_t>(std::distance(first, last)));
  LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
  for (typename C::const_iterator i = c.cbegin(), e = c.cend(); i != e;
       ++i, ++first)
    assert(*i == *first);
}

static void basic_test_cases() {
  int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0};
  int* an = a + sizeof(a) / sizeof(a[0]);
  test<std::vector<int> >(input_iterator<const int*>(a),
                          input_iterator<const int*>(an));
  test<std::vector<int> >(forward_iterator<const int*>(a),
                          forward_iterator<const int*>(an));
  test<std::vector<int> >(bidirectional_iterator<const int*>(a),
                          bidirectional_iterator<const int*>(an));
  test<std::vector<int> >(random_access_iterator<const int*>(a),
                          random_access_iterator<const int*>(an));
  test<std::vector<int> >(a, an);

  test<std::vector<int, limited_allocator<int, 63> > >(
      input_iterator<const int*>(a), input_iterator<const int*>(an));
  // Add 1 for implementations that dynamically allocate a container proxy.
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      forward_iterator<const int*>(a), forward_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      bidirectional_iterator<const int*>(a),
      bidirectional_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      random_access_iterator<const int*>(a),
      random_access_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(a, an);
#if TEST_STD_VER >= 11
  test<std::vector<int, min_allocator<int> > >(input_iterator<const int*>(a),
                                               input_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      forward_iterator<const int*>(a), forward_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      bidirectional_iterator<const int*>(a),
      bidirectional_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      random_access_iterator<const int*>(a),
      random_access_iterator<const int*>(an));
  test<std::vector<int> >(a, an);
#endif
}

void emplaceable_concept_tests() {
#if TEST_STD_VER >= 11
  int arr1[] = {42};
  int arr2[] = {1, 101, 42};
  {
    using T = EmplaceConstructible<int>;
    using It = forward_iterator<int*>;
    {
      std::vector<T> v(It(arr1), It(std::end(arr1)));
      assert(v[0].value == 42);
    }
    {
      std::vector<T> v(It(arr2), It(std::end(arr2)));
      assert(v[0].value == 1);
      assert(v[1].value == 101);
      assert(v[2].value == 42);
    }
  }
  {
    using T = EmplaceConstructibleAndMoveInsertable<int>;
    using It = input_iterator<int*>;
    {
      std::vector<T> v(It(arr1), It(std::end(arr1)));
      assert(v[0].copied == 0);
      assert(v[0].value == 42);
    }
    {
      std::vector<T> v(It(arr2), It(std::end(arr2)));
      //assert(v[0].copied == 0);
      assert(v[0].value == 1);
      //assert(v[1].copied == 0);
      assert(v[1].value == 101);
      assert(v[2].copied == 0);
      assert(v[2].value == 42);
    }
  }
#endif
}

void test_ctor_under_alloc() {
#if TEST_STD_VER >= 11
  int arr1[] = {42};
  int arr2[] = {1, 101, 42};
  {
    using C = TCT::vector<>;
    using It = forward_iterator<int*>;
    {
      ExpectConstructGuard<int&> G(1);
      C v(It(arr1), It(std::end(arr1)));
    }
    {
      ExpectConstructGuard<int&> G(3);
      C v(It(arr2), It(std::end(arr2)));
    }
  }
  {
    using C = TCT::vector<>;
    using It = input_iterator<int*>;
    {
      ExpectConstructGuard<int&> G(1);
      C v(It(arr1), It(std::end(arr1)));
    }
    {
      //ExpectConstructGuard<int&> G(3);
      //C v(It(arr2), It(std::end(arr2)), a);
    }
  }
#endif
}

// Initialize a vector with a different value type.
void test_ctor_with_different_value_type() {
  {
    // Make sure initialization is performed with each element value, not with
    // a memory blob.
    float array[3] = {0.0f, 1.0f, 2.0f};
    std::vector<int> v(array, array + 3);
    assert(v[0] == 0);
    assert(v[1] == 1);
    assert(v[2] == 2);
  }
  struct X { int x; };
  struct Y { int y; };
  struct Z : X, Y { int z; };
  {
    Z z;
    Z *array[1] = { &z };
    // Though the types Z* and Y* are very similar, initialization still cannot
    // be done with `memcpy`.
    std::vector<Y*> v(array, array + 1);
    assert(v[0] == &z);
  }
  {
    // Though the types are different, initialization can be done with `memcpy`.
    int32_t array[1] = { -1 };
    std::vector<uint32_t> v(array, array + 1);
    assert(v[0] == 4294967295);
  }
}

int main(int, char**) {
  basic_test_cases();
  emplaceable_concept_tests(); // See PR34898
  test_ctor_under_alloc();
  test_ctor_with_different_value_type();

  return 0;
}
<commit_msg>Fix a vector test to not use a local type as a template parameter. This causes a warning on C++03. NFC<commit_after>//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// <vector>

// template <class InputIter> vector(InputIter first, InputIter last);

#include <vector>
#include <cassert>
#include <cstddef>

#include "test_macros.h"
#include "test_iterators.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"
#if TEST_STD_VER >= 11
#include "emplace_constructible.h"
#include "container_test_types.h"
#endif

template <class C, class Iterator>
void test(Iterator first, Iterator last) {
  C c(first, last);
  LIBCPP_ASSERT(c.__invariants());
  assert(c.size() == static_cast<std::size_t>(std::distance(first, last)));
  LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
  for (typename C::const_iterator i = c.cbegin(), e = c.cend(); i != e;
       ++i, ++first)
    assert(*i == *first);
}

static void basic_test_cases() {
  int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0};
  int* an = a + sizeof(a) / sizeof(a[0]);
  test<std::vector<int> >(input_iterator<const int*>(a),
                          input_iterator<const int*>(an));
  test<std::vector<int> >(forward_iterator<const int*>(a),
                          forward_iterator<const int*>(an));
  test<std::vector<int> >(bidirectional_iterator<const int*>(a),
                          bidirectional_iterator<const int*>(an));
  test<std::vector<int> >(random_access_iterator<const int*>(a),
                          random_access_iterator<const int*>(an));
  test<std::vector<int> >(a, an);

  test<std::vector<int, limited_allocator<int, 63> > >(
      input_iterator<const int*>(a), input_iterator<const int*>(an));
  // Add 1 for implementations that dynamically allocate a container proxy.
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      forward_iterator<const int*>(a), forward_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      bidirectional_iterator<const int*>(a),
      bidirectional_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(
      random_access_iterator<const int*>(a),
      random_access_iterator<const int*>(an));
  test<std::vector<int, limited_allocator<int, 18 + 1> > >(a, an);
#if TEST_STD_VER >= 11
  test<std::vector<int, min_allocator<int> > >(input_iterator<const int*>(a),
                                               input_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      forward_iterator<const int*>(a), forward_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      bidirectional_iterator<const int*>(a),
      bidirectional_iterator<const int*>(an));
  test<std::vector<int, min_allocator<int> > >(
      random_access_iterator<const int*>(a),
      random_access_iterator<const int*>(an));
  test<std::vector<int> >(a, an);
#endif
}

void emplaceable_concept_tests() {
#if TEST_STD_VER >= 11
  int arr1[] = {42};
  int arr2[] = {1, 101, 42};
  {
    using T = EmplaceConstructible<int>;
    using It = forward_iterator<int*>;
    {
      std::vector<T> v(It(arr1), It(std::end(arr1)));
      assert(v[0].value == 42);
    }
    {
      std::vector<T> v(It(arr2), It(std::end(arr2)));
      assert(v[0].value == 1);
      assert(v[1].value == 101);
      assert(v[2].value == 42);
    }
  }
  {
    using T = EmplaceConstructibleAndMoveInsertable<int>;
    using It = input_iterator<int*>;
    {
      std::vector<T> v(It(arr1), It(std::end(arr1)));
      assert(v[0].copied == 0);
      assert(v[0].value == 42);
    }
    {
      std::vector<T> v(It(arr2), It(std::end(arr2)));
      //assert(v[0].copied == 0);
      assert(v[0].value == 1);
      //assert(v[1].copied == 0);
      assert(v[1].value == 101);
      assert(v[2].copied == 0);
      assert(v[2].value == 42);
    }
  }
#endif
}

void test_ctor_under_alloc() {
#if TEST_STD_VER >= 11
  int arr1[] = {42};
  int arr2[] = {1, 101, 42};
  {
    using C = TCT::vector<>;
    using It = forward_iterator<int*>;
    {
      ExpectConstructGuard<int&> G(1);
      C v(It(arr1), It(std::end(arr1)));
    }
    {
      ExpectConstructGuard<int&> G(3);
      C v(It(arr2), It(std::end(arr2)));
    }
  }
  {
    using C = TCT::vector<>;
    using It = input_iterator<int*>;
    {
      ExpectConstructGuard<int&> G(1);
      C v(It(arr1), It(std::end(arr1)));
    }
    {
      //ExpectConstructGuard<int&> G(3);
      //C v(It(arr2), It(std::end(arr2)), a);
    }
  }
#endif
}

// In C++03, you can't instantiate a template with a local type.
struct B1 { int x; };
struct B2 { int y; };
struct Der : B1, B2 { int z; };

// Initialize a vector with a different value type.
void test_ctor_with_different_value_type() {
  {
    // Make sure initialization is performed with each element value, not with
    // a memory blob.
    float array[3] = {0.0f, 1.0f, 2.0f};
    std::vector<int> v(array, array + 3);
    assert(v[0] == 0);
    assert(v[1] == 1);
    assert(v[2] == 2);
  }
  {
    Der z;
    Der *array[1] = { &z };
    // Though the types Der* and B2* are very similar, initialization still cannot
    // be done with `memcpy`.
    std::vector<B2*> v(array, array + 1);
    assert(v[0] == &z);
  }
  {
    // Though the types are different, initialization can be done with `memcpy`.
    int32_t array[1] = { -1 };
    std::vector<uint32_t> v(array, array + 1);
    assert(v[0] == 4294967295);
  }
}

int main(int, char**) {
  basic_test_cases();
  emplaceable_concept_tests(); // See PR34898
  test_ctor_under_alloc();
  test_ctor_with_different_value_type();

  return 0;
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 | FileCheck %s

// CHECK-DAG: @PR22043 = local_unnamed_addr global i32 0, align 4
typedef _Atomic(int) AtomicInt;
AtomicInt PR22043 = AtomicInt();

// CHECK-DAG: @_ZN7PR180978constant1aE = local_unnamed_addr global { i16, i8 } { i16 1, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1bE = local_unnamed_addr global { i16, i8 } { i16 2, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1cE = local_unnamed_addr global { i16, i8 } { i16 3, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1yE = local_unnamed_addr global { { i16, i8 }, i32 } { { i16, i8 } { i16 4, i8 6 }, i32 5 }, align 4

struct A {
  _Atomic(int) i;
  A(int j);
  void v(int j);
};
// Storing to atomic values should be atomic
// CHECK: store atomic i32
void A::v(int j) { i = j; }
// Initialising atomic values should not be atomic
// CHECK-NOT: store atomic
A::A(int j) : i(j) {}

struct B {
  int i;
  B(int x) : i(x) {}
};

_Atomic(B) b;

// CHECK-LABEL: define void @_Z11atomic_initR1Ai
void atomic_init(A& a, int i) {
  // CHECK-NOT: atomic
  // CHECK: tail call void @_ZN1BC1Ei
  __c11_atomic_init(&b, B(i));
  // CHECK-NEXT: ret void
}

// CHECK-LABEL: define void @_Z16atomic_init_boolPU7_Atomicbb
void atomic_init_bool(_Atomic(bool) *ab, bool b) {
  // CHECK-NOT: atomic
  // CHECK: {{zext i1.*to i8}}
  // CHECK-NEXT: store i8
  __c11_atomic_init(ab, b);
  // CHECK-NEXT: ret void
}

struct AtomicBoolMember {
  _Atomic(bool) ab;
  AtomicBoolMember(bool b);
};

// CHECK-LABEL: define void @_ZN16AtomicBoolMemberC2Eb
// CHECK: {{zext i1.*to i8}}
// CHECK-NEXT: store i8
// CHECK-NEXT: ret void
AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { }

namespace PR18097 {
  namespace dynamic {
    struct X {
      X(int);
      short n;
      char c;
    };

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1aE, i32 1)
    _Atomic(X) a = X(1);

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1bE, i32 2)
    _Atomic(X) b(X(2));

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1cE, i32 3)
    _Atomic(X) c{X(3)};

    struct Y {
      _Atomic(X) a;
      _Atomic(int) b;
    };
    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 0), i32 4)
    // CHECK: store i32 5, i32* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 1)
    Y y = { X(4), 5 };
  }

  // CHECKs at top of file.
  namespace constant {
    struct X {
      constexpr X(int n) : n(n) {}
      short n;
      char c = 6;
    };
    _Atomic(X) a = X(1);
    _Atomic(X) b(X(2));
    _Atomic(X) c{X(3)};

    struct Y {
      _Atomic(X) a;
      _Atomic(int) b;
    };
    Y y = { X(4), 5 };
  }
}
<commit_msg>Update test to account for r276604<commit_after>// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 -std=c++11 | FileCheck %s

// CHECK-DAG: @PR22043 = local_unnamed_addr global i32 0, align 4
typedef _Atomic(int) AtomicInt;
AtomicInt PR22043 = AtomicInt();

// CHECK-DAG: @_ZN7PR180978constant1aE = local_unnamed_addr global { i16, i8 } { i16 1, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1bE = local_unnamed_addr global { i16, i8 } { i16 2, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1cE = local_unnamed_addr global { i16, i8 } { i16 3, i8 6 }, align 4
// CHECK-DAG: @_ZN7PR180978constant1yE = local_unnamed_addr global { { i16, i8 }, i32 } { { i16, i8 } { i16 4, i8 6 }, i32 5 }, align 4

struct A {
  _Atomic(int) i;
  A(int j);
  void v(int j);
};
// Storing to atomic values should be atomic
// CHECK: store atomic i32
void A::v(int j) { i = j; }
// Initialising atomic values should not be atomic
// CHECK-NOT: store atomic
A::A(int j) : i(j) {}

struct B {
  int i;
  B(int x) : i(x) {}
};

_Atomic(B) b;

// CHECK-LABEL: define void @_Z11atomic_initR1Ai
void atomic_init(A& a, int i) {
  // CHECK-NOT: atomic
  // CHECK: tail call void @_ZN1BC1Ei
  __c11_atomic_init(&b, B(i));
  // CHECK-NEXT: ret void
}

// CHECK-LABEL: define void @_Z16atomic_init_boolPU7_Atomicbb
void atomic_init_bool(_Atomic(bool) *ab, bool b) {
  // CHECK-NOT: atomic
  // CHECK: {{zext i1.*to i8}}
  // CHECK-NEXT: store i8
  __c11_atomic_init(ab, b);
  // CHECK-NEXT: ret void
}

struct AtomicBoolMember {
  _Atomic(bool) ab;
  AtomicBoolMember(bool b);
};

// CHECK-LABEL: define void @_ZN16AtomicBoolMemberC2Eb
// CHECK: zext i1 {{.*}} to i8
// CHECK: store i8
// CHECK-NEXT: ret void
AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { }

namespace PR18097 {
  namespace dynamic {
    struct X {
      X(int);
      short n;
      char c;
    };

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1aE, i32 1)
    _Atomic(X) a = X(1);

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1bE, i32 2)
    _Atomic(X) b(X(2));

    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* nonnull @_ZN7PR180977dynamic1cE, i32 3)
    _Atomic(X) c{X(3)};

    struct Y {
      _Atomic(X) a;
      _Atomic(int) b;
    };
    // CHECK-LABEL: define {{.*}} @__cxx_global_var_init
    // CHECK: call void @_ZN7PR180977dynamic1XC1Ei({{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 0), i32 4)
    // CHECK: store i32 5, i32* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN7PR180977dynamic1yE, i32 0, i32 1)
    Y y = { X(4), 5 };
  }

  // CHECKs at top of file.
  namespace constant {
    struct X {
      constexpr X(int n) : n(n) {}
      short n;
      char c = 6;
    };
    _Atomic(X) a = X(1);
    _Atomic(X) b(X(2));
    _Atomic(X) c{X(3)};

    struct Y {
      _Atomic(X) a;
      _Atomic(int) b;
    };
    Y y = { X(4), 5 };
  }
}
<|endoftext|>