<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_CONFIG_OPTION_HPP
#define CAF_CONFIG_OPTION_HPP

#include <memory>
#include <string>
#include <vector>
#include <cstdint>
#include <cstring>
#include <functional>

#include "caf/atom.hpp"
#include "caf/error.hpp"
#include "caf/message.hpp"
#include "caf/variant.hpp"
#include "caf/config_value.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/static_visitor.hpp"

#include "caf/detail/type_traits.hpp"

namespace caf {

extern const char* type_name_visitor_tbl[];

/// Helper class to generate config readers for different input types.
class config_option {
public:
  using config_reader_sink = std::function<void (size_t, config_value&,
                                                 optional<std::ostream&>)>;

  using legal_types = detail::type_list<bool, float, double, std::string,
                                        atom_value, int8_t, uint8_t, int16_t,
                                        uint16_t, int32_t, uint32_t, int64_t,
                                        uint64_t>;

  config_option(const char* cat, const char* nm, const char* expl);

  virtual ~config_option();

  inline const char* name() const {
    return name_.c_str();
  }

  inline char short_name() const {
    return short_name_;
  }

  inline const char* category() const {
    return category_;
  }

  inline const char* explanation() const {
    return explanation_;
  }

  /// Returns the full name for this config option as "<category>.<long name>".
  std::string full_name() const;

  /// Returns the held value as string.
  virtual std::string to_string() const = 0;

  /// Returns a sink function for config readers.
  virtual config_reader_sink to_sink() = 0;

  /// Returns a CLI argument parser.
  virtual message::cli_arg to_cli_arg(bool use_caf_prefix = false) = 0;

  /// Returns a human-readable type name for the visited type.
  class type_name_visitor : public static_visitor<const char*> {
  public:
    template <class T>
    const char* operator()(const T&) const {
      static constexpr bool is_int = std::is_integral<T>::value
                                     && !std::is_same<bool, T>::value;
      static constexpr std::integral_constant<bool, is_int> tk{};
      static constexpr int index = idx<T>(tk);
      static_assert(index >= 0, "illegal type in name visitor");
      return type_name_visitor_tbl[static_cast<size_t>(index)];
    }

  private:
    template <class T>
    static constexpr int idx(std::false_type /* is_integer */) {
      return detail::tl_index_of<legal_types, T>::value;
    }

    template <class T>
    static constexpr int idx(std::true_type /* is_integer */) {
      using squashed = detail::squashed_int_t<T>;
      return detail::tl_index_of<legal_types, squashed>::value;
    }
  };

protected:
  template <class T, class U>
  static bool assign_config_value(T& x, U& y) {
    x = std::move(y);
    return true;
  }

  template <class T>
  static bool assign_config_value(T& x, int64_t& y) {
    if (y < static_cast<int64_t>(std::numeric_limits<T>::lowest())
        || y > static_cast<int64_t>(std::numeric_limits<T>::max()))
      return false;
    x = static_cast<T>(y);
    return true;
  }

  static bool assign_config_value(uint64_t& x, int64_t& y) {
    if (y < 0)
      return false;
    x = static_cast<uint64_t>(y);
    return true;
  }

  static bool assign_config_value(float& x, double& y) {
    if (y < static_cast<double>(std::numeric_limits<float>::lowest())
        || y > static_cast<double>(std::numeric_limits<float>::max()))
      return false;
    x = static_cast<float>(y);
    return true;
  }

  void report_type_error(size_t ln, config_value& x, const char* expected,
                         optional<std::ostream&> out);

private:
  const char* category_;
  std::string name_;
  const char* explanation_;
  char short_name_;
};

template <class T, bool IsInsertable = detail::can_insert_elements<T>()
                                       && !std::is_same<T, std::string>::value>
class config_option_impl : public config_option {
public:
  config_option_impl(T& ref, const char* ctg, const char* nm, const char* xp)
      : config_option(ctg, nm, xp),
        ref_(ref) {
    // nop
  }

  std::string to_string() const override {
    return deep_to_string(ref_);
  }

  message::cli_arg to_cli_arg(bool use_caf_prefix) override {
    std::string argname;
    if (use_caf_prefix)
      argname = "caf#";
    if (strcmp(category(), "global") != 0) {
      argname += category();
      argname += ".";
    }
    argname += name();
    if (short_name() != '\0') {
      argname += ',';
      argname += short_name();
    }
    return {std::move(argname), explanation(), ref_};
  }

  config_reader_sink to_sink() override {
    return [=](size_t ln, config_value& x, optional<std::ostream&> errors) {
      // the INI parser accepts all integers as int64_t
      // and all floating point numbers as doubles
      using cfg_type =
        typename std::conditional<
          std::is_integral<T>::value && !std::is_same<bool, T>::value,
          int64_t,
          typename std::conditional<
            std::is_floating_point<T>::value,
            double,
            T
            >::type
        >::type;
      if (get<cfg_type>(&x) && assign_config_value(ref_, get<cfg_type>(x)))
        return;
      type_name_visitor tnv;
      report_type_error(ln, x, tnv(ref_), errors);
    };
  }

private:
  T& ref_;
};

template <class T>
class config_option_impl<T, true> : public config_option {
public:
  using value_type = typename T::value_type;

  config_option_impl(T& ref, const char* ctg, const char* nm, const char* xp)
      : config_option(ctg, nm, xp),
        ref_(ref) {
    // nop
  }

  std::string to_string() const override {
    return deep_to_string(ref_);
  }

  message::cli_arg to_cli_arg(bool use_caf_prefix) override {
    std::string argname;
    if (use_caf_prefix)
      argname = "caf#";
    if (strcmp(category(), "global") != 0) {
      argname += category();
      argname += ".";
    }
    argname += name();
    if (short_name() != '\0') {
      argname += ',';
      argname += short_name();
    }
    return {std::move(argname), explanation(), ref_};
  }

  config_reader_sink to_sink() override {
    return [=](size_t ln, config_value& x, optional<std::ostream&> errors) {
      // the INI parser accepts all integers as int64_t
      // and all floating point numbers as doubles
      using cfg_type =
        typename std::conditional<
          std::is_integral<value_type>::value &&
                           !std::is_same<bool, value_type>::value,
          int64_t,
          typename std::conditional<
            std::is_floating_point<value_type>::value,
            double,
            value_type
            >::type
        >::type;
      value_type tmp;
      if (get<cfg_type>(&x) && assign_config_value(tmp, get<cfg_type>(x))) {
        ref_.insert(ref_.end(), std::move(tmp));
        return;
      }
      type_name_visitor tnv;
      report_type_error(ln, x, tnv(tmp), errors);
    };
  }

private:
  T& ref_;
};

template <class T>
std::unique_ptr<config_option>
make_config_option(T& storage, const char* category,
                   const char* name, const char* explanation) {
  auto ptr = new config_option_impl<T>(storage, category, name, explanation);
  return std::unique_ptr<config_option>{ptr};
}

} // namespace caf

#endif // CAF_CONFIG_OPTION_HPP
<commit_msg>Fix parsing of size_t config options<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_CONFIG_OPTION_HPP
#define CAF_CONFIG_OPTION_HPP

#include <memory>
#include <string>
#include <vector>
#include <cstdint>
#include <cstring>
#include <functional>

#include "caf/atom.hpp"
#include "caf/error.hpp"
#include "caf/message.hpp"
#include "caf/variant.hpp"
#include "caf/config_value.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/static_visitor.hpp"

#include "caf/detail/type_traits.hpp"

namespace caf {

extern const char* type_name_visitor_tbl[];

/// Helper class to generate config readers for different input types.
class config_option {
public:
  using config_reader_sink = std::function<void (size_t, config_value&,
                                                 optional<std::ostream&>)>;

  using legal_types = detail::type_list<bool, float, double, std::string,
                                        atom_value, int8_t, uint8_t, int16_t,
                                        uint16_t, int32_t, uint32_t, int64_t,
                                        uint64_t>;

  config_option(const char* cat, const char* nm, const char* expl);

  virtual ~config_option();

  inline const char* name() const {
    return name_.c_str();
  }

  inline char short_name() const {
    return short_name_;
  }

  inline const char* category() const {
    return category_;
  }

  inline const char* explanation() const {
    return explanation_;
  }

  /// Returns the full name for this config option as "<category>.<long name>".
  std::string full_name() const;

  /// Returns the held value as string.
  virtual std::string to_string() const = 0;

  /// Returns a sink function for config readers.
  virtual config_reader_sink to_sink() = 0;

  /// Returns a CLI argument parser.
  virtual message::cli_arg to_cli_arg(bool use_caf_prefix = false) = 0;

  /// Returns a human-readable type name for the visited type.
  class type_name_visitor : public static_visitor<const char*> {
  public:
    template <class T>
    const char* operator()(const T&) const {
      static constexpr bool is_int = std::is_integral<T>::value
                                     && !std::is_same<bool, T>::value;
      static constexpr std::integral_constant<bool, is_int> tk{};
      static constexpr int index = idx<T>(tk);
      static_assert(index >= 0, "illegal type in name visitor");
      return type_name_visitor_tbl[static_cast<size_t>(index)];
    }

  private:
    // Catches non-integer types.
    template <class T>
    static constexpr int idx(std::false_type) {
      return detail::tl_index_of<legal_types, T>::value;
    }

    // Catches integer types.
    template <class T>
    static constexpr int idx(std::true_type) {
      using squashed = detail::squashed_int_t<T>;
      return detail::tl_index_of<legal_types, squashed>::value;
    }
  };

protected:
  template <class T, class U>
  static bool assign_config_value(T& x, U& y) {
    x = std::move(y);
    return true;
  }

  // Catches any integer type that is smaller than int64_t.
  template <class T>
  static typename std::enable_if<sizeof(T) < sizeof(int64_t), bool>::type
  assign_config_value(T& x, int64_t& y) {
    if (y < static_cast<int64_t>(std::numeric_limits<T>::lowest())
        || y > static_cast<int64_t>(std::numeric_limits<T>::max()))
      return false;
    x = static_cast<T>(y);
    return true;
  }

  // Catches size_t and uint64_t (yes, they differ on some compilers).
  template <class T>
  static typename std::enable_if<std::is_unsigned<T>::value
                                 && sizeof(T) == sizeof(int64_t), bool>::type
  assign_config_value(T& x, int64_t& y) {
    if (y < 0)
      return false;
    x = static_cast<uint64_t>(y);
    return true;
  }

  static bool assign_config_value(float& x, double& y) {
    if (y < static_cast<double>(std::numeric_limits<float>::lowest())
        || y > static_cast<double>(std::numeric_limits<float>::max()))
      return false;
    x = static_cast<float>(y);
    return true;
  }

  void report_type_error(size_t ln, config_value& x, const char* expected,
                         optional<std::ostream&> out);

private:
  const char* category_;
  std::string name_;
  const char* explanation_;
  char short_name_;
};

template <class T,
          bool IsInsertable = detail::can_insert_elements<T>()
                              && !std::is_same<T, std::string>::value>
class config_option_impl : public config_option {
public:
  config_option_impl(T& ref, const char* ctg, const char* nm, const char* xp)
      : config_option(ctg, nm, xp),
        ref_(ref) {
    // nop
  }

  std::string to_string() const override {
    return deep_to_string(ref_);
  }

  message::cli_arg to_cli_arg(bool use_caf_prefix) override {
    std::string argname;
    if (use_caf_prefix)
      argname = "caf#";
    if (strcmp(category(), "global") != 0) {
      argname += category();
      argname += ".";
    }
    argname += name();
    if (short_name() != '\0') {
      argname += ',';
      argname += short_name();
    }
    return {std::move(argname), explanation(), ref_};
  }

  config_reader_sink to_sink() override {
    return [=](size_t ln, config_value& x, optional<std::ostream&> errors) {
      // the INI parser accepts all integers as int64_t
      // and all floating point numbers as doubles
      using cfg_type =
        typename std::conditional<
          std::is_integral<T>::value && !std::is_same<bool, T>::value,
          int64_t,
          typename std::conditional<
            std::is_floating_point<T>::value,
            double,
            T
            >::type
        >::type;
      if (get<cfg_type>(&x) && assign_config_value(ref_, get<cfg_type>(x)))
        return;
      type_name_visitor tnv;
      report_type_error(ln, x, tnv(ref_), errors);
    };
  }

private:
  T& ref_;
};

template <class T>
class config_option_impl<T, true> : public config_option {
public:
  using value_type = typename T::value_type;

  config_option_impl(T& ref, const char* ctg, const char* nm, const char* xp)
      : config_option(ctg, nm, xp),
        ref_(ref) {
    // nop
  }

  std::string to_string() const override {
    return deep_to_string(ref_);
  }

  message::cli_arg to_cli_arg(bool use_caf_prefix) override {
    std::string argname;
    if (use_caf_prefix)
      argname = "caf#";
    if (strcmp(category(), "global") != 0) {
      argname += category();
      argname += ".";
    }
    argname += name();
    if (short_name() != '\0') {
      argname += ',';
      argname += short_name();
    }
    return {std::move(argname), explanation(), ref_};
  }

  config_reader_sink to_sink() override {
    return [=](size_t ln, config_value& x, optional<std::ostream&> errors) {
      // the INI parser accepts all integers as int64_t
      // and all floating point numbers as doubles
      using cfg_type =
        typename std::conditional<
          std::is_integral<value_type>::value &&
                           !std::is_same<bool, value_type>::value,
          int64_t,
          typename std::conditional<
            std::is_floating_point<value_type>::value,
            double,
            value_type
            >::type
        >::type;
      value_type tmp;
      if (get<cfg_type>(&x) && assign_config_value(tmp, get<cfg_type>(x))) {
        ref_.insert(ref_.end(), std::move(tmp));
        return;
      }
      type_name_visitor tnv;
      report_type_error(ln, x, tnv(tmp), errors);
    };
  }

private:
  T& ref_;
};

template <class T>
std::unique_ptr<config_option>
make_config_option(T& storage, const char* category,
                   const char* name, const char* explanation) {
  auto ptr = new config_option_impl<T>(storage, category, name, explanation);
  return std::unique_ptr<config_option>{ptr};
}

} // namespace caf

#endif // CAF_CONFIG_OPTION_HPP
<|endoftext|>


<commit_before>/*
 MPL3115A2 Barometric Pressure Sensor Library
 By: Nathan Seidle
 SparkFun Electronics
 Date: September 24th, 2013
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 Get pressure, altitude and temperature from the MPL3115A2 sensor.

 September 6, 2016: Modified for use in OpenROV's Software

*/

#include <Arduino.h>
#include <CI2C.h>

#include "MPL3115A2.h"

using namespace mpl3115a2;

MPL3115A2::MPL3115A2( CI2C *i2cInterfaceIn )
    : m_i2cAddress( mpl3115a2::MPL3115A2_ADDRESS )
    , m_pI2C( i2cInterfaceIn )
{

}

ERetCode MPL3115A2::Initialize()
{
    m_isInitialized = false;

    delay( 500 );

    //Verify that the sensor is up and running
    if( VerifyChipId() != ERetCode::SUCCESS )
    {
        //We were unable to verify this sensor
        return ERetCode::FAILED;
    }

    m_isInitialized = true;
    return ERetCode::SUCCESS;
}

ERetCode MPL3115A2::SetMode( EMode modeIn )
{
    switch (modeIn)
    {
        case EMode::BAROMETER:
        {
            return SetModeBarometer();
        }
        case EMode::ALTIMETER:
        {
            return SetModeAltimeter();
        }
        case EMode::STANDBY:
        {
            return SetModeStandby();
        }
        case EMode::ACTIVE:
        {
            return SetModeActive();
        }
        default:
        {
            return ERetCode::FAILED;
        }
    }
}

//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
ERetCode MPL3115A2::SetOversampleRatio( EOversampleRatio osrIn )
{
    int32_t returnCode;
    auto sampleRate = static_cast<int>( osrIn );

    //Align it for the control register
    sampleRate <<= 3;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Clear out old Oversample bits
    tempSetting &= B11000111;

    //Mask new sample rate
    tempSetting |= sampleRate;

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
ERetCode MPL3115A2::EnableEventFlags()
{
    // Enable all three pressure and temp event flags
    auto ret = WriteByte( MPL3115A2_REGISTER::PT_DATA_CFG, 0x07);
    if( ret != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
ERetCode MPL3115A2::ReadPressure( float& pressureOut )
{
    int32_t retCode;
    //Serial.println("In pressure loop");

    //Check the PDR bit to see if we need to toggle oneshot
    uint8_t status;

    retCode = ReadByte( MPL3115A2_REGISTER::STATUS, status );
    if( retCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    if( ( status & (1<<2) )  == 0 )
    {
        //Serial.println( "HAVE TO TOGGLE ONESHOT" );
        ToggleOneShot();
    }

    //Wait for PDR bit
    int counter = 0;
    retCode = ReadByte( MPL3115A2_REGISTER::STATUS, status );
    if( retCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }
    while( ( status & (1<<2) )  == 0 )
    {
        //Check that bit again, duh
        retCode = ReadByte( MPL3115A2_REGISTER::STATUS, status );
        if( retCode != I2C::ERetCode::SUCCESS )
        {
            return ERetCode::FAILED;
        }

        if( ++counter > 600 )
        {
            return ERetCode::TIMED_OUT;
        }
    }

    return ERetCode::SUCCESS;
}

/***************************************************************************
    PRIVATE FUNCTIONS
 ***************************************************************************/

ERetCode MPL3115A2::VerifyChipId()
{
    //Read the chip id
    uint8_t id;

    auto ret = ReadByte( MPL3115A2_REGISTER::WHO_AM_I, id );

    if( ret != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Check to see if it matches the proper ID (0xC4)
    if( id != 0xC4 )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

ERetCode MPL3115A2::SetModeBarometer()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t setting;

    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, setting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Clear the altimeter bit
    setting &= ~(1<<7);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, setting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

ERetCode MPL3115A2::SetModeAltimeter()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Set the altimeter bit
    tempSetting |= (1<<7);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
ERetCode MPL3115A2::SetModeStandby()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Clear SBYB bit for Standby mode
    tempSetting &= ~(1<<0);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
ERetCode MPL3115A2::SetModeActive()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Set SBYB bit for Active mode
    tempSetting |= (1<<0);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Clears and then sets the OST bit which causes the sensor to take another readings
//Needed to sample faster than 1Hz
ERetCode MPL3115A2::ToggleOneShot()
{
    Serial.println( "Toggling one shot." );
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Clear the one shot bit
    tempSetting &= ~(1<<1);
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Reat the current settings, just to be safe :)
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Set the overshot bit
    tempSetting |= (1<<1);
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    return ERetCode::SUCCESS;
}

int32_t MPL3115A2::WriteByte( MPL3115A2_REGISTER addressIn, uint8_t dataIn )
{
	return (int32_t)m_pI2C->WriteByte( m_i2cAddress, (uint8_t)addressIn, dataIn );
}

int32_t MPL3115A2::ReadByte( MPL3115A2_REGISTER addressIn, uint8_t &dataOut )
{
	return (int32_t)m_pI2C->ReadByte( m_i2cAddress, (uint8_t)addressIn, &dataOut );
}
int32_t MPL3115A2::ReadNBytes( MPL3115A2_REGISTER addressIn, uint8_t* dataOut, uint8_t byteCountIn )
{
    return (int32_t)m_pI2C->ReadBytes( m_i2cAddress, (uint8_t)addressIn, dataOut, byteCountIn );
}<commit_msg>Need to make sure it sets the correct bit<commit_after>/*
 MPL3115A2 Barometric Pressure Sensor Library
 By: Nathan Seidle
 SparkFun Electronics
 Date: September 24th, 2013
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 Get pressure, altitude and temperature from the MPL3115A2 sensor.

 September 6, 2016: Modified for use in OpenROV's Software

*/

#include <Arduino.h>
#include <CI2C.h>

#include "MPL3115A2.h"

using namespace mpl3115a2;

MPL3115A2::MPL3115A2( CI2C *i2cInterfaceIn )
    : m_i2cAddress( mpl3115a2::MPL3115A2_ADDRESS )
    , m_pI2C( i2cInterfaceIn )
{

}

ERetCode MPL3115A2::Initialize()
{
    m_isInitialized = false;

    delay( 500 );

    //Verify that the sensor is up and running
    if( VerifyChipId() != ERetCode::SUCCESS )
    {
        //We were unable to verify this sensor
        return ERetCode::FAILED;
    }

    m_isInitialized = true;
    return ERetCode::SUCCESS;
}

ERetCode MPL3115A2::SetMode( EMode modeIn )
{
    switch (modeIn)
    {
        case EMode::BAROMETER:
        {
            return SetModeBarometer();
        }
        case EMode::ALTIMETER:
        {
            return SetModeAltimeter();
        }
        case EMode::STANDBY:
        {
            return SetModeStandby();
        }
        case EMode::ACTIVE:
        {
            return SetModeActive();
        }
        default:
        {
            return ERetCode::FAILED;
        }
    }
}

//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
ERetCode MPL3115A2::SetOversampleRatio( EOversampleRatio osrIn )
{
    int32_t returnCode;
    auto sampleRate = static_cast<int>( osrIn );

    //Align it for the control register
    sampleRate <<= 3;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Clear out old Oversample bits
    tempSetting &= B11000111;

    //Mask new sample rate
    tempSetting |= sampleRate;

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
ERetCode MPL3115A2::EnableEventFlags()
{
    // Enable all three pressure and temp event flags
    auto ret = WriteByte( MPL3115A2_REGISTER::PT_DATA_CFG, 0x07);
    if( ret != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
ERetCode MPL3115A2::ReadPressure( float& pressureOut )
{
    int32_t retCode;
    //Serial.println("In pressure loop");

    //Check the PDR bit to see if we need to toggle oneshot
    uint8_t status;

    retCode = ReadByte( MPL3115A2_REGISTER::STATUS, status );
    if( retCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    Serial.println(status, HEX);

    return ERetCode::SUCCESS;
}

ERetCode MPL3115A2::SetModeAltimeter()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Set the altimeter bit
    tempSetting |= (1<<7);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
ERetCode MPL3115A2::SetModeStandby()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Clear SBYB bit for Standby mode
    tempSetting &= ~(1<<0);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
ERetCode MPL3115A2::SetModeActive()
{
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    //Set SBYB bit for Active mode
    tempSetting |= (1<<0);

    //And write it to the register
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED;
    }

    return ERetCode::SUCCESS;
}

//Clears and then sets the OST bit which causes the sensor to take another readings
//Needed to sample faster than 1Hz
ERetCode MPL3115A2::ToggleOneShot()
{
    Serial.println( "Toggling one shot." );
    int32_t returnCode;

    //Read the current settings
    uint8_t tempSetting;
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Clear the one shot bit
    tempSetting &= ~(1<<1);
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Reat the current settings, just to be safe :)
    returnCode = ReadByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    //Set the overshot bit
    tempSetting |= (1<<1);
    returnCode = WriteByte( MPL3115A2_REGISTER::CONTROL_REGISTER_1, tempSetting );
    if( returnCode != I2C::ERetCode::SUCCESS )
    {
        return ERetCode::FAILED_ONESHOT;
    }

    return ERetCode::SUCCESS;
}

int32_t MPL3115A2::WriteByte( MPL3115A2_REGISTER addressIn, uint8_t dataIn )
{
	return (int32_t)m_pI2C->WriteByte( m_i2cAddress, (uint8_t)addressIn, dataIn );
}

int32_t MPL3115A2::ReadByte( MPL3115A2_REGISTER addressIn, uint8_t &dataOut )
{
	return (int32_t)m_pI2C->ReadByte( m_i2cAddress, (uint8_t)addressIn, &dataOut );
}
int32_t MPL3115A2::ReadNBytes( MPL3115A2_REGISTER addressIn, uint8_t* dataOut, uint8_t byteCountIn )
{
    return (int32_t)m_pI2C->ReadBytes( m_i2cAddress, (uint8_t)addressIn, dataOut, byteCountIn );
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Any modified source or binaries are used only with the BitShares network.
 *
 * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 2000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
      if( !block.valid() )
      {
         wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
         uint32_t dropped_count = 0;
         while( true )
         {
            fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
            // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
            if( !last_id.valid() )
               break;
            // we've caught up to the gap
            if( block_header::num_from_id( *last_id ) <= i )
               break;
            _block_id_to_block.remove( *last_id );
            dropped_count++;
         }
         wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
         break;
      }
      apply_block(*block, skip_witness_signature |
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_witness_schedule_check |
                          skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader)
{
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      fc::optional<signed_block> last_block = _block_id_to_block.last();
      if( last_block.valid() )
      {
         _fork_db.start_block( *last_block );
         idump((last_block->id())(last_block->block_num()));
         if( last_block->id() != head_block_id() )
         {
              FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state" );
         }
      }
      //idump((head_block_id())(head_block_num()));
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         while( true )
         {
         //   elog("pop");
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
            try
            {
               _block_id_to_block.remove(popped_block_id);
            }
            catch (const fc::key_not_found_exception&)
            {
            }
         }
      }
      catch (...)
      {
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

} }
<commit_msg>db_management.cpp:  Only pop to last irreversible block, fix #407<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Any modified source or binaries are used only with the BitShares network.
 *
 * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <graphene/chain/database.hpp>

#include <graphene/chain/operation_history_object.hpp>
#include <graphene/chain/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
{ try {
   ilog( "reindexing blockchain" );
   wipe(data_dir, false);
   open(data_dir, [&initial_allocation]{return initial_allocation;});

   auto start = fc::time_point::now();
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }

   const auto last_block_num = last_block->block_num();

   ilog( "Replaying blocks..." );
   _undo_db.disable();
   for( uint32_t i = 1; i <= last_block_num; ++i )
   {
      if( i % 2000 == 0 ) std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional< signed_block > block = _block_id_to_block.fetch_by_number(i);
      if( !block.valid() )
      {
         wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
         uint32_t dropped_count = 0;
         while( true )
         {
            fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
            // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
            if( !last_id.valid() )
               break;
            // we've caught up to the gap
            if( block_header::num_from_id( *last_id ) <= i )
               break;
            _block_id_to_block.remove( *last_id );
            dropped_count++;
         }
         wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
         break;
      }
      apply_block(*block, skip_witness_signature |
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_witness_schedule_check |
                          skip_authority_check);
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   close();
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader)
{
   try
   {
      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());

      fc::optional<signed_block> last_block = _block_id_to_block.last();
      if( last_block.valid() )
      {
         _fork_db.start_block( *last_block );
         idump((last_block->id())(last_block->block_num()));
         if( last_block->id() != head_block_id() )
         {
              FC_ASSERT( head_block_num() == 0, "last block ID does not match current chain state" );
         }
      }
      //idump((head_block_id())(head_block_num()));
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         uint32_t cutoff = get_dynamic_global_properties().last_irreversible_block_num;

         while( head_block_num() > cutoff )
         {
         //   elog("pop");
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
            try
            {
               _block_id_to_block.remove(popped_block_id);
            }
            catch (const fc::key_not_found_exception&)
            {
            }
         }
      }
      catch (...)
      {
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();
}

} }
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
#define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH

#ifdef HAVE_CMAKE_CONFIG
#include "cmake_config.h"
#elif defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#include <memory>

#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

#include <dune/grid/io/file/vtk/function.hh>

#include <dune/stuff/la/container/interface.hh>

#include <dune/gdt/space/interface.hh>

#include "local.hh"

namespace Dune {
namespace GDT {

// template< class DiscreteFunctionSpaceImp, class VectorImp >
// class DefaultConst;

// template< class DiscreteFunctionSpaceImp, class VectorImp >
// class Default
//  : public Dune::VTKFunction< typename DiscreteFunctionSpaceImp::GridViewType >
//{
// private:
//  typedef Dune::VTKFunction< typename DiscreteFunctionSpaceImp::GridViewType > BaseType;

// public:
//  typedef DiscreteFunctionSpaceImp DiscreteFunctionSpaceType;

//  typedef VectorImp VectorType;

//  typedef Default< DiscreteFunctionSpaceType, VectorType > ThisType;

//  typedef DefaultConst< DiscreteFunctionSpaceType, VectorType > ConstType;

//  typedef typename DiscreteFunctionSpaceType::GridViewType::template Codim< 0 >::Iterator::Entity EntityType;

//  static const int polOrder = DiscreteFunctionSpaceType::polynomialOrder;

//  typedef Dune::Detailed::Discretizations::DiscreteFunction::LocalConst< ThisType > ConstLocalFunctionType;

//  typedef Dune::Detailed::Discretizations::DiscreteFunction::Local< ThisType > LocalFunctionType;

//  typedef typename DiscreteFunctionSpaceType::FunctionSpaceType FunctionSpaceType;

//  typedef typename FunctionSpaceType::DomainType DomainType;

//  typedef typename FunctionSpaceType::RangeFieldType RangeFieldType;

//  typedef typename FunctionSpaceType::RangeType RangeType;

//  static const int dimDomain = DiscreteFunctionSpaceType::dimDomain;

//  static const int dimRange = DiscreteFunctionSpaceType::dimRange;

//  typedef typename VectorType::size_type size_type;

//  Default(const DiscreteFunctionSpaceType& _space,
//          std::shared_ptr< VectorType > _vector,
//          const std::string _name = "discrete_function")
//    : BaseType(),
//      space_(_space)
//    , vector_(_vector)
//    , name_(_name)
//  {
//    assert(vector_->size() == space_.map().size() && "Given vector has wrong size!");
//  }

//  Default(const DiscreteFunctionSpaceType& _space,
//          const std::string _name = "discrete_function")
//    : BaseType(),
//      space_(_space)
//    , vector_(new VectorType(space_.map().size()))
//    , name_(_name)
//  {
//    assert(vector_->size() == space_.map().size() && "Given vector has wrong size!");
//  }

//  std::shared_ptr< const ConstType > createConst() const
//  {
//    std::shared_ptr< const ConstType > ret(new ConstType(*this));
//    return ret;
//  }

// private:
//  Default(const ThisType&);
//  ThisType& operator=(const ThisType&);

// public:
//  const DiscreteFunctionSpaceType& space() const
//  {
//    return space_;
//  }

//  virtual std::string name() const
//  {
//    return name_;
//  }

//  ConstLocalFunctionType localFunction(const EntityType& entity) const
//  {
//    return ConstLocalFunctionType(*this, entity);
//  }

//  LocalFunctionType localFunction(const EntityType& entity)
//  {
//    return LocalFunctionType(*this, entity);
//  }

//  std::shared_ptr< VectorType > vector()
//  {
//    return vector_;
//  }

//  const std::shared_ptr< const VectorType > vector() const
//  {
//    return vector_;
//  }

//  /**
//      @name Convenience methods
//      @{
//   **/
//  size_type size() const
//  {
//    return vector_->size();
//  }
//  /**
//      @}
//   **/

//  void clear()
//  {
//    const RangeFieldType zero(0);
//    for (size_type ii = 0; ii < vector_->size(); ++ii)
//      vector_->set(ii, zero);
//  }

//  /**
//      @name Methods to comply with the Dune::VTKFunction interface
//      @{
//   **/
//  virtual int ncomps() const
//  {
//    return dimRange;
//  }

//  virtual double evaluate(int component, const EntityType& entity, const DomainType& x) const
//  {
//    assert(vector_->size() == space_.map().size() && "Given vector has wrong size!");
//    RangeType ret(0.0);
//    localFunction(entity).evaluate(x, ret);
//    return ret[component];
//  }
//  /**
//      @}
//     **/

// private:
//  const DiscreteFunctionSpaceType& space_;
//  std::shared_ptr< VectorType > vector_;
//  const std::string name_;
//}; // class Default

template <class SpaceImp, class VectorImp>
class DiscreteFunctionDefaultConst : public Dune::VTKFunction<typename SpaceImp::GridPartType::GridViewType>,
                                     public Dune::Stuff::LocalizableFunction
{
public:
  typedef typename SpaceInterface<typename SpaceImp::Traits>::derived_type SpaceType;
  typedef typename Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>::derived_type VectorType;

  typedef typename SpaceType::EntityType EntityType;

  typedef DiscreteFunctionLocalConst<SpaceType, VectorType> ConstLocalFunctionType;
  typedef typename ConstLocalFunctionType::DomainType DomainType;
  typedef typename ConstLocalFunctionType::RangeType RangeType;

  DiscreteFunctionDefaultConst(const SpaceType& sp, const std::shared_ptr<const VectorType> vec,
                               const std::string nm = "discrete_function")
    : /*BaseType()
    , */ space_(sp)
    , name_(nm)
    , vector_(vec)
  {
    assert(vector_->size() == space_.mapper().size() && "Given vector has wrong size!");
  }

  const SpaceType& space() const
  {
    return space_;
  }

  virtual std::string name() const
  {
    return name_;
  }

  ConstLocalFunctionType localFunction(const EntityType& entity) const
  {
    return ConstLocalFunctionType(*this, entity);
  }

  std::shared_ptr<const VectorType> vector() const
  {
    return vector_;
  }

  /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
  /* @{ */
  virtual int ncomps() const
  {
    return SpaceType::dimRange;
  }

  virtual double evaluate(int component, const EntityType& entity, const DomainType& x) const
  {
    RangeType ret(0);
    localFunction(entity).evaluate(x, ret);
    return ret[component];
  }
  /* @} */

private:
  const SpaceType& space_;
  const std::string name_;
  const std::shared_ptr<const VectorType> vector_;
}; // class DiscreteFunctionDefaultConst

template <class SpaceImp, class VectorImp>
class DiscreteFunctionDefault : public DiscreteFunctionDefaultConst<SpaceImp, VectorImp>
{
  typedef DiscreteFunctionDefaultConst<SpaceImp, VectorImp> BaseType;

public:
  typedef typename SpaceInterface<typename SpaceImp::Traits>::derived_type SpaceType;
  typedef typename Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>::derived_type VectorType;

  typedef typename SpaceType::EntityType EntityType;

  typedef DiscreteFunctionLocal<SpaceType, VectorType> LocalFunctionType;
  typedef typename LocalFunctionType::DomainType DomainType;

  DiscreteFunctionDefault(const SpaceType& sp, std::shared_ptr<VectorType> vec,
                          const std::string nm = "discrete_function")
    : BaseType(sp, vec, nm)
    , nonConstVector_(vec)
  {
  }

  DiscreteFunctionDefault(const SpaceType& sp, const std::string nm = "discrete_function")
    : BaseType(sp, std::make_shared<VectorType>(sp.mapper().size()), nm)
    , nonConstVector_(std::make_shared<VectorType>(const_cast<VectorType&>(
          *(BaseType::vector())))) // <- I am not sure if this is safe to do. I would expect the BaseType to live long
  // enough, but maybe someone else has a better Idea!
  {
  }

  LocalFunctionType localFunction(const EntityType& entity)
  {
    return LocalFunctionType(*this, entity);
  }

  std::shared_ptr<VectorType> vector()
  {
    return nonConstVector_;
  }

  //  virtual std::string name() const
  //  {
  //    return BaseType::name();
  //  }

  //  /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
  //  /* @{ */
  //  virtual int ncomps() const
  //  {
  //    return BaseType::ncomps();
  //  }

  //  virtual double evaluate(int component, const EntityType& entity, const DomainType& x) const
  //  {
  //    BaseType::evaluate(component, entity, x);
  //  }
  //  /* @} */

private:
  std::shared_ptr<VectorType> nonConstVector_;
}; // class DiscreteFunctionDefault

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
<commit_msg>[discretefunction.default] some cleanup<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
#define DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH

#ifdef HAVE_CMAKE_CONFIG
#include "cmake_config.h"
#elif defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#include <memory>

#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>

#include <dune/grid/io/file/vtk/function.hh>

#include <dune/stuff/la/container/interface.hh>
#include <dune/gdt/space/interface.hh>

#include "local.hh"

namespace Dune {
namespace GDT {

template <class SpaceImp, class VectorImp>
class DiscreteFunctionDefaultConst : public Dune::VTKFunction<typename SpaceImp::GridPartType::GridViewType>,
                                     public Dune::Stuff::LocalizableFunction
{
public:
  typedef typename SpaceInterface<typename SpaceImp::Traits>::derived_type SpaceType;
  typedef typename Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>::derived_type VectorType;

  typedef typename SpaceType::EntityType EntityType;

  typedef DiscreteFunctionLocalConst<SpaceType, VectorType> ConstLocalFunctionType;
  typedef typename ConstLocalFunctionType::DomainType DomainType;
  typedef typename ConstLocalFunctionType::RangeType RangeType;

  DiscreteFunctionDefaultConst(const SpaceType& sp, const std::shared_ptr<const VectorType> vec,
                               const std::string nm = "discrete_function")
    : space_(sp)
    , name_(nm)
    , vector_(vec)
  {
    assert(vector_->size() == space_.mapper().size() && "Given vector has wrong size!");
  }

  const SpaceType& space() const
  {
    return space_;
  }

  virtual std::string name() const
  {
    return name_;
  }

  ConstLocalFunctionType localFunction(const EntityType& entity) const
  {
    return ConstLocalFunctionType(*this, entity);
  }

  std::shared_ptr<const VectorType> vector() const
  {
    return vector_;
  }

  /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
  /* @{ */
  virtual int ncomps() const
  {
    return SpaceType::dimRange;
  }

  virtual double evaluate(int component, const EntityType& entity, const DomainType& x) const
  {
    RangeType ret(0);
    localFunction(entity).evaluate(x, ret);
    return ret[component];
  }
  /* @} */

private:
  const SpaceType& space_;
  const std::string name_;
  const std::shared_ptr<const VectorType> vector_;
}; // class DiscreteFunctionDefaultConst

template <class SpaceImp, class VectorImp>
class DiscreteFunctionDefault : public DiscreteFunctionDefaultConst<SpaceImp, VectorImp>
{
  typedef DiscreteFunctionDefaultConst<SpaceImp, VectorImp> BaseType;

public:
  typedef typename SpaceInterface<typename SpaceImp::Traits>::derived_type SpaceType;
  typedef typename Dune::Stuff::LA::VectorInterface<typename VectorImp::Traits>::derived_type VectorType;

  typedef typename SpaceType::EntityType EntityType;

  typedef DiscreteFunctionLocal<SpaceType, VectorType> LocalFunctionType;
  typedef typename LocalFunctionType::DomainType DomainType;

  DiscreteFunctionDefault(const SpaceType& sp, std::shared_ptr<VectorType> vec,
                          const std::string nm = "discrete_function")
    : BaseType(sp, vec, nm)
    , nonConstVector_(vec)
  {
  }

  DiscreteFunctionDefault(const SpaceType& sp, const std::string nm = "discrete_function")
    : BaseType(sp, std::make_shared<VectorType>(sp.mapper().size()), nm)
    , nonConstVector_(std::make_shared<VectorType>(const_cast<VectorType&>(
          *(BaseType::vector())))) // <- I am not sure if this is safe to do. I would expect the BaseType to live long
  // enough, but maybe someone else has a better Idea!
  {
  }

  LocalFunctionType localFunction(const EntityType& entity)
  {
    return LocalFunctionType(*this, entity);
  }

  std::shared_ptr<VectorType> vector()
  {
    return nonConstVector_;
  }

  //  virtual std::string name() const
  //  {
  //    return BaseType::name();
  //  }

  //  /** \defgroup vtk ´´Methods to comply with the Dune::VTKFunction interface.'' */
  //  /* @{ */
  //  virtual int ncomps() const
  //  {
  //    return BaseType::ncomps();
  //  }

  //  virtual double evaluate(int component, const EntityType& entity, const DomainType& x) const
  //  {
  //    BaseType::evaluate(component, entity, x);
  //  }
  //  /* @} */

private:
  std::shared_ptr<VectorType> nonConstVector_;
}; // class DiscreteFunctionDefault

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_DISCRETEFUNCTION_DEFAULT_HH
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <iostream>
#include <tuple>

#include <opcodes.hpp>

using namespace std;
using dcpu::emulator::opcode;

class OpcodesParserTest: public ::testing::TestWithParam<tuple<uint16_t, string>> {
public:
	void SetUp() {
		auto data = GetParam();
		instruction = get<0>(data);
		expected_string = get<1>(data);
	}
protected:
	uint16_t instruction;
	string expected_string;
};

TEST_P(OpcodesParserTest, Parse) {
	dcpu::emulator::dcpu cpu;

	unique_ptr<opcode> op = opcode::parse(cpu, instruction);
	EXPECT_EQ(expected_string, op->to_str());
}

INSTANTIATE_TEST_CASE_P(All, OpcodesParserTest, ::testing::Values(
	make_tuple((uint16_t)0x0001, string("set A, A")),
	make_tuple((uint16_t)0x0002, string("add A, A")),
	make_tuple((uint16_t)0x0003, string("sub A, A")),
	make_tuple((uint16_t)0x0004, string("mul A, A")),
	make_tuple((uint16_t)0x0005, string("mli A, A")),
	make_tuple((uint16_t)0x0006, string("div A, A")),
	make_tuple((uint16_t)0x0007, string("dvi A, A")),
	make_tuple((uint16_t)0x0008, string("mod A, A")),
	make_tuple((uint16_t)0x0009, string("mdi A, A")),
	make_tuple((uint16_t)0x000a, string("and A, A")),
	make_tuple((uint16_t)0x000b, string("bor A, A")),
	make_tuple((uint16_t)0x000c, string("xor A, A")),
	make_tuple((uint16_t)0x000d, string("shr A, A")),
	make_tuple((uint16_t)0x000e, string("asr A, A")),
	make_tuple((uint16_t)0x000f, string("shl A, A")),
	make_tuple((uint16_t)0xfd50, string("ifb [C], 30")),
	make_tuple((uint16_t)0xf971, string("ifc [X], 29")),
	make_tuple((uint16_t)0x0012, string("ife A, A")),
	make_tuple((uint16_t)0x0013, string("ifn A, A")),
	make_tuple((uint16_t)0x0014, string("ifg A, A")),
	make_tuple((uint16_t)0x0015, string("ifa A, A")),
	make_tuple((uint16_t)0x0016, string("ifl A, A")),
	make_tuple((uint16_t)0x0017, string("ifu A, A")),
	make_tuple((uint16_t)0x001a, string("adx A, A")),
	make_tuple((uint16_t)0x001b, string("sbx A, A")),
	make_tuple((uint16_t)0x001e, string("sti A, A")),
	make_tuple((uint16_t)0x001f, string("std A, A")),
	make_tuple((uint16_t)0x0020, string("jsr A")),
	make_tuple((uint16_t)0x00e0, string("hcf A")),
	make_tuple((uint16_t)0x0100, string("int A")),
	make_tuple((uint16_t)0x0120, string("iag A")),
	make_tuple((uint16_t)0x0140, string("ias A")),
	make_tuple((uint16_t)0x0160, string("rfi A")),
	make_tuple((uint16_t)0x0180, string("iaq A")),
	make_tuple((uint16_t)0x0200, string("hwn A")),
	make_tuple((uint16_t)0x0220, string("hwq A")),
	make_tuple((uint16_t)0x0240, string("hwi A"))

));
<commit_msg>Added negative tests for opcodes parser<commit_after>#include <gtest/gtest.h>
#include <iostream>
#include <tuple>

#include <opcodes.hpp>

using namespace std;
using dcpu::emulator::opcode;

class OpcodesParserTest: public ::testing::TestWithParam<tuple<uint16_t, string>> {
public:
	void SetUp() {
		auto data = GetParam();
		instruction = get<0>(data);
		expected_string = get<1>(data);
	}
protected:
	uint16_t instruction;
	string expected_string;
};

TEST_P(OpcodesParserTest, ValidInstruction) {
	dcpu::emulator::dcpu cpu;

	unique_ptr<opcode> op = opcode::parse(cpu, instruction);
	EXPECT_EQ(expected_string, op->to_str());
}

INSTANTIATE_TEST_CASE_P(All, OpcodesParserTest, ::testing::Values(
	make_tuple((uint16_t)0x0001, string("set A, A")),
	make_tuple((uint16_t)0x0002, string("add A, A")),
	make_tuple((uint16_t)0x0003, string("sub A, A")),
	make_tuple((uint16_t)0x0004, string("mul A, A")),
	make_tuple((uint16_t)0x0005, string("mli A, A")),
	make_tuple((uint16_t)0x0006, string("div A, A")),
	make_tuple((uint16_t)0x0007, string("dvi A, A")),
	make_tuple((uint16_t)0x0008, string("mod A, A")),
	make_tuple((uint16_t)0x0009, string("mdi A, A")),
	make_tuple((uint16_t)0x000a, string("and A, A")),
	make_tuple((uint16_t)0x000b, string("bor A, A")),
	make_tuple((uint16_t)0x000c, string("xor A, A")),
	make_tuple((uint16_t)0x000d, string("shr A, A")),
	make_tuple((uint16_t)0x000e, string("asr A, A")),
	make_tuple((uint16_t)0x000f, string("shl A, A")),
	make_tuple((uint16_t)0xfd50, string("ifb [C], 30")),
	make_tuple((uint16_t)0xf971, string("ifc [X], 29")),
	make_tuple((uint16_t)0x0012, string("ife A, A")),
	make_tuple((uint16_t)0x0013, string("ifn A, A")),
	make_tuple((uint16_t)0x0014, string("ifg A, A")),
	make_tuple((uint16_t)0x0015, string("ifa A, A")),
	make_tuple((uint16_t)0x0016, string("ifl A, A")),
	make_tuple((uint16_t)0x0017, string("ifu A, A")),
	make_tuple((uint16_t)0x001a, string("adx A, A")),
	make_tuple((uint16_t)0x001b, string("sbx A, A")),
	make_tuple((uint16_t)0x001e, string("sti A, A")),
	make_tuple((uint16_t)0x001f, string("std A, A")),
	make_tuple((uint16_t)0x0020, string("jsr A")),
	make_tuple((uint16_t)0x00e0, string("hcf A")),
	make_tuple((uint16_t)0x0100, string("int A")),
	make_tuple((uint16_t)0x0120, string("iag A")),
	make_tuple((uint16_t)0x0140, string("ias A")),
	make_tuple((uint16_t)0x0160, string("rfi A")),
	make_tuple((uint16_t)0x0180, string("iaq A")),
	make_tuple((uint16_t)0x0200, string("hwn A")),
	make_tuple((uint16_t)0x0220, string("hwq A")),
	make_tuple((uint16_t)0x0240, string("hwi A"))
));

class OpcodesParserNegativeTest: public ::testing::TestWithParam<uint16_t> {
public:
	void SetUp() {
		instruction = GetParam();
	}
protected:
	uint16_t instruction;
};

TEST_P(OpcodesParserNegativeTest, InvalidInstruction) {
	dcpu::emulator::dcpu cpu;
	EXPECT_THROW({
		opcode::parse(cpu, instruction);
	}, invalid_argument);
}

INSTANTIATE_TEST_CASE_P(All, OpcodesParserNegativeTest, ::testing::Values(
	0x0000, 0x0018, 0x0019, 0x001c, 0x001d, 0x0040, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x01a0, 0x01c0, 0x01e0,
	0x0260, 0x0280, 0x02a0, 0x02c0, 0x02e0, 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0, 0x03e0));
<|endoftext|>


<commit_before>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "parser_clang/pch.h"
#include "parser_clang/coClangSourceParser.h"
#include "pattern/scope/coDefer.h"
#include "lang/result/coResult_f.h"
#include "lang/reflect/coType.h"
#include "lang/reflect/coField.h"
#include "parser/source/coParsedType.h"
#include "parser/source/coParsedField.h"
#include "container/string/coDynamicString_f.h"
#include "container/array/coDynamicArray_f.h"
#include "container/array/coConstArray_f.h"
#include "memory/allocator/coLocalAllocator.h"
#include "io/path/coPath_f.h"
#include "io/path/coPathStatus.h"

coSourceParser* coSourceParser::Create()
{
	return new coClangSourceParser();
}

coClangSourceParser::coClangSourceParser()
	: clangIndex(nullptr)
{

}

coClangSourceParser::~coClangSourceParser()
{
	if (clangIndex)
	{
		clang_disposeIndex(clangIndex);
	}
}

coResult coClangSourceParser::OnInit(const coObject::InitConfig& _config)
{
	coTRY(Super::OnInit(_config), nullptr);
	//const InitConfig& config = static_cast<const InitConfig&>(_config);
	coASSERT(!clangIndex);
	clangIndex = clang_createIndex(1, 1);

	return true;
}

coResult coClangSourceParser::ParsePrecompiledHeader(const ParseConfig& _config)
{
	coTRY(Super::ParsePrecompiledHeader(_config), nullptr);
	coLocalAllocator localAllocator(2048);

	// Check out dir
	/*{
		coPathStatus status;
		coTRY(coGetPathStatus(status, _config.outPath), nullptr);
		coTRY(status.Exists(), "The output directory does not exist: "<<_config.outPath);
	}*/

	// Build file path
	coDynamicString filePath(localAllocator);
	{
		filePath = _config.filePath;
		coNullTerminate(filePath);
	}

	// Build out path
	coDynamicString outPath(localAllocator);
	{
		coConstString baseName;
		coGetBaseName(baseName, _config.filePath);
		coJoinPaths(outPath, _config.outPath, baseName);
		outPath << ".pch";
		coNullTerminate(outPath);
	}

	// Parse
	{
		CXTranslationUnit translationUnit = nullptr;
		const coArray<const coChar*> args = { "-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-D", "coREFLECTION_PARSING", "-IJ:/CODE/core/src" };
		//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, args.count, args.data, 0, nullptr);
		const CXErrorCode parseError = clang_parseTranslationUnit2(clangIndex, filePath.data, args.data, args.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
		coTRY(parseError == CXError_Success, "Clang failed to parse the file: " << filePath);
		coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
		coDEFER() { clang_disposeTranslationUnit(translationUnit); };
		const CXSaveError saveError = static_cast<CXSaveError>(clang_saveTranslationUnit(translationUnit, outPath.data, 0));
		coTRY(parseError == CXSaveError_None, "Clang failed to save the file: " << outPath.data);
	}

	return true;
}

coResult coClangSourceParser::Parse(ParseResult& _result, const ParseConfig& _config)
{
	coTRY(Super::Parse(_result, _config), nullptr);
	coLocalAllocator localAllocator(2048);

	coDynamicString filePath(localAllocator);
	filePath = _config.filePath;
	coNullTerminate(filePath);
	CXTranslationUnit translationUnit = nullptr;
	const coArray<const coChar*> args = {"-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-D", "coREFLECTION_PARSING", "-IJ:/CODE/core/src", "-include-pch", "J:/CODE/core/build/vs2015/reflect/pattern/pch.pch"};
	//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, args.count, args.data, 0, nullptr);
	const CXErrorCode error = clang_parseTranslationUnit2(clangIndex, filePath.data, args.data, args.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
	coTRY(error == CXError_Success, "Clang failed to parse the file: " << filePath);
	coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
	coDEFER() { clang_disposeTranslationUnit(translationUnit); };
	CXCursor cursor = clang_getTranslationUnitCursor(translationUnit);

	if (_result.parsedTypes)
	{
		coTRY(ParseTypes(_result, cursor), "Failed to parse types");
	}
	return true;
}

CXChildVisitResult coClangSourceParser::ParseTypesVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coClangSourceParser* _this = scope->parser;
	const coBool definition = clang_isCursorDefinition(_child) != 0;
	if (!definition)
		return CXChildVisitResult::CXChildVisit_Continue;

	switch (_child.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		const CXCursor reflectedAttr = FindAttribute(_child, "Reflected");
		if (!clang_Cursor_isNull(reflectedAttr))
		{
			coASSERT(scope->result);
			if (!_this->ParseType(*scope->result, _child))
			{
				coERROR("Failed");
				return CXChildVisitResult::CXChildVisit_Break;
			}
		}
		break;
	}
	}
	return CXChildVisitResult::CXChildVisit_Continue;
}

CXChildVisitResult coClangSourceParser::ParseTypeChildrenVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coASSERT(scope);
	coClangSourceParser* _this = scope->parser;
	if (!_this->ParseTypeChild(*scope, _child))
	{
		coERROR("Failed to parse type child");
		CXChildVisitResult::CXChildVisit_Break;
	}

	return CXChildVisitResult::CXChildVisit_Continue;
}

coResult coClangSourceParser::ParseTypeChild(const ScopeInfo& scope, const CXCursor& _cursor)
{
	coTRY(scope.curType, nullptr);
	switch (_cursor.kind)
	{
	case CXCursor_StructDecl:
	{
		int x = 0;
		++x;
		break;
	}
	case CXCursor_FieldDecl:
	{
		coParsedField* parsedField = new coParsedField();
		parsedField->field = new coField();
		coDEFER() { delete parsedField; };
		coTRY(ParseField(*parsedField, _cursor), "Failed to parse field: " << parsedField->field->name);
		coPushBack(scope.curType->parsedFields, parsedField);
		parsedField = nullptr;
		break;
	}
	case CXCursor_VarDecl: // Static field
	{
		break;
	}
	case CXCursor_CXXMethod: // Both static and non-static
	{
		const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
		if (staticMethod)
		{

		}
		else
		{

		}
		break;
	}
	}
	return true;
}

coResult coClangSourceParser::ParseTypes(ParseResult& _result, const CXCursor& _cursor)
{
	coASSERT(_result.parsedTypes);
	ScopeInfo scope;
	scope.parser = this;
	scope.result = &_result;
	clang_visitChildren(_cursor, &ParseTypesVisitor, &scope);
	return true;
}

coResult coClangSourceParser::ParseType(ParseResult& _result, const CXCursor& _cursor)
{
	coParsedType* parsedType = new coParsedType();
	coDEFER() { delete parsedType; };
	parsedType->type = new coType();
	coTRY(ParseSymbol(*parsedType->type, _cursor), nullptr);
	ScopeInfo scope;
	scope.parser = this;
	scope.curType = parsedType;
	clang_visitChildren(_cursor, &ParseTypeChildrenVisitor, &scope);
	coPushBack(*_result.parsedTypes, parsedType);
	parsedType = nullptr; // Release from defer
	return true;
}

coResult coClangSourceParser::ParseField(coParsedField& _parsedField, const CXCursor& _cursor)
{
	coTRY(ParseSymbol(*_parsedField.field, _cursor), nullptr);
	const CXType type = clang_getCursorType(_cursor);
	const CXType canonicalType = clang_getCanonicalType(type);
	const CXCursor typeCursor = clang_getTypeDeclaration(canonicalType);
	const CXString typeSpelling = clang_getCursorSpelling(typeCursor);
	coDEFER() { clang_disposeString(typeSpelling); };
	_parsedField.typeName = clang_getCString(typeSpelling);
	return true;
}

coResult coClangSourceParser::ParseSymbol(coSymbol& _symbol, const CXCursor& _cursor)
{
	const CXString name = clang_getCursorSpelling(_cursor);
	coDEFER() { clang_disposeString(name); };
	_symbol.name = clang_getCString(name);

	const CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(_cursor);
	if (access == CX_CXXPublic)
		_symbol.symbolFlags |= coType::PUBLIC;
	return true;
}

coResult coClangSourceParser::ParseMethod(coParsedFunction& /*_function*/, const CXCursor& _cursor)
{
	const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
	if (staticMethod)
	{

	}
	else
	{

	}
	return true;
}

CXCursor coClangSourceParser::FindAttribute(const CXCursor& _cursor, const coConstString& _attr)
{
	switch (_cursor.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		struct Result
		{
			Result(const coConstString& _structName) : cursor(clang_getNullCursor()), structName(_structName) {}
			CXCursor cursor;
			const coConstString& structName;
		};
		static const coConstString attributePrefix("_attribute_");
		coDynamicString structName;
		structName << attributePrefix;
		structName << _attr;
		Result result(structName);
		auto AttributeVisitor = [](CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
		{
			if (_child.kind == CXCursor_StructDecl)
			{
				CXString cursorStr = clang_getCursorDisplayName(_child);
				coDEFER() { clang_disposeString(cursorStr); };
				const coConstString name = clang_getCString(cursorStr);
				Result* result = static_cast<Result*>(_clientData);
				if (name == result->structName)
				{
					result->cursor = _child;
					return CXChildVisit_Break;
				}
			}
			return CXChildVisit_Continue;
		};
		clang_visitChildren(_cursor, AttributeVisitor, &result);
		return result.cursor;
		break;
	}
	}

	return clang_getNullCursor();
}
<commit_msg>Fixed hard-coded pch directory.<commit_after>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "parser_clang/pch.h"
#include "parser_clang/coClangSourceParser.h"
#include "pattern/scope/coDefer.h"
#include "lang/result/coResult_f.h"
#include "lang/reflect/coType.h"
#include "lang/reflect/coField.h"
#include "parser/source/coParsedType.h"
#include "parser/source/coParsedField.h"
#include "container/string/coDynamicString_f.h"
#include "container/array/coDynamicArray_f.h"
#include "container/array/coConstArray_f.h"
#include "memory/allocator/coLocalAllocator.h"
#include "io/path/coPath_f.h"
#include "io/path/coPathStatus.h"

coSourceParser* coSourceParser::Create()
{
	return new coClangSourceParser();
}

coClangSourceParser::coClangSourceParser()
	: clangIndex(nullptr)
{

}

coClangSourceParser::~coClangSourceParser()
{
	if (clangIndex)
	{
		clang_disposeIndex(clangIndex);
	}
}

coResult coClangSourceParser::OnInit(const coObject::InitConfig& _config)
{
	coTRY(Super::OnInit(_config), nullptr);
	//const InitConfig& config = static_cast<const InitConfig&>(_config);
	coASSERT(!clangIndex);
	clangIndex = clang_createIndex(1, 1);

	return true;
}

coResult coClangSourceParser::ParsePrecompiledHeader(const ParseConfig& _config)
{
	coTRY(Super::ParsePrecompiledHeader(_config), nullptr);
	coLocalAllocator localAllocator(2048);

	// Check out dir
	/*{
		coPathStatus status;
		coTRY(coGetPathStatus(status, _config.outPath), nullptr);
		coTRY(status.Exists(), "The output directory does not exist: "<<_config.outPath);
	}*/

	// Build file path
	coDynamicString filePath(localAllocator);
	{
		filePath = _config.filePath;
		coNullTerminate(filePath);
	}

	// Build out path
	coDynamicString outPath(localAllocator);
	{
		coConstString baseName;
		coGetBaseName(baseName, _config.filePath);
		coJoinPaths(outPath, _config.outPath, baseName);
		outPath << ".pch";
		coNullTerminate(outPath);
	}

	// Parse
	{
		CXTranslationUnit translationUnit = nullptr;
		const coArray<const coChar*> args = { "-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-D", "coREFLECTION_PARSING", "-IJ:/CODE/core/src" };
		//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, args.count, args.data, 0, nullptr);
		const CXErrorCode parseError = clang_parseTranslationUnit2(clangIndex, filePath.data, args.data, args.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
		coTRY(parseError == CXError_Success, "Clang failed to parse the file: " << filePath);
		coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
		coDEFER() { clang_disposeTranslationUnit(translationUnit); };
		const CXSaveError saveError = static_cast<CXSaveError>(clang_saveTranslationUnit(translationUnit, outPath.data, 0));
		coTRY(parseError == CXSaveError_None, "Clang failed to save the file: " << outPath.data);
	}

	return true;
}

coResult coClangSourceParser::Parse(ParseResult& _result, const ParseConfig& _config)
{
	coTRY(Super::Parse(_result, _config), nullptr);
	coLocalAllocator localAllocator(2048);

	coDynamicString filePath(localAllocator);
	filePath = _config.filePath;
	coNullTerminate(filePath);
	CXTranslationUnit translationUnit = nullptr;
	const coArray<const coChar*> args = {"-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-D", "coREFLECTION_PARSING", "-IJ:/CODE/core/src", "-include-pch", "J:/CODE/core/build/clang/reflect/pattern/pch.pch"};
	//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, args.count, args.data, 0, nullptr);
	const CXErrorCode error = clang_parseTranslationUnit2(clangIndex, filePath.data, args.data, args.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
	coTRY(error == CXError_Success, "Clang failed to parse the file: " << filePath);
	coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
	coDEFER() { clang_disposeTranslationUnit(translationUnit); };
	CXCursor cursor = clang_getTranslationUnitCursor(translationUnit);

	if (_result.parsedTypes)
	{
		coTRY(ParseTypes(_result, cursor), "Failed to parse types");
	}
	return true;
}

CXChildVisitResult coClangSourceParser::ParseTypesVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coClangSourceParser* _this = scope->parser;
	const coBool definition = clang_isCursorDefinition(_child) != 0;
	if (!definition)
		return CXChildVisitResult::CXChildVisit_Continue;

	switch (_child.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		const CXCursor reflectedAttr = FindAttribute(_child, "Reflected");
		if (!clang_Cursor_isNull(reflectedAttr))
		{
			coASSERT(scope->result);
			if (!_this->ParseType(*scope->result, _child))
			{
				coERROR("Failed");
				return CXChildVisitResult::CXChildVisit_Break;
			}
		}
		break;
	}
	}
	return CXChildVisitResult::CXChildVisit_Continue;
}

CXChildVisitResult coClangSourceParser::ParseTypeChildrenVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coASSERT(scope);
	coClangSourceParser* _this = scope->parser;
	if (!_this->ParseTypeChild(*scope, _child))
	{
		coERROR("Failed to parse type child");
		CXChildVisitResult::CXChildVisit_Break;
	}

	return CXChildVisitResult::CXChildVisit_Continue;
}

coResult coClangSourceParser::ParseTypeChild(const ScopeInfo& scope, const CXCursor& _cursor)
{
	coTRY(scope.curType, nullptr);
	switch (_cursor.kind)
	{
	case CXCursor_StructDecl:
	{
		int x = 0;
		++x;
		break;
	}
	case CXCursor_FieldDecl:
	{
		coParsedField* parsedField = new coParsedField();
		parsedField->field = new coField();
		coDEFER() { delete parsedField; };
		coTRY(ParseField(*parsedField, _cursor), "Failed to parse field: " << parsedField->field->name);
		coPushBack(scope.curType->parsedFields, parsedField);
		parsedField = nullptr;
		break;
	}
	case CXCursor_VarDecl: // Static field
	{
		break;
	}
	case CXCursor_CXXMethod: // Both static and non-static
	{
		const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
		if (staticMethod)
		{

		}
		else
		{

		}
		break;
	}
	}
	return true;
}

coResult coClangSourceParser::ParseTypes(ParseResult& _result, const CXCursor& _cursor)
{
	coASSERT(_result.parsedTypes);
	ScopeInfo scope;
	scope.parser = this;
	scope.result = &_result;
	clang_visitChildren(_cursor, &ParseTypesVisitor, &scope);
	return true;
}

coResult coClangSourceParser::ParseType(ParseResult& _result, const CXCursor& _cursor)
{
	coParsedType* parsedType = new coParsedType();
	coDEFER() { delete parsedType; };
	parsedType->type = new coType();
	coTRY(ParseSymbol(*parsedType->type, _cursor), nullptr);
	ScopeInfo scope;
	scope.parser = this;
	scope.curType = parsedType;
	clang_visitChildren(_cursor, &ParseTypeChildrenVisitor, &scope);
	coPushBack(*_result.parsedTypes, parsedType);
	parsedType = nullptr; // Release from defer
	return true;
}

coResult coClangSourceParser::ParseField(coParsedField& _parsedField, const CXCursor& _cursor)
{
	coTRY(ParseSymbol(*_parsedField.field, _cursor), nullptr);
	const CXType type = clang_getCursorType(_cursor);
	const CXType canonicalType = clang_getCanonicalType(type);
	const CXCursor typeCursor = clang_getTypeDeclaration(canonicalType);
	const CXString typeSpelling = clang_getCursorSpelling(typeCursor);
	coDEFER() { clang_disposeString(typeSpelling); };
	_parsedField.typeName = clang_getCString(typeSpelling);
	return true;
}

coResult coClangSourceParser::ParseSymbol(coSymbol& _symbol, const CXCursor& _cursor)
{
	const CXString name = clang_getCursorSpelling(_cursor);
	coDEFER() { clang_disposeString(name); };
	_symbol.name = clang_getCString(name);

	const CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(_cursor);
	if (access == CX_CXXPublic)
		_symbol.symbolFlags |= coType::PUBLIC;
	return true;
}

coResult coClangSourceParser::ParseMethod(coParsedFunction& /*_function*/, const CXCursor& _cursor)
{
	const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
	if (staticMethod)
	{

	}
	else
	{

	}
	return true;
}

CXCursor coClangSourceParser::FindAttribute(const CXCursor& _cursor, const coConstString& _attr)
{
	switch (_cursor.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		struct Result
		{
			Result(const coConstString& _structName) : cursor(clang_getNullCursor()), structName(_structName) {}
			CXCursor cursor;
			const coConstString& structName;
		};
		static const coConstString attributePrefix("_attribute_");
		coDynamicString structName;
		structName << attributePrefix;
		structName << _attr;
		Result result(structName);
		auto AttributeVisitor = [](CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
		{
			if (_child.kind == CXCursor_StructDecl)
			{
				CXString cursorStr = clang_getCursorDisplayName(_child);
				coDEFER() { clang_disposeString(cursorStr); };
				const coConstString name = clang_getCString(cursorStr);
				Result* result = static_cast<Result*>(_clientData);
				if (name == result->structName)
				{
					result->cursor = _child;
					return CXChildVisit_Break;
				}
			}
			return CXChildVisit_Continue;
		};
		clang_visitChildren(_cursor, AttributeVisitor, &result);
		return result.cursor;
		break;
	}
	}

	return clang_getNullCursor();
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "registerhandler.h"

#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"

#include <utils/qtcassert.h>

#include <QtCore/QAbstractTableModel>
#include <QtCore/QDebug>

#include <QtGui/QColor>

using namespace Debugger;
using namespace Debugger::Internal;
using namespace Debugger::Constants;

//////////////////////////////////////////////////////////////////
//
// RegisterHandler
//
//////////////////////////////////////////////////////////////////

RegisterHandler::RegisterHandler(DebuggerEngine *engine)
  : m_engine(engine)
{
    setNumberBase(16);
}

int RegisterHandler::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_registers.size();
}

int RegisterHandler::columnCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : 2;
}

inline QString RegisterHandler::value(const Register &reg, bool padded) const
{
    bool ok = true;
    // Try to convert to number?
    const qulonglong value = reg.value.toULongLong(&ok, 0); // Autodetect format
    if (ok)
        return QString::fromAscii("%1").arg(value, (padded ? m_strlen : 0), m_base);
    // Cannot convert, return raw string.
    if (padded && reg.value.size() < m_strlen)
        return QString(m_strlen - reg.value.size(), QLatin1Char(' ')) + reg.value;
    return reg.value;
}

QVariant RegisterHandler::data(const QModelIndex &index, int role) const
{
    switch (role) {
        case EngineStateRole:
            return m_engine->state();

        case EngineCapabilitiesRole:
            return m_engine->debuggerCapabilities();

        case EngineActionsEnabledRole:
            return m_engine->debuggerActionsEnabled();

        case RegisterNumberBaseRole:
            return m_base;
    }

    if (!index.isValid() || index.row() >= m_registers.size())
        return QVariant();

    const Register &reg = m_registers.at(index.row());

    switch (role) {
    case RegisterAddressRole: {
        // Return some address associated with the register. Autodetect format
        bool ok = true;
        qulonglong value = reg.value.toULongLong(&ok, 0);
        return ok ? QVariant(QString::fromLatin1("0x") + QString::number(value, 16)) : QVariant();
    }
        break;

    case Qt::DisplayRole:
        switch (index.column()) {
        case 0: {
            const QString padding = QLatin1String("  ");
            return QVariant(padding + reg.name + padding);
        }
        case 1: // Display: Pad value for alignment
            return value(reg, true);
        } // switch column
    case Qt::EditRole: // Edit: Unpadded for editing
        return value(reg, false);
    case Qt::TextAlignmentRole:
        return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant();
    case RegisterChangedRole:
        return QVariant(reg.changed);
    default:
        break;
    }
    return QVariant();
}

QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation,
    int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        switch (section) {
            case 0: return tr("Name");
            case 1: return tr("Value (base %1)").arg(m_base);
        };
    }
    return QVariant();
}

Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const
{
    using namespace Qt;

    if (!idx.isValid())
        return ItemFlags();

    static const ItemFlags notEditable =
          ItemIsSelectable
        // | ItemIsDragEnabled
        // | ItemIsDropEnabled
        | ItemIsEnabled;

    static const ItemFlags editable = notEditable | ItemIsEditable;

    if (idx.column() == 1)
        return editable; // locals and watcher values are editable
    return  notEditable;
}

bool RegisterHandler::setData(const QModelIndex &index, const QVariant &value, int role)
{
    switch (role) {
        case RequestSetRegisterRole:
            m_engine->setRegisterValue(index.row(), value.toString());
            return true;

        case RequestReloadRegistersRole:
            m_engine->reloadRegisters();
            return true;

        case RequestShowMemoryRole:
            (void) new MemoryViewAgent(m_engine, value.toString());
            return true;

        default:
            return QAbstractTableModel::setData(index, value, role);
    }
}

void RegisterHandler::removeAll()
{
    m_registers.clear();
    reset();
}

bool RegisterHandler::isEmpty() const
{
    return m_registers.isEmpty();
}

void RegisterHandler::setRegisters(const Registers &registers)
{
    m_registers = registers;
    calculateWidth();
    reset();
}

void RegisterHandler::setAndMarkRegisters(const Registers &registers)
{
    const Registers old = m_registers;
    m_registers = registers;
    for (int i = qMin(m_registers.size(), old.size()); --i >= 0; )
        m_registers[i].changed = m_registers[i].value != old[i].value;
    calculateWidth();
    reset();
}

Registers RegisterHandler::registers() const
{
    return m_registers;
}

void RegisterHandler::calculateWidth()
{
    m_strlen = (m_base == 2 ? 64 : m_base == 8 ? 32 : m_base == 10 ? 26 : 16);
    foreach(const Register &reg, m_registers)
        if (reg.value.size() > m_strlen)
            m_strlen = reg.value.size();
    if (m_strlen > 40) // Allow for 128bit, but restrict overly ling CDB register arrays.
        m_strlen = 40;
}

void RegisterHandler::setNumberBase(int base)
{
    if (m_base != base) {
        m_base = base;
        calculateWidth();
        emit reset();
    }
}
<commit_msg>Debugger: Make register window smaller (do not pad all values).<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "registerhandler.h"

#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"

#include <utils/qtcassert.h>

#include <QtCore/QAbstractTableModel>
#include <QtCore/QDebug>

#include <QtGui/QColor>

using namespace Debugger;
using namespace Debugger::Internal;
using namespace Debugger::Constants;

//////////////////////////////////////////////////////////////////
//
// RegisterHandler
//
//////////////////////////////////////////////////////////////////

RegisterHandler::RegisterHandler(DebuggerEngine *engine)
  : m_engine(engine)
{
    setNumberBase(16);
}

int RegisterHandler::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_registers.size();
}

int RegisterHandler::columnCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : 2;
}

inline QString RegisterHandler::value(const Register &reg, bool padded) const
{
    bool ok = true;
    // Try to convert to number?
    const qulonglong value = reg.value.toULongLong(&ok, 0); // Autodetect format
    if (ok)
        return QString::fromAscii("%1").arg(value, (padded ? m_strlen : 0), m_base);
    // Cannot convert, return raw string.
    if (padded && reg.value.size() < m_strlen)
        return QString(m_strlen - reg.value.size(), QLatin1Char(' ')) + reg.value;
    return reg.value;
}

QVariant RegisterHandler::data(const QModelIndex &index, int role) const
{
    switch (role) {
        case EngineStateRole:
            return m_engine->state();

        case EngineCapabilitiesRole:
            return m_engine->debuggerCapabilities();

        case EngineActionsEnabledRole:
            return m_engine->debuggerActionsEnabled();

        case RegisterNumberBaseRole:
            return m_base;
    }

    if (!index.isValid() || index.row() >= m_registers.size())
        return QVariant();

    const Register &reg = m_registers.at(index.row());

    switch (role) {
    case RegisterAddressRole: {
        // Return some address associated with the register. Autodetect format
        bool ok = true;
        qulonglong value = reg.value.toULongLong(&ok, 0);
        return ok ? QVariant(QString::fromLatin1("0x") + QString::number(value, 16)) : QVariant();
    }
        break;

    case Qt::DisplayRole:
        switch (index.column()) {
        case 0: {
            const QString padding = QLatin1String("  ");
            return QVariant(padding + reg.name + padding);
        }
        case 1: // Display: Pad value for alignment
            return value(reg, true);
        } // switch column
    case Qt::EditRole: // Edit: Unpadded for editing
        return value(reg, false);
    case Qt::TextAlignmentRole:
        return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant();
    case RegisterChangedRole:
        return QVariant(reg.changed);
    default:
        break;
    }
    return QVariant();
}

QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation,
    int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        switch (section) {
            case 0: return tr("Name");
            case 1: return tr("Value (base %1)").arg(m_base);
        };
    }
    return QVariant();
}

Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const
{
    using namespace Qt;

    if (!idx.isValid())
        return ItemFlags();

    static const ItemFlags notEditable =
          ItemIsSelectable
        // | ItemIsDragEnabled
        // | ItemIsDropEnabled
        | ItemIsEnabled;

    static const ItemFlags editable = notEditable | ItemIsEditable;

    if (idx.column() == 1)
        return editable; // locals and watcher values are editable
    return  notEditable;
}

bool RegisterHandler::setData(const QModelIndex &index, const QVariant &value, int role)
{
    switch (role) {
        case RequestSetRegisterRole:
            m_engine->setRegisterValue(index.row(), value.toString());
            return true;

        case RequestReloadRegistersRole:
            m_engine->reloadRegisters();
            return true;

        case RequestShowMemoryRole:
            (void) new MemoryViewAgent(m_engine, value.toString());
            return true;

        default:
            return QAbstractTableModel::setData(index, value, role);
    }
}

void RegisterHandler::removeAll()
{
    m_registers.clear();
    reset();
}

bool RegisterHandler::isEmpty() const
{
    return m_registers.isEmpty();
}

void RegisterHandler::setRegisters(const Registers &registers)
{
    m_registers = registers;
    calculateWidth();
    reset();
}

void RegisterHandler::setAndMarkRegisters(const Registers &registers)
{
    const Registers old = m_registers;
    m_registers = registers;
    for (int i = qMin(m_registers.size(), old.size()); --i >= 0; )
        m_registers[i].changed = m_registers[i].value != old[i].value;
    calculateWidth();
    reset();
}

Registers RegisterHandler::registers() const
{
    return m_registers;
}

void RegisterHandler::calculateWidth()
{
    m_strlen = (m_base == 2 ? 64 : m_base == 8 ? 32 : m_base == 10 ? 26 : 16);
}

void RegisterHandler::setNumberBase(int base)
{
    if (m_base != base) {
        m_base = base;
        calculateWidth();
        emit reset();
    }
}
<|endoftext|>