<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Open Source Robotics Foundation
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * 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.
 *   * Neither the name of the Open Source Robotics Foundation
 *     nor the names of its contributors may be
 *     used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  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 OWNER 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.
 *********************************************************************/

/* Author: Hariharasudan Malaichamee
 * Author: Dave Coleman
 Desc:   Customized the default gazebo_ros_control_plugin.cpp
 */

// Overload the default plugin
#include <gazebo_ros_control/gazebo_ros_control_plugin.h>

// Controller Manager
#include <controller_manager_msgs/SwitchController.h>

// Baxter
#include <baxter_core_msgs/JointCommand.h>
#include <baxter_core_msgs/AssemblyState.h>
#include <baxter_core_msgs/HeadPanCommand.h>

namespace baxter_gazebo_plugin {

class BaxterGazeboRosControlPlugin :
    public gazebo_ros_control::GazeboRosControlPlugin {
 private:
  ros::Subscriber left_command_mode_sub_;
  ros::Subscriber right_command_mode_sub_;
  ros::Subscriber robot_state_sub_;
  ros::Subscriber head_state_sub;

  // Rate to publish assembly state
  ros::Timer timer_;

  // Cache the message
  baxter_core_msgs::AssemblyState assembly_state_;

  // use this as flag to indicate current mode
  baxter_core_msgs::JointCommand right_command_mode_,left_command_mode_;

  boost::mutex mtx_;  // mutex for re-entrent calls to modeCommandCallback
  bool enable_cmd, is_disabled, head_is_started;  // enabled tracks the current status of the robot that is being published & is_disabled keeps track of the action taken

 public:

  void Load(gazebo::physics::ModelPtr parent, sdf::ElementPtr sdf) {
    // Load parent class first
    GazeboRosControlPlugin::Load(parent, sdf);

    // Baxter customizations:
    ROS_INFO_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                          "Loading Baxter specific simulation components");

    // Subscribe to a topic that switches' Baxter's msgs
    left_command_mode_sub_ =
        nh_.subscribe < baxter_core_msgs::JointCommand
            > ("/robot/limb/left/joint_command", 1, &BaxterGazeboRosControlPlugin::leftModeCommandCallback, this);
    right_command_mode_sub_ =
        nh_.subscribe < baxter_core_msgs::JointCommand
            > ("/robot/limb/right/joint_command", 1, &BaxterGazeboRosControlPlugin::rightModeCommandCallback, this);
    head_state_sub =
        nh_.subscribe < baxter_core_msgs::HeadPanCommand
            > ("/robot/head/command_head_pan", 1, &BaxterGazeboRosControlPlugin::headCommandCallback, this);

    //Subscribe to the topic that publishes the robot's state
    robot_state_sub_ =
        nh_.subscribe < baxter_core_msgs::AssemblyState
            > ("/robot/state", 1, &BaxterGazeboRosControlPlugin::enableCommandCallback, this);

    enable_cmd = false;
    is_disabled = false;
    right_command_mode_.mode = -1;
    left_command_mode_.mode = -1;
    head_is_started = false;
  }

  void enableCommandCallback(const baxter_core_msgs::AssemblyState msg) {
    enable_cmd = msg.enabled;
    std::vector < std::string > start_controllers;
    std::vector < std::string > stop_controllers;

    // Check if we got disable signal and if the controllers are not already disabled
    if (!enable_cmd && !is_disabled) {
      stop_controllers.push_back("left_joint_effort_controller");
      stop_controllers.push_back("left_joint_velocity_controller");
      stop_controllers.push_back("left_joint_position_controller");
      stop_controllers.push_back("right_joint_effort_controller");
      stop_controllers.push_back("right_joint_velocity_controller");
      stop_controllers.push_back("right_joint_position_controller");
      stop_controllers.push_back("head_position_controller");

      if (!controller_manager_->switchController(
          start_controllers, stop_controllers,
          controller_manager_msgs::SwitchController::Request::BEST_EFFORT)) {
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Failed to switch controllers");
      } else {
        //Resetting the command modes to the initial configuration
	ROS_INFO("Robot is disabled");
	ROS_INFO("Gravity compensation was turned off");
        right_command_mode_.mode = -1;
        left_command_mode_.mode = -1;
        head_is_started=false;
        is_disabled = true;
      }
    }
  }

  void headCommandCallback(
      const baxter_core_msgs::HeadPanCommand msg) {
    if (!head_is_started && enable_cmd){
      std::vector < std::string > start_controllers;
      std::vector < std::string > stop_controllers;

      start_controllers.push_back("head_position_controller");
      if (!controller_manager_->switchController(
          start_controllers, stop_controllers,
          controller_manager_msgs::SwitchController::Request::STRICT)) {
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Failed to switch controllers");
      }
      else {
        ROS_INFO("Robot is enabled");
        ROS_INFO("Head controller was successfully started");
        ROS_INFO("Gravity compensation was turned on");
        head_is_started=true;
	      is_disabled=false;
      }
    }
    else
      return;
  }
  void leftModeCommandCallback(
      const baxter_core_msgs::JointCommandConstPtr& msg) {

    //Check if we already received this command for this arm and bug out if so
    if (left_command_mode_.mode == msg->mode) {
      return;
    } else if (enable_cmd) {
      left_command_mode_.mode = msg->mode;  //cache last mode
      modeCommandCallback(msg, "left");
    } else {
      ROS_WARN_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                            "Enable the robot");
      return;
    }
  }

  void rightModeCommandCallback(
      const baxter_core_msgs::JointCommandConstPtr& msg) {

    //Check if we already received this command for this arm and bug out if so
    if (right_command_mode_.mode == msg->mode) {
      return;
    } else if (enable_cmd) {
      right_command_mode_.mode = msg->mode;  //cache last mode
      modeCommandCallback(msg, "right");
    } else {
      ROS_WARN_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                            "Enable the robot");
      return;
    }
  }

  void modeCommandCallback(const baxter_core_msgs::JointCommandConstPtr& msg,
                           const std::string& side) {
    ROS_DEBUG_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                           "Switching command mode for side " << side);

    //lock out other thread(s) which are getting called back via ros.
    boost::lock_guard < boost::mutex > guard(mtx_);

    std::vector < std::string > start_controllers;
    std::vector < std::string > stop_controllers;
    std::string start,stop;

    switch (msg->mode) {
      case baxter_core_msgs::JointCommand::POSITION_MODE:
        start_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_velocity_controller");
        stop_controllers.push_back(side + "_joint_effort_controller");
        start=side+"_joint_position_controller";
	stop=side+"_joint_velocity_controller and "+side+"_joint_effort_controller";
        break;
      case baxter_core_msgs::JointCommand::RAW_POSITION_MODE:
        start_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_velocity_controller");
        stop_controllers.push_back(side + "_joint_effort_controller");
        start=side+"_joint_position_controller";
	stop=side+"_joint_velocity_controller and "+side+"_joint_effort_controller";
        break;
      case baxter_core_msgs::JointCommand::VELOCITY_MODE:
        start_controllers.push_back(side + "_joint_velocity_controller");
        stop_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_effort_controller");
        start=side+"_joint_velocity_controller";
	stop=side+"_joint_position_controller and "+side+"_joint_effort_controller";
        break;
      case baxter_core_msgs::JointCommand::TORQUE_MODE:
        start_controllers.push_back(side + "_joint_effort_controller");
        stop_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_velocity_controller");
        start=side+"_joint_position_controller";
	stop=side+"_joint_velocity_controller and "+side+"_joint_velocity_controller";
        break;
      default:
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Unknown command mode " << msg->mode);
        return;
    }
    //Checks if we have already disabled the controllers
    /** \brief Switch multiple controllers simultaneously.
     *
     * \param start_controllers A vector of controller names to be started
     * \param stop_controllers A vector of controller names to be stopped
     * \param strictness How important it is that the requested controllers are
     * started and stopped.  The levels are defined in the
     * controller_manager_msgs/SwitchControllers service as either \c BEST_EFFORT
     * or \c STRICT.  \c BEST_EFFORT means that \ref switchController can still
     * succeed if a non-existant controller is requested to be stopped or started.
     */
    if (!controller_manager_->switchController(
        start_controllers, stop_controllers,
        controller_manager_msgs::SwitchController::Request::STRICT)) {
      ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                             "Failed to switch controllers");
    }
    else {
       is_disabled=false;
       ROS_INFO("Robot is enabled");
       ROS_INFO_STREAM(start<<" was started and "<<stop<<" were stopped succesfully");
       ROS_INFO("Gravity compensation was turned on");
    }
  }

};

// Register this plugin with the simulator
GZ_REGISTER_MODEL_PLUGIN (BaxterGazeboRosControlPlugin);
}  // namespace
<commit_msg>Modified case statement to support raw position mode<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Open Source Robotics Foundation
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * 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.
 *   * Neither the name of the Open Source Robotics Foundation
 *     nor the names of its contributors may be
 *     used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  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 OWNER 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.
 *********************************************************************/

/* Author: Hariharasudan Malaichamee
 * Author: Dave Coleman
 Desc:   Customized the default gazebo_ros_control_plugin.cpp
 */

// Overload the default plugin
#include <gazebo_ros_control/gazebo_ros_control_plugin.h>

// Controller Manager
#include <controller_manager_msgs/SwitchController.h>

// Baxter
#include <baxter_core_msgs/JointCommand.h>
#include <baxter_core_msgs/AssemblyState.h>
#include <baxter_core_msgs/HeadPanCommand.h>

namespace baxter_gazebo_plugin {

class BaxterGazeboRosControlPlugin :
    public gazebo_ros_control::GazeboRosControlPlugin {
 private:
  ros::Subscriber left_command_mode_sub_;
  ros::Subscriber right_command_mode_sub_;
  ros::Subscriber robot_state_sub_;
  ros::Subscriber head_state_sub;

  // Rate to publish assembly state
  ros::Timer timer_;

  // Cache the message
  baxter_core_msgs::AssemblyState assembly_state_;

  // use this as flag to indicate current mode
  baxter_core_msgs::JointCommand right_command_mode_,left_command_mode_;

  boost::mutex mtx_;  // mutex for re-entrent calls to modeCommandCallback
  bool enable_cmd, is_disabled, head_is_started;  // enabled tracks the current status of the robot that is being published & is_disabled keeps track of the action taken

 public:

  void Load(gazebo::physics::ModelPtr parent, sdf::ElementPtr sdf) {
    // Load parent class first
    GazeboRosControlPlugin::Load(parent, sdf);

    // Baxter customizations:
    ROS_INFO_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                          "Loading Baxter specific simulation components");

    // Subscribe to a topic that switches' Baxter's msgs
    left_command_mode_sub_ =
        nh_.subscribe < baxter_core_msgs::JointCommand
            > ("/robot/limb/left/joint_command", 1, &BaxterGazeboRosControlPlugin::leftModeCommandCallback, this);
    right_command_mode_sub_ =
        nh_.subscribe < baxter_core_msgs::JointCommand
            > ("/robot/limb/right/joint_command", 1, &BaxterGazeboRosControlPlugin::rightModeCommandCallback, this);
    head_state_sub =
        nh_.subscribe < baxter_core_msgs::HeadPanCommand
            > ("/robot/head/command_head_pan", 1, &BaxterGazeboRosControlPlugin::headCommandCallback, this);

    //Subscribe to the topic that publishes the robot's state
    robot_state_sub_ =
        nh_.subscribe < baxter_core_msgs::AssemblyState
            > ("/robot/state", 1, &BaxterGazeboRosControlPlugin::enableCommandCallback, this);

    enable_cmd = false;
    is_disabled = false;
    right_command_mode_.mode = -1;
    left_command_mode_.mode = -1;
    head_is_started = false;
  }

  void enableCommandCallback(const baxter_core_msgs::AssemblyState msg) {
    enable_cmd = msg.enabled;
    std::vector < std::string > start_controllers;
    std::vector < std::string > stop_controllers;

    // Check if we got disable signal and if the controllers are not already disabled
    if (!enable_cmd && !is_disabled) {
      stop_controllers.push_back("left_joint_effort_controller");
      stop_controllers.push_back("left_joint_velocity_controller");
      stop_controllers.push_back("left_joint_position_controller");
      stop_controllers.push_back("right_joint_effort_controller");
      stop_controllers.push_back("right_joint_velocity_controller");
      stop_controllers.push_back("right_joint_position_controller");
      stop_controllers.push_back("head_position_controller");

      if (!controller_manager_->switchController(
          start_controllers, stop_controllers,
          controller_manager_msgs::SwitchController::Request::BEST_EFFORT)) {
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Failed to switch controllers");
      } else {
        //Resetting the command modes to the initial configuration
	ROS_INFO("Robot is disabled");
	ROS_INFO("Gravity compensation was turned off");
        right_command_mode_.mode = -1;
        left_command_mode_.mode = -1;
        head_is_started=false;
        is_disabled = true;
      }
    }
  }

  void headCommandCallback(
      const baxter_core_msgs::HeadPanCommand msg) {
    if (!head_is_started && enable_cmd){
      std::vector < std::string > start_controllers;
      std::vector < std::string > stop_controllers;

      start_controllers.push_back("head_position_controller");
      if (!controller_manager_->switchController(
          start_controllers, stop_controllers,
          controller_manager_msgs::SwitchController::Request::STRICT)) {
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Failed to switch controllers");
      }
      else {
        ROS_INFO("Robot is enabled");
        ROS_INFO("Head controller was successfully started");
        ROS_INFO("Gravity compensation was turned on");
        head_is_started=true;
	      is_disabled=false;
      }
    }
    else
      return;
  }
  void leftModeCommandCallback(
      const baxter_core_msgs::JointCommandConstPtr& msg) {

    //Check if we already received this command for this arm and bug out if so
    if (left_command_mode_.mode == msg->mode) {
      return;
    } else if (enable_cmd) {
      left_command_mode_.mode = msg->mode;  //cache last mode
      modeCommandCallback(msg, "left");
    } else {
      ROS_WARN_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                            "Enable the robot");
      return;
    }
  }

  void rightModeCommandCallback(
      const baxter_core_msgs::JointCommandConstPtr& msg) {

    //Check if we already received this command for this arm and bug out if so
    if (right_command_mode_.mode == msg->mode) {
      return;
    } else if (enable_cmd) {
      right_command_mode_.mode = msg->mode;  //cache last mode
      modeCommandCallback(msg, "right");
    } else {
      ROS_WARN_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                            "Enable the robot");
      return;
    }
  }

  void modeCommandCallback(const baxter_core_msgs::JointCommandConstPtr& msg,
                           const std::string& side) {
    ROS_DEBUG_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                           "Switching command mode for side " << side);

    //lock out other thread(s) which are getting called back via ros.
    boost::lock_guard < boost::mutex > guard(mtx_);

    std::vector < std::string > start_controllers;
    std::vector < std::string > stop_controllers;
    std::string start,stop;

    switch (msg->mode) {
      case baxter_core_msgs::JointCommand::POSITION_MODE:
      case baxter_core_msgs::JointCommand::RAW_POSITION_MODE:
        start_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_velocity_controller");
        stop_controllers.push_back(side + "_joint_effort_controller");
        start=side+"_joint_position_controller";
	stop=side+"_joint_velocity_controller and "+side+"_joint_effort_controller";
        break;
      case baxter_core_msgs::JointCommand::VELOCITY_MODE:
        start_controllers.push_back(side + "_joint_velocity_controller");
        stop_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_effort_controller");
        start=side+"_joint_velocity_controller";
	stop=side+"_joint_position_controller and "+side+"_joint_effort_controller";
        break;
      case baxter_core_msgs::JointCommand::TORQUE_MODE:
        start_controllers.push_back(side + "_joint_effort_controller");
        stop_controllers.push_back(side + "_joint_position_controller");
        stop_controllers.push_back(side + "_joint_velocity_controller");
        start=side+"_joint_position_controller";
	stop=side+"_joint_velocity_controller and "+side+"_joint_velocity_controller";
        break;
      default:
        ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                               "Unknown command mode " << msg->mode);
        return;
    }
    //Checks if we have already disabled the controllers
    /** \brief Switch multiple controllers simultaneously.
     *
     * \param start_controllers A vector of controller names to be started
     * \param stop_controllers A vector of controller names to be stopped
     * \param strictness How important it is that the requested controllers are
     * started and stopped.  The levels are defined in the
     * controller_manager_msgs/SwitchControllers service as either \c BEST_EFFORT
     * or \c STRICT.  \c BEST_EFFORT means that \ref switchController can still
     * succeed if a non-existant controller is requested to be stopped or started.
     */
    if (!controller_manager_->switchController(
        start_controllers, stop_controllers,
        controller_manager_msgs::SwitchController::Request::STRICT)) {
      ROS_ERROR_STREAM_NAMED("baxter_gazebo_ros_control_plugin",
                             "Failed to switch controllers");
    }
    else {
       is_disabled=false;
       ROS_INFO("Robot is enabled");
       ROS_INFO_STREAM(start<<" was started and "<<stop<<" were stopped succesfully");
       ROS_INFO("Gravity compensation was turned on");
    }
  }

};

// Register this plugin with the simulator
GZ_REGISTER_MODEL_PLUGIN (BaxterGazeboRosControlPlugin);
}  // namespace
<|endoftext|>


<commit_before>/*
 *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/base/bitbuffer.h"
#include "webrtc/base/bytebuffer.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"

namespace rtc {

TEST(BitBufferTest, ConsumeBits) {
  const uint8 bytes[64] = {0};
  BitBuffer buffer(bytes, 32);
  uint64 total_bits = 32 * 8;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(3));
  total_bits -= 3;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(3));
  total_bits -= 3;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(15));
  total_bits -= 15;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(37));
  total_bits -= 37;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());

  EXPECT_FALSE(buffer.ConsumeBits(32 * 8));
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
}

TEST(BitBufferTest, ReadBytesAligned) {
  const uint8 bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89};
  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0x0Au, val8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xBCu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xDEF1u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x23456789u, val32);
}

TEST(BitBufferTest, ReadBytesOffset4) {
  const uint8 bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0x0A};
  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 9);
  EXPECT_TRUE(buffer.ConsumeBits(4));

  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xABu, val8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xCDu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xEF12u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x34567890u, val32);
}

TEST(BitBufferTest, ReadBytesOffset3) {
  // The pattern we'll check against is counting down from 0b1111. It looks
  // weird here because it's all offset by 3.
  // Byte pattern is:
  //    56701234
  //  0b00011111,
  //  0b11011011,
  //  0b10010111,
  //  0b01010011,
  //  0b00001110,
  //  0b11001010,
  //  0b10000110,
  //  0b01000010
  //       xxxxx <-- last 5 bits unused.

  // The bytes. It almost looks like counting down by two at a time, except the
  // jump at 5->3->0, since that's when the high bit is turned off.
  const uint8 bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42};

  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 8);
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xFEu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xDCBAu, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x98765432u, val32);
  // 5 bits left unread. Not enough to read a uint8.
  EXPECT_EQ(5u, buffer.RemainingBitCount());
  EXPECT_FALSE(buffer.ReadUInt8(&val8));
}

TEST(BitBufferTest, ReadBits) {
  // Bit values are:
  //  0b01001101,
  //  0b00110010
  const uint8 bytes[] = {0x4D, 0x32};
  uint32_t val;
  BitBuffer buffer(bytes, 2);
  EXPECT_TRUE(buffer.ReadBits(&val, 3));
  // 0b010
  EXPECT_EQ(0x2u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  // 0b01
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 7));
  // 0b1010011
  EXPECT_EQ(0x53u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  // 0b00
  EXPECT_EQ(0x0u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  // 0b1
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  // 0b0
  EXPECT_EQ(0x0u, val);

  EXPECT_FALSE(buffer.ReadBits(&val, 1));
}

TEST(BitBufferTest, SetOffsetValues) {
  uint8 bytes[4] = {0};
  BitBufferWriter buffer(bytes, 4);

  size_t byte_offset, bit_offset;
  // Bit offsets are [0,7].
  EXPECT_TRUE(buffer.Seek(0, 0));
  EXPECT_TRUE(buffer.Seek(0, 7));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(0u, byte_offset);
  EXPECT_EQ(7u, bit_offset);
  EXPECT_FALSE(buffer.Seek(0, 8));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(0u, byte_offset);
  EXPECT_EQ(7u, bit_offset);
  // Byte offsets are [0,length]. At byte offset length, the bit offset must be
  // 0.
  EXPECT_TRUE(buffer.Seek(0, 0));
  EXPECT_TRUE(buffer.Seek(2, 4));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(2u, byte_offset);
  EXPECT_EQ(4u, bit_offset);
  EXPECT_TRUE(buffer.Seek(4, 0));
  EXPECT_FALSE(buffer.Seek(5, 0));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(4u, byte_offset);
  EXPECT_EQ(0u, bit_offset);
  EXPECT_FALSE(buffer.Seek(4, 1));

  // Passing a NULL out parameter is death.
  EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, NULL), "");
}

uint64 GolombEncoded(uint32 val) {
  val++;
  uint32 bit_counter = val;
  uint64 bit_count = 0;
  while (bit_counter > 0) {
    bit_count++;
    bit_counter >>= 1;
  }
  return static_cast<uint64>(val) << (64 - (bit_count * 2 - 1));
}

TEST(BitBufferTest, GolombUint32Values) {
  ByteBuffer byteBuffer;
  byteBuffer.Resize(16);
  BitBuffer buffer(reinterpret_cast<const uint8*>(byteBuffer.Data()),
                   byteBuffer.Capacity());
  // Test over the uint32 range with a large enough step that the test doesn't
  // take forever. Around 20,000 iterations should do.
  const int kStep = std::numeric_limits<uint32>::max() / 20000;
  for (uint32 i = 0; i < std::numeric_limits<uint32>::max() - kStep;
       i += kStep) {
    uint64 encoded_val = GolombEncoded(i);
    byteBuffer.Clear();
    byteBuffer.WriteUInt64(encoded_val);
    uint32 decoded_val;
    EXPECT_TRUE(buffer.Seek(0, 0));
    EXPECT_TRUE(buffer.ReadExponentialGolomb(&decoded_val));
    EXPECT_EQ(i, decoded_val);
  }
}

TEST(BitBufferTest, NoGolombOverread) {
  const uint8 bytes[] = {0x00, 0xFF, 0xFF};
  // Make sure the bit buffer correctly enforces byte length on golomb reads.
  // If it didn't, the above buffer would be valid at 3 bytes.
  BitBuffer buffer(bytes, 1);
  uint32 decoded_val;
  EXPECT_FALSE(buffer.ReadExponentialGolomb(&decoded_val));

  BitBuffer longer_buffer(bytes, 2);
  EXPECT_FALSE(longer_buffer.ReadExponentialGolomb(&decoded_val));

  BitBuffer longest_buffer(bytes, 3);
  EXPECT_TRUE(longest_buffer.ReadExponentialGolomb(&decoded_val));
  // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the
  // result is 0x01FF - 1 = 0x01FE.
  EXPECT_EQ(0x01FEu, decoded_val);
}

TEST(BitBufferWriterTest, SymmetricReadWrite) {
  uint8 bytes[16] = {0};
  BitBufferWriter buffer(bytes, 4);

  // Write some bit data at various sizes.
  EXPECT_TRUE(buffer.WriteBits(0x2u, 3));
  EXPECT_TRUE(buffer.WriteBits(0x1u, 2));
  EXPECT_TRUE(buffer.WriteBits(0x53u, 7));
  EXPECT_TRUE(buffer.WriteBits(0x0u, 2));
  EXPECT_TRUE(buffer.WriteBits(0x1u, 1));
  EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17));
  // That should be all that fits in the buffer.
  EXPECT_FALSE(buffer.WriteBits(1, 1));

  EXPECT_TRUE(buffer.Seek(0, 0));
  uint32 val;
  EXPECT_TRUE(buffer.ReadBits(&val, 3));
  EXPECT_EQ(0x2u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 7));
  EXPECT_EQ(0x53u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  EXPECT_EQ(0x0u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 17));
  EXPECT_EQ(0x1ABCDu, val);
  // And there should be nothing left.
  EXPECT_FALSE(buffer.ReadBits(&val, 1));
}

TEST(BitBufferWriterTest, SymmetricBytesMisaligned) {
  uint8 bytes[16] = {0};
  BitBufferWriter buffer(bytes, 16);

  // Offset 3, to get things misaligned.
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.WriteUInt8(0x12u));
  EXPECT_TRUE(buffer.WriteUInt16(0x3456u));
  EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu));

  buffer.Seek(0, 3);
  uint8 val8;
  uint16 val16;
  uint32 val32;
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0x12u, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0x3456u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x789ABCDEu, val32);
}

TEST(BitBufferWriterTest, SymmetricGolomb) {
  char test_string[] = "my precious";
  uint8 bytes[64] = {0};
  BitBufferWriter buffer(bytes, 64);
  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
    EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i]));
  }
  buffer.Seek(0, 0);
  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
    uint32 val;
    EXPECT_TRUE(buffer.ReadExponentialGolomb(&val));
    EXPECT_LE(val, std::numeric_limits<uint8>::max());
    EXPECT_EQ(test_string[i], static_cast<char>(val));
  }
}

TEST(BitBufferWriterTest, WriteClearsBits) {
  uint8 bytes[] = {0xFF, 0xFF};
  BitBufferWriter buffer(bytes, 2);
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.WriteBits(0, 1));
  EXPECT_EQ(0xEFu, bytes[0]);
  EXPECT_TRUE(buffer.WriteBits(0, 3));
  EXPECT_EQ(0xE1u, bytes[0]);
  EXPECT_TRUE(buffer.WriteBits(0, 2));
  EXPECT_EQ(0xE0u, bytes[0]);
  EXPECT_EQ(0x7F, bytes[1]);
}

}  // namespace rtc
<commit_msg>Disable the EXPECT_DEATH check in bitbuffer on Android<commit_after>/*
 *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/base/bitbuffer.h"
#include "webrtc/base/bytebuffer.h"
#include "webrtc/base/common.h"
#include "webrtc/base/gunit.h"

namespace rtc {

TEST(BitBufferTest, ConsumeBits) {
  const uint8 bytes[64] = {0};
  BitBuffer buffer(bytes, 32);
  uint64 total_bits = 32 * 8;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(3));
  total_bits -= 3;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(3));
  total_bits -= 3;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(15));
  total_bits -= 15;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
  EXPECT_TRUE(buffer.ConsumeBits(37));
  total_bits -= 37;
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());

  EXPECT_FALSE(buffer.ConsumeBits(32 * 8));
  EXPECT_EQ(total_bits, buffer.RemainingBitCount());
}

TEST(BitBufferTest, ReadBytesAligned) {
  const uint8 bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89};
  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0x0Au, val8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xBCu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xDEF1u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x23456789u, val32);
}

TEST(BitBufferTest, ReadBytesOffset4) {
  const uint8 bytes[] = {0x0A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0x0A};
  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 9);
  EXPECT_TRUE(buffer.ConsumeBits(4));

  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xABu, val8);
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xCDu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xEF12u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x34567890u, val32);
}

TEST(BitBufferTest, ReadBytesOffset3) {
  // The pattern we'll check against is counting down from 0b1111. It looks
  // weird here because it's all offset by 3.
  // Byte pattern is:
  //    56701234
  //  0b00011111,
  //  0b11011011,
  //  0b10010111,
  //  0b01010011,
  //  0b00001110,
  //  0b11001010,
  //  0b10000110,
  //  0b01000010
  //       xxxxx <-- last 5 bits unused.

  // The bytes. It almost looks like counting down by two at a time, except the
  // jump at 5->3->0, since that's when the high bit is turned off.
  const uint8 bytes[] = {0x1F, 0xDB, 0x97, 0x53, 0x0E, 0xCA, 0x86, 0x42};

  uint8 val8;
  uint16 val16;
  uint32 val32;
  BitBuffer buffer(bytes, 8);
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0xFEu, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0xDCBAu, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x98765432u, val32);
  // 5 bits left unread. Not enough to read a uint8.
  EXPECT_EQ(5u, buffer.RemainingBitCount());
  EXPECT_FALSE(buffer.ReadUInt8(&val8));
}

TEST(BitBufferTest, ReadBits) {
  // Bit values are:
  //  0b01001101,
  //  0b00110010
  const uint8 bytes[] = {0x4D, 0x32};
  uint32_t val;
  BitBuffer buffer(bytes, 2);
  EXPECT_TRUE(buffer.ReadBits(&val, 3));
  // 0b010
  EXPECT_EQ(0x2u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  // 0b01
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 7));
  // 0b1010011
  EXPECT_EQ(0x53u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  // 0b00
  EXPECT_EQ(0x0u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  // 0b1
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  // 0b0
  EXPECT_EQ(0x0u, val);

  EXPECT_FALSE(buffer.ReadBits(&val, 1));
}

TEST(BitBufferTest, SetOffsetValues) {
  uint8 bytes[4] = {0};
  BitBufferWriter buffer(bytes, 4);

  size_t byte_offset, bit_offset;
  // Bit offsets are [0,7].
  EXPECT_TRUE(buffer.Seek(0, 0));
  EXPECT_TRUE(buffer.Seek(0, 7));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(0u, byte_offset);
  EXPECT_EQ(7u, bit_offset);
  EXPECT_FALSE(buffer.Seek(0, 8));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(0u, byte_offset);
  EXPECT_EQ(7u, bit_offset);
  // Byte offsets are [0,length]. At byte offset length, the bit offset must be
  // 0.
  EXPECT_TRUE(buffer.Seek(0, 0));
  EXPECT_TRUE(buffer.Seek(2, 4));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(2u, byte_offset);
  EXPECT_EQ(4u, bit_offset);
  EXPECT_TRUE(buffer.Seek(4, 0));
  EXPECT_FALSE(buffer.Seek(5, 0));
  buffer.GetCurrentOffset(&byte_offset, &bit_offset);
  EXPECT_EQ(4u, byte_offset);
  EXPECT_EQ(0u, bit_offset);
  EXPECT_FALSE(buffer.Seek(4, 1));

  // Disable death test on Android because it relies on fork() and doesn't play
  // nicely.
#if !defined(WEBRTC_ANDROID)
  // Passing a NULL out parameter is death.
  EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, NULL), "");
#endif
}

uint64 GolombEncoded(uint32 val) {
  val++;
  uint32 bit_counter = val;
  uint64 bit_count = 0;
  while (bit_counter > 0) {
    bit_count++;
    bit_counter >>= 1;
  }
  return static_cast<uint64>(val) << (64 - (bit_count * 2 - 1));
}

TEST(BitBufferTest, GolombUint32Values) {
  ByteBuffer byteBuffer;
  byteBuffer.Resize(16);
  BitBuffer buffer(reinterpret_cast<const uint8*>(byteBuffer.Data()),
                   byteBuffer.Capacity());
  // Test over the uint32 range with a large enough step that the test doesn't
  // take forever. Around 20,000 iterations should do.
  const int kStep = std::numeric_limits<uint32>::max() / 20000;
  for (uint32 i = 0; i < std::numeric_limits<uint32>::max() - kStep;
       i += kStep) {
    uint64 encoded_val = GolombEncoded(i);
    byteBuffer.Clear();
    byteBuffer.WriteUInt64(encoded_val);
    uint32 decoded_val;
    EXPECT_TRUE(buffer.Seek(0, 0));
    EXPECT_TRUE(buffer.ReadExponentialGolomb(&decoded_val));
    EXPECT_EQ(i, decoded_val);
  }
}

TEST(BitBufferTest, NoGolombOverread) {
  const uint8 bytes[] = {0x00, 0xFF, 0xFF};
  // Make sure the bit buffer correctly enforces byte length on golomb reads.
  // If it didn't, the above buffer would be valid at 3 bytes.
  BitBuffer buffer(bytes, 1);
  uint32 decoded_val;
  EXPECT_FALSE(buffer.ReadExponentialGolomb(&decoded_val));

  BitBuffer longer_buffer(bytes, 2);
  EXPECT_FALSE(longer_buffer.ReadExponentialGolomb(&decoded_val));

  BitBuffer longest_buffer(bytes, 3);
  EXPECT_TRUE(longest_buffer.ReadExponentialGolomb(&decoded_val));
  // Golomb should have read 9 bits, so 0x01FF, and since it is golomb, the
  // result is 0x01FF - 1 = 0x01FE.
  EXPECT_EQ(0x01FEu, decoded_val);
}

TEST(BitBufferWriterTest, SymmetricReadWrite) {
  uint8 bytes[16] = {0};
  BitBufferWriter buffer(bytes, 4);

  // Write some bit data at various sizes.
  EXPECT_TRUE(buffer.WriteBits(0x2u, 3));
  EXPECT_TRUE(buffer.WriteBits(0x1u, 2));
  EXPECT_TRUE(buffer.WriteBits(0x53u, 7));
  EXPECT_TRUE(buffer.WriteBits(0x0u, 2));
  EXPECT_TRUE(buffer.WriteBits(0x1u, 1));
  EXPECT_TRUE(buffer.WriteBits(0x1ABCDu, 17));
  // That should be all that fits in the buffer.
  EXPECT_FALSE(buffer.WriteBits(1, 1));

  EXPECT_TRUE(buffer.Seek(0, 0));
  uint32 val;
  EXPECT_TRUE(buffer.ReadBits(&val, 3));
  EXPECT_EQ(0x2u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 7));
  EXPECT_EQ(0x53u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 2));
  EXPECT_EQ(0x0u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 1));
  EXPECT_EQ(0x1u, val);
  EXPECT_TRUE(buffer.ReadBits(&val, 17));
  EXPECT_EQ(0x1ABCDu, val);
  // And there should be nothing left.
  EXPECT_FALSE(buffer.ReadBits(&val, 1));
}

TEST(BitBufferWriterTest, SymmetricBytesMisaligned) {
  uint8 bytes[16] = {0};
  BitBufferWriter buffer(bytes, 16);

  // Offset 3, to get things misaligned.
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.WriteUInt8(0x12u));
  EXPECT_TRUE(buffer.WriteUInt16(0x3456u));
  EXPECT_TRUE(buffer.WriteUInt32(0x789ABCDEu));

  buffer.Seek(0, 3);
  uint8 val8;
  uint16 val16;
  uint32 val32;
  EXPECT_TRUE(buffer.ReadUInt8(&val8));
  EXPECT_EQ(0x12u, val8);
  EXPECT_TRUE(buffer.ReadUInt16(&val16));
  EXPECT_EQ(0x3456u, val16);
  EXPECT_TRUE(buffer.ReadUInt32(&val32));
  EXPECT_EQ(0x789ABCDEu, val32);
}

TEST(BitBufferWriterTest, SymmetricGolomb) {
  char test_string[] = "my precious";
  uint8 bytes[64] = {0};
  BitBufferWriter buffer(bytes, 64);
  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
    EXPECT_TRUE(buffer.WriteExponentialGolomb(test_string[i]));
  }
  buffer.Seek(0, 0);
  for (size_t i = 0; i < ARRAY_SIZE(test_string); ++i) {
    uint32 val;
    EXPECT_TRUE(buffer.ReadExponentialGolomb(&val));
    EXPECT_LE(val, std::numeric_limits<uint8>::max());
    EXPECT_EQ(test_string[i], static_cast<char>(val));
  }
}

TEST(BitBufferWriterTest, WriteClearsBits) {
  uint8 bytes[] = {0xFF, 0xFF};
  BitBufferWriter buffer(bytes, 2);
  EXPECT_TRUE(buffer.ConsumeBits(3));
  EXPECT_TRUE(buffer.WriteBits(0, 1));
  EXPECT_EQ(0xEFu, bytes[0]);
  EXPECT_TRUE(buffer.WriteBits(0, 3));
  EXPECT_EQ(0xE1u, bytes[0]);
  EXPECT_TRUE(buffer.WriteBits(0, 2));
  EXPECT_EQ(0xE0u, bytes[0]);
  EXPECT_EQ(0x7F, bytes[1]);
}

}  // namespace rtc
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef SD_SLIDESORTER_PAGE_CACHE_HXX
#define SD_SLIDESORTER_PAGE_CACHE_HXX

#include "cache/SlsCacheContext.hxx"
#include <sal/types.h>
#include <boost/scoped_ptr.hpp>
#include <vcl/bitmap.hxx>

struct Size;

namespace sd { namespace slidesorter { namespace cache {

class GenericPageCache;

/** The page cache is responsible for the creation and storage of preview
    bitmaps of pages that are shown by the slide sorter.

Bitmaps for previews and a cache are used to speed up the display
    (painting) of the slide sorter.  But, of course, we have to limit this
    time-space-tradeoff by limiting the amount of space that can be use to
    store bitmaps.

There are several strategies employed by this class to shorten the
    perceived time that is used to paint the slide sorter:

Rendering pages ahead of time.  Additionally to rendering the
    visible slides we try to render part or all of the slides that are not
    (yet) visible.  This, of course, makes sense only when the computer is
    ohterwise idle while doing that.

When the size of the slides on the screen changes we mark the
    bitmaps as needing an update but use them while the new bitmap in the
    correct size is not available.

Give the UI the chance to handle user events between the rendering
    of differe slides.

Limit the amount of space that may be used for storing preview
    bitmaps and throw.

There is another somewhat similar methods for requesting new previews:
    GetPreviewBitmap() schedules a re-rendering (when necessary) and
    returns the preview what is currently available, either as a preview of
    the preview or, when nothing has changed since the last call, as the
    final thing.

*/
class PageCache
{
public:
    /** The page chache is created with a reference to the slide sorter so
        that it has access to both the view and the model and so can fill
        itself with requests for all or just the visible pages.

        It is the task of the PageCacheManager to create new objects of this
        class.
    */
    PageCache (
        const Size& rPreviewSize,
        const bool bDoSuperSampling,
        const SharedCacheContext& rpCacheContext);

    ~PageCache (void);

    void ChangeSize(
        const Size& rPreviewSize,
        const bool bDoSuperSampling);

    /** Request a preview bitmap for the specified page object in the
        specified size.  The returned bitmap may be a preview of the
        preview, i.e. either a scaled (up or down) version of a previous
        preview (of the wrong size) or an empty bitmap.  In this case a
        request for the generation of a new preview is created and inserted
        into the request queue.  When the preview is available in the right
        size the page shape will be told to paint itself again.  When it
        then calls this method again if receives the correctly sized preview
        bitmap.
        @param rRequestData
            This data is used to determine the preview.
        @param bResize
            When <TRUE/> then when the available bitmap has not the
            requested size, it is scaled before it is returned.  When
            <FALSE/> then the bitmap is returned in the wrong size and it is
            the task of the caller to scale it.
        @return
            Returns a bitmap that is either empty, contains a scaled (up or
            down) version or is the requested bitmap.
    */
    Bitmap GetPreviewBitmap (
        const CacheKey aKey,
        const bool bResize);

    Bitmap GetMarkedPreviewBitmap (
        const CacheKey aKey,
        const bool bResize);
    void SetMarkedPreviewBitmap (
        const CacheKey aKey,
        const Bitmap& rBitmap);

    /** When the requested preview bitmap does not yet exist or is not
        up-to-date then the rendering of one is scheduled.  Otherwise this
        method does nothing.
    */
    void RequestPreviewBitmap (const CacheKey aKey);

    /** Tell the cache that the bitmap associated with the given request
        data is not up-to-date anymore.  This will invalidate all previews
        in other caches that represent the same page as well.
        @param bRequestPreview
            When <TRUE/> then a new preview is requested and will lead
            eventually to a repaint of the associated page object.
    */
    void InvalidatePreviewBitmap (
        const CacheKey aKey,
        const bool bRequestPreview);

    /** Call this method when all preview bitmaps have to be generated anew.
        This is the case when the size of the page objects on the screen has
        changed or when the model has changed.
        @param bUpdateCache
            When this flags is <TRUE/> then requests for updated previews
            are created.  When it is <FALSE/> the existing previews are only
            marked as not being up-to-date anymore.
    */
    void InvalidateCache (const bool bUpdateCache = true);

    /** With the precious flag you can control whether a bitmap can be
        removed or reduced in size to make room for other bitmaps or is so
        precious that it will not touched.  A typical use is to set the
        precious flag for exactly the visible pages.
    */
    void SetPreciousFlag (const CacheKey aKey, const bool bIsPrecious);

    void Pause (void);
    void Resume (void);

private:
    ::boost::scoped_ptr<GenericPageCache> mpImplementation;
};

} } } // end of namespace ::sd::slidesorter::cache

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE: struct 'Size' was previously declared as a class<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef SD_SLIDESORTER_PAGE_CACHE_HXX
#define SD_SLIDESORTER_PAGE_CACHE_HXX

#include "cache/SlsCacheContext.hxx"
#include <sal/types.h>
#include <boost/scoped_ptr.hpp>
#include <vcl/bitmap.hxx>

class Size;

namespace sd { namespace slidesorter { namespace cache {

class GenericPageCache;

/** The page cache is responsible for the creation and storage of preview
    bitmaps of pages that are shown by the slide sorter.

Bitmaps for previews and a cache are used to speed up the display
    (painting) of the slide sorter.  But, of course, we have to limit this
    time-space-tradeoff by limiting the amount of space that can be use to
    store bitmaps.

There are several strategies employed by this class to shorten the
    perceived time that is used to paint the slide sorter:

Rendering pages ahead of time.  Additionally to rendering the
    visible slides we try to render part or all of the slides that are not
    (yet) visible.  This, of course, makes sense only when the computer is
    ohterwise idle while doing that.

When the size of the slides on the screen changes we mark the
    bitmaps as needing an update but use them while the new bitmap in the
    correct size is not available.

Give the UI the chance to handle user events between the rendering
    of differe slides.

Limit the amount of space that may be used for storing preview
    bitmaps and throw.

There is another somewhat similar methods for requesting new previews:
    GetPreviewBitmap() schedules a re-rendering (when necessary) and
    returns the preview what is currently available, either as a preview of
    the preview or, when nothing has changed since the last call, as the
    final thing.

*/
class PageCache
{
public:
    /** The page chache is created with a reference to the slide sorter so
        that it has access to both the view and the model and so can fill
        itself with requests for all or just the visible pages.

        It is the task of the PageCacheManager to create new objects of this
        class.
    */
    PageCache (
        const Size& rPreviewSize,
        const bool bDoSuperSampling,
        const SharedCacheContext& rpCacheContext);

    ~PageCache (void);

    void ChangeSize(
        const Size& rPreviewSize,
        const bool bDoSuperSampling);

    /** Request a preview bitmap for the specified page object in the
        specified size.  The returned bitmap may be a preview of the
        preview, i.e. either a scaled (up or down) version of a previous
        preview (of the wrong size) or an empty bitmap.  In this case a
        request for the generation of a new preview is created and inserted
        into the request queue.  When the preview is available in the right
        size the page shape will be told to paint itself again.  When it
        then calls this method again if receives the correctly sized preview
        bitmap.
        @param rRequestData
            This data is used to determine the preview.
        @param bResize
            When <TRUE/> then when the available bitmap has not the
            requested size, it is scaled before it is returned.  When
            <FALSE/> then the bitmap is returned in the wrong size and it is
            the task of the caller to scale it.
        @return
            Returns a bitmap that is either empty, contains a scaled (up or
            down) version or is the requested bitmap.
    */
    Bitmap GetPreviewBitmap (
        const CacheKey aKey,
        const bool bResize);

    Bitmap GetMarkedPreviewBitmap (
        const CacheKey aKey,
        const bool bResize);
    void SetMarkedPreviewBitmap (
        const CacheKey aKey,
        const Bitmap& rBitmap);

    /** When the requested preview bitmap does not yet exist or is not
        up-to-date then the rendering of one is scheduled.  Otherwise this
        method does nothing.
    */
    void RequestPreviewBitmap (const CacheKey aKey);

    /** Tell the cache that the bitmap associated with the given request
        data is not up-to-date anymore.  This will invalidate all previews
        in other caches that represent the same page as well.
        @param bRequestPreview
            When <TRUE/> then a new preview is requested and will lead
            eventually to a repaint of the associated page object.
    */
    void InvalidatePreviewBitmap (
        const CacheKey aKey,
        const bool bRequestPreview);

    /** Call this method when all preview bitmaps have to be generated anew.
        This is the case when the size of the page objects on the screen has
        changed or when the model has changed.
        @param bUpdateCache
            When this flags is <TRUE/> then requests for updated previews
            are created.  When it is <FALSE/> the existing previews are only
            marked as not being up-to-date anymore.
    */
    void InvalidateCache (const bool bUpdateCache = true);

    /** With the precious flag you can control whether a bitmap can be
        removed or reduced in size to make room for other bitmaps or is so
        precious that it will not touched.  A typical use is to set the
        precious flag for exactly the visible pages.
    */
    void SetPreciousFlag (const CacheKey aKey, const bool bIsPrecious);

    void Pause (void);
    void Resume (void);

private:
    ::boost::scoped_ptr<GenericPageCache> mpImplementation;
};

} } } // end of namespace ::sd::slidesorter::cache

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before><commit_msg>process_util_linux: mark functions that use /proc as safe for disk IO<commit_after><|endoftext|>


<commit_before><commit_msg>Fix KillProcess so it doesn't report everything as a failure.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/test/test_timeouts.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/test/test_switches.h"

namespace {

// Sets value to the greatest of:
// 1) value's current value.
// 2) min_value.
// 3) the numerical value given by switch_name on the command line.
void InitializeTimeout(const char* switch_name, int min_value, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
  *value = std::max(*value, min_value);
}

// Sets value to the greatest of:
// 1) value's current value.
// 2) 0
// 3) the numerical value given by switch_name on the command line.
void InitializeTimeout(const char* switch_name, int* value) {
  InitializeTimeout(switch_name, 0, value);
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 2000;
int TestTimeouts::action_max_timeout_ms_ = 25000;
int TestTimeouts::large_test_timeout_ms_ = 3 * 60 * 1000;
int TestTimeouts::huge_test_timeout_ms_ = 10 * 60 * 1000;

// static
int TestTimeouts::live_operation_timeout_ms_ = 45000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  // Note that these timeouts MUST be initialized in the correct order as
  // per the CHECKS below.
  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionTimeout, tiny_timeout_ms_,
                    &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
                    &action_max_timeout_ms_);
  // TODO(phajdan.jr): Fix callers and remove kTestTerminateTimeout.
  InitializeTimeout(switches::kTestTerminateTimeout, &action_max_timeout_ms_);
  InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
                    &large_test_timeout_ms_);
  InitializeTimeout(switches::kUiTestTimeout, large_test_timeout_ms_,
                    &huge_test_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_);
  CHECK(large_test_timeout_ms_ <= huge_test_timeout_ms_);

  InitializeTimeout(switches::kLiveOperationTimeout,
                    &live_operation_timeout_ms_);
}
<commit_msg>Increase test timeout for out of process tests by 4 seconds.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/test/test_timeouts.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/test/test_switches.h"

namespace {

// Sets value to the greatest of:
// 1) value's current value.
// 2) min_value.
// 3) the numerical value given by switch_name on the command line.
void InitializeTimeout(const char* switch_name, int min_value, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
  *value = std::max(*value, min_value);
}

// Sets value to the greatest of:
// 1) value's current value.
// 2) 0
// 3) the numerical value given by switch_name on the command line.
void InitializeTimeout(const char* switch_name, int* value) {
  InitializeTimeout(switch_name, 0, value);
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 2000;
int TestTimeouts::action_max_timeout_ms_ = 29000;
int TestTimeouts::large_test_timeout_ms_ = 3 * 60 * 1000;
int TestTimeouts::huge_test_timeout_ms_ = 10 * 60 * 1000;

// static
int TestTimeouts::live_operation_timeout_ms_ = 45000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  // Note that these timeouts MUST be initialized in the correct order as
  // per the CHECKS below.
  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionTimeout, tiny_timeout_ms_,
                    &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
                    &action_max_timeout_ms_);
  // TODO(phajdan.jr): Fix callers and remove kTestTerminateTimeout.
  InitializeTimeout(switches::kTestTerminateTimeout, &action_max_timeout_ms_);
  InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
                    &large_test_timeout_ms_);
  InitializeTimeout(switches::kUiTestTimeout, large_test_timeout_ms_,
                    &huge_test_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_);
  CHECK(large_test_timeout_ms_ <= huge_test_timeout_ms_);

  InitializeTimeout(switches::kLiveOperationTimeout,
                    &live_operation_timeout_ms_);
}
<|endoftext|>


<commit_before>/*

Copyright 2015 Armağan Salman

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

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

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

*/

#include <iostream>
#include <stack>
#include <cstdlib>
#include <sstream>
#include <string>

#include "MathematicalExpression.h"

using namespace std;

MathematicalExpression::MathematicalExpression()
{
    this->expression = "";
    this->isResultCalculated = false;
    this->result = 0.0;
}

MathematicalExpression::MathematicalExpression(string expression)
{
    this->expression = expression;
    this->isResultCalculated = false;
    this->result = 0.0;
}

double MathematicalExpression::getResult()
{
    return this->result;
}

void MathematicalExpression::setExpression(string expression)
{
    this->expression = expression;
    this->isResultCalculated = false;
    this->result = 0;
}

double MathematicalExpression::evaluateTerm(char op, double operand1, double operand2)
{
    switch(op)
    {
    case '+':
        return operand1 + operand2;
        break;
    case '-':
        return operand1 - operand2;
        break;
    case '*':
        return operand1 * operand2;
        break;
    case '/':
        return operand1 / operand2;
        break;
    default:
        return 0.0;
    }
}

double MathematicalExpression::evaluate()
{
    string errorMessage = expressionErrorMessage(this->expression);
    if(errorMessage.empty()) // Hata mesaji bossa ifade hatasiz demektir. Ä°slemler gerceklestirilmeli.
    {
        if(isResultCalculated)
        {
            cout << this->expression << " = " << this->result << endl;
            return this->result;
        }
        else
        {
            this->result = this->evaluate(this->expression);
            this->isResultCalculated = true;
            return this->result;
        }
    }
    else // Hata varsa bas.
    {
        cout << errorMessage << endl;
    }
}

double MathematicalExpression::evaluate(string expression)
{
    string errorMessage = expressionErrorMessage(expression);
    if(!errorMessage.empty())
    {
        cout << errorMessage << endl;
        return 0;
    }

    stack<char> symbols;
    stack<double> operands;

    int index = 0;
    char current = 0;
    char *charAfterDouble = NULL;

    char op=0;
    double d1=0,d2=0;
    string temp = "";

    // Her bir karakter icin:
    // Bosluksa atla,
    // '(' ise bir sonraki indisteki operatoru stack'e at,
    // ')' ise sayi stack'inden iki sayi, operator stack'inden bir operator al. Islemi hesapla.
    // Usttekilerden biri degilse sayinin baslangici olmak zorundadÄ±r. Sayiyi strtod ile al. strtod'un ikinci parametresi ile sayidan sonraki karaktere eris. Onun indisini bul. Ana indisi bulunan deger yap.
    while(index < expression.length())
    {
        index = skipBlankChars(expression, index);
        current = expression.at(index);
        if(current == '(')
        {
            index++; // reach operand
            symbols.push(expression.at(index));
            index++; // go over operand
            index = this->skipBlankChars(expression, index);
        }
        else if(current == ')')
        {
            op = symbols.top();
            symbols.pop();

            d2 = operands.top();
            operands.pop();

            d1 = operands.top();
            operands.pop();

            operands.push(evaluateTerm(op,d1,d2));

            index++;
        }
        else // Burada sayi oldugunu biliyoruz.
        {
            temp = expression.substr(index);
            operands.push( strtod(temp.c_str(), &charAfterDouble) ); // Find what comes after double value.

            index = expression.find(*charAfterDouble,index); // Go to whatever comes after double value. Could be a space character or ')'
        }
    }
    cout << expression << " = " << operands.top() << endl;
    return operands.top();
}

int MathematicalExpression::skipBlankChars(std::string str, int idx)
{
    for(; isspace(str.at(idx)); idx++)
        ;
    return idx;
}

string MathematicalExpression::expressionErrorMessage(string expr)
{
    int parans = 0;
    int operators = 0;
    int operands = 0;
    const int LENGTH = expr.length();

    char * charAfterNumber;
    ostringstream errorMessage;

    for(int i = 0; i < LENGTH;)
    {
        if(isspace(expr.at(i)))
        {
            i++;
            continue;
        }
        else if(expr.at(i) == '(')
        {
            parans++;
            if( i+1 >= LENGTH || !isOperator(expr.at(i+1)) ) // parantez acimindan sonra operator olmali.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i+1 << " indisinde operator yok.";
                return errorMessage.str();
            }

            operators++; // Ustteki return'de cikmadi. Demekki operator var.

            if( i+2 >= LENGTH || !isspace(expr.at(i+2)) ) // parantez acimindan iki karakter sonra bosluk olmali. Standart isspace fonksiyonu kullanildi.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i+2 << " indisinde bosluk yok.";
                return errorMessage.str();
            }

            i += 2;
        }
        else if(expr.at(i) == ')')
        {
            parans--;
            operators--;
            operands--; // Ýki deger kullanip bir deger yazildigindan bir azalmali.
            i++;
        }
        else // Sayi olmali
        {
            if(isOperator(expr.at(i))) // Buraya girerse operatorden once '(' yok demektir.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki operatorden once '(' bekleniyor.";
                return errorMessage.str();
            }

            if( i-1 >= 0 && !isspace(expr.at(i-1))) // Sayidan once bosluk olmali
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki sayidan once bosluk bekleniyor.";
                return errorMessage.str();
            }

            strtod(expr.substr(i).c_str(), &charAfterNumber); // Sayiyi parse etmeye calis. Sayidan sonraki karakteri charAfterNumber gostersin.
            if(!isspace(*charAfterNumber) && *charAfterNumber != ')') // Sayidan sonra bosluk veya ')' yoksa hata ver.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki sayidan sonra bosluk veya ')' bekleniyor.";
                return errorMessage.str();
            }
            operands++;
            i = expr.find(*charAfterNumber, i); // Sayidan sonra ilk bulunan bosluk veya ')' ise oraya atla.
        }
    }

    if(parans != 0)
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" parantez acildigi kadar kapatilmamis.";
        return errorMessage.str();
    }
    else if(operators != 0)
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" operatorler sifirlanamamis.";
        return errorMessage.str();
    }
    else if(operands != 1) // En sonda stack'te 1 eleman kalmali. O da ifadenin sonuc degeri.
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" operandlar beklenen sayida degil.";
        return errorMessage.str();
    }
    else // Hata saptanmadi. Bos string don.
    {
        return "";
    }
}

bool MathematicalExpression::isOperator(char c)
{
    return c == '+' || c == '-' || c == '*' || c == '/';
}
<commit_msg>Update MathematicalExpression.cpp<commit_after>/*

Copyright 2015 Armağan Salman

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

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

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

*/

#include <iostream>
#include <stack>
#include <cstdlib>
#include <sstream>
#include <string>

#include "MathematicalExpression.h"

using namespace std;

MathematicalExpression::MathematicalExpression()
{
    this->expression = "";
    this->isResultCalculated = false;
    this->result = 0.0;
}

MathematicalExpression::MathematicalExpression(string expression)
{
    this->expression = expression;
    this->isResultCalculated = false;
    this->result = 0.0;
}

double MathematicalExpression::getResult()
{
    return this->result;
}

void MathematicalExpression::setExpression(string expression)
{
    this->expression = expression;
    this->isResultCalculated = false;
    this->result = 0;
}

double MathematicalExpression::evaluateTerm(char op, double operand1, double operand2)
{
    switch(op)
    {
    case '+':
        return operand1 + operand2;
        break;
    case '-':
        return operand1 - operand2;
        break;
    case '*':
        return operand1 * operand2;
        break;
    case '/':
        return operand1 / operand2;
        break;
    default:
        return 0.0;
    }
}

double MathematicalExpression::evaluate()
{
    string errorMessage = expressionErrorMessage(this->expression);
    if(!errorMessage.empty())
    {
        cout << errorMessage << endl;
        return 0;
    }

   // Hata mesaji bossa ifade hatasiz demektir. İşlemler gerceklestirilmeli.
     if(isResultCalculated)
     {
         cout << this->expression << " = " << this->result << endl;
         return this->result;
     }
     else
     {
         this->result = this->evaluate(this->expression);
         this->isResultCalculated = true;
         return this->result;
     }
}

double MathematicalExpression::evaluate(string expression)
{
    string errorMessage = expressionErrorMessage(expression);
    if(!errorMessage.empty())
    {
        cout << errorMessage << endl;
        return 0;
    }

    stack<char> symbols;
    stack<double> operands;

    int index = 0;
    char current = 0;
    char *charAfterDouble = NULL;

    char op=0;
    double d1=0,d2=0;
    string temp = "";

    // Her bir karakter icin:
    // Bosluksa atla,
    // '(' ise bir sonraki indisteki operatoru stack'e at,
    // ')' ise sayi stack'inden iki sayi, operator stack'inden bir operator al. Islemi hesapla.
    // Usttekilerden biri degilse sayinin baslangici olmak zorundadÄ±r. Sayiyi strtod ile al. strtod'un ikinci parametresi ile sayidan sonraki karaktere eris. Onun indisini bul. Ana indisi bulunan deger yap.
    while(index < expression.length())
    {
        index = skipBlankChars(expression, index);
        current = expression.at(index);
        if(current == '(')
        {
            index++; // reach operand
            symbols.push(expression.at(index));
            index++; // go over operand
            index = this->skipBlankChars(expression, index);
        }
        else if(current == ')')
        {
            op = symbols.top();
            symbols.pop();

            d2 = operands.top();
            operands.pop();

            d1 = operands.top();
            operands.pop();

            operands.push(evaluateTerm(op,d1,d2));

            index++;
        }
        else // Burada sayi oldugunu biliyoruz.
        {
            temp = expression.substr(index);
            operands.push( strtod(temp.c_str(), &charAfterDouble) ); // Find what comes after double value.

            index = expression.find(*charAfterDouble,index); // Go to whatever comes after double value. Could be a space character or ')'
        }
    }
    cout << expression << " = " << operands.top() << endl;
    return operands.top();
}

int MathematicalExpression::skipBlankChars(std::string str, int idx)
{
    for(; isspace(str.at(idx)); idx++)
        ;
    return idx;
}

string MathematicalExpression::expressionErrorMessage(string expr)
{
    int parans = 0;
    int operators = 0;
    int operands = 0;
    const int LENGTH = expr.length();

    char * charAfterNumber;
    ostringstream errorMessage;

    for(int i = 0; i < LENGTH;)
    {
        if(isspace(expr.at(i)))
        {
            i++;
            continue;
        }
        else if(expr.at(i) == '(')
        {
            parans++;
            if( i+1 >= LENGTH || !isOperator(expr.at(i+1)) ) // parantez acimindan sonra operator olmali.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i+1 << " indisinde operator yok.";
                return errorMessage.str();
            }

            operators++; // Ustteki return'de cikmadi. Demekki operator var.

            if( i+2 >= LENGTH || !isspace(expr.at(i+2)) ) // parantez acimindan iki karakter sonra bosluk olmali. Standart isspace fonksiyonu kullanildi.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i+2 << " indisinde bosluk yok.";
                return errorMessage.str();
            }

            i += 2;
        }
        else if(expr.at(i) == ')')
        {
            parans--;
            operators--;
            operands--; // Ýki deger kullanip bir deger yazildigindan bir azalmali.
            i++;
        }
        else // Sayi olmali
        {
            if(isOperator(expr.at(i))) // Buraya girerse operatorden once '(' yok demektir.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki operatorden once '(' bekleniyor.";
                return errorMessage.str();
            }

            if( i-1 >= 0 && !isspace(expr.at(i-1))) // Sayidan once bosluk olmali
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki sayidan once bosluk bekleniyor.";
                return errorMessage.str();
            }

            strtod(expr.substr(i).c_str(), &charAfterNumber); // Sayiyi parse etmeye calis. Sayidan sonraki karakteri charAfterNumber gostersin.
            if(!isspace(*charAfterNumber) && *charAfterNumber != ')') // Sayidan sonra bosluk veya ')' yoksa hata ver.
            {
                errorMessage << "Hesaplanamayan expression :\"" << expr << "\" " << i << " indisindeki sayidan sonra bosluk veya ')' bekleniyor.";
                return errorMessage.str();
            }
            operands++;
            i = expr.find(*charAfterNumber, i); // Sayidan sonra ilk bulunan bosluk veya ')' ise oraya atla.
        }
    }

    if(parans != 0)
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" parantez acildigi kadar kapatilmamis.";
        return errorMessage.str();
    }
    else if(operators != 0)
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" operatorler sifirlanamamis.";
        return errorMessage.str();
    }
    else if(operands != 1) // En sonda stack'te 1 eleman kalmali. O da ifadenin sonuc degeri.
    {
        errorMessage << "Hesaplanamayan expression :\"" << expr << "\" operandlar beklenen sayida degil.";
        return errorMessage.str();
    }
    else // Hata saptanmadi. Bos string don.
    {
        return "";
    }
}

bool MathematicalExpression::isOperator(char c)
{
    return c == '+' || c == '-' || c == '*' || c == '/';
}
<|endoftext|>


<commit_before>#pragma once

#include "adapters/net.hpp"
#include "components/config.hpp"
#include "modules/meta/timer_module.hpp"

POLYBAR_NS

namespace modules {
  enum class connection_state { NONE = 0, CONNECTED, DISCONNECTED, PACKETLOSS };

  class network_module : public timer_module<network_module> {
   public:
    using timer_module::timer_module;

    void setup();
    void teardown();
    bool update();
    string get_format() const;
    bool build(builder* builder, string tag) const;

   protected:
    void subthread_routine();

   private:
    static constexpr auto FORMAT_CONNECTED = "format-connected";
    static constexpr auto FORMAT_PACKETLOSS = "format-packetloss";
    static constexpr auto FORMAT_DISCONNECTED = "format-disconnected";
    static constexpr auto TAG_RAMP_SIGNAL = "<ramp-signal>";
    static constexpr auto TAG_RAMP_QUALITY = "<ramp-quality>";
    static constexpr auto TAG_LABEL_CONNECTED = "<label-connected>";
    static constexpr auto TAG_LABEL_DISCONNECTED = "<label-disconnected>";
    static constexpr auto TAG_LABEL_PACKETLOSS = "<label-packetloss>";
    static constexpr auto TAG_ANIMATION_PACKETLOSS = "<animation-packetloss>";

    net::wired_t m_wired;
    net::wireless_t m_wireless;

    ramp_t m_ramp_signal;
    ramp_t m_ramp_quality;
    animation_t m_animation_packetloss;
    map<connection_state, label_t> m_label;

    stateflag m_connected{false};
    stateflag m_packetloss{false};

    int m_signal = 0;
    int m_quality = 0;
    int m_counter = -1;  // -1 to ignore the first run

    string m_interface;
    int m_ping_nth_update = 0;
    int m_udspeed_minwidth = 3;
    bool m_accumulate = false;
  };
}

POLYBAR_NS_END
<commit_msg>fix(network): Change default value of udspeed_minwidth<commit_after>#pragma once

#include "adapters/net.hpp"
#include "components/config.hpp"
#include "modules/meta/timer_module.hpp"

POLYBAR_NS

namespace modules {
  enum class connection_state { NONE = 0, CONNECTED, DISCONNECTED, PACKETLOSS };

  class network_module : public timer_module<network_module> {
   public:
    using timer_module::timer_module;

    void setup();
    void teardown();
    bool update();
    string get_format() const;
    bool build(builder* builder, string tag) const;

   protected:
    void subthread_routine();

   private:
    static constexpr auto FORMAT_CONNECTED = "format-connected";
    static constexpr auto FORMAT_PACKETLOSS = "format-packetloss";
    static constexpr auto FORMAT_DISCONNECTED = "format-disconnected";
    static constexpr auto TAG_RAMP_SIGNAL = "<ramp-signal>";
    static constexpr auto TAG_RAMP_QUALITY = "<ramp-quality>";
    static constexpr auto TAG_LABEL_CONNECTED = "<label-connected>";
    static constexpr auto TAG_LABEL_DISCONNECTED = "<label-disconnected>";
    static constexpr auto TAG_LABEL_PACKETLOSS = "<label-packetloss>";
    static constexpr auto TAG_ANIMATION_PACKETLOSS = "<animation-packetloss>";

    net::wired_t m_wired;
    net::wireless_t m_wireless;

    ramp_t m_ramp_signal;
    ramp_t m_ramp_quality;
    animation_t m_animation_packetloss;
    map<connection_state, label_t> m_label;

    stateflag m_connected{false};
    stateflag m_packetloss{false};

    int m_signal{0};
    int m_quality{0};
    int m_counter{-1};  // -1 to ignore the first run

    string m_interface;
    int m_ping_nth_update{0};
    int m_udspeed_minwidth{0};
    bool m_accumulate{false};
  };
}

POLYBAR_NS_END
<|endoftext|>


<commit_before>/* Transactor framework, a wrapper for safely retryable transactions.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
 *
 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#ifndef PQXX_H_TRANSACTOR
#define PQXX_H_TRANSACTOR

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#include "pqxx/connection_base.hxx"
#include "pqxx/transaction.hxx"

// Methods tested in eg. test module test01 are marked with "//[t01]".

namespace pqxx
{
/**
 * @defgroup transactor Transactor framework
 *
 * Sometimes a transaction can fail for completely transient reasons, such as a
 * conflict with another transaction in SERIALIZABLE isolation.  The right way
 * to handle those failures is often just to re-run the transaction from
 * scratch.
 *
 * For example, your REST API might be handling each HTTP request in its own
 * database transaction, and if this kind of transient failure happens, you
 * simply want to "replay" the whole request, in a fresh transaction.
 *
 * You won't necessarily want to execute the exact same SQL commands with the
 * exact same data.  Some of your SQL statements may depend on state that can
 * vary between retries.  So instead of dumbly replaying the SQL, you re-run
 * the same application code that produced those SQL commands.
 *
 * The transactor framework makes it a little easier for you to do this safely,
 * and avoid typical pitfalls.  You encapsulate the work that you want to do
 * into a callable that you pass to the @c perform function.
 *
 * Here's how it works.  You write your transaction code as a lambda or
 * function, which creates its own transaction object, does its work, and
 * commits at the end.  You pass that callback to @c pqxx::perform, which runs
 * it for you.
 *
 * If there's a failure inside your callback, there will be an exception.  Your
 * transaction object goes out of scope and gets destroyed, so that it aborts
 * implicitly.  Seeing this, @c perform tries running your callback again.  It
 * stops doing that when the callback succeeds, or when it has failed too many
 * times, or when there's an error that leaves the database in an unknown
 * state, such as a lost connection just while we're waiting for the database
 * to confirm a commit.  It all depends on the type of exception.
 *
 * The callback takes no arguments.  If you're using lambdas, the easy way to
 * pass arguments is for the lambda to "capture" them from your variables.  Or,
 * if you're using functions, you may want to use @c std::bind.
 *
 * Once your callback succeeds, it can return a result, and @c perform will
 * return that result back to you.
 */
//@{

/// Simple way to execute a transaction with automatic retry.
/**
 * Executes your transaction code as a callback.  Repeats it until it completes
 * normally, or it throws an error other than the few libpqxx-generated
 * exceptions that the framework understands, or after a given number of failed
 * attempts, or if the transaction ends in an "in-doubt" state.
 *
 * (An in-doubt state is one where libpqxx cannot determine whether the server
 * finally committed a transaction or not.  This can happen if the network
 * connection to the server is lost just while we're waiting for its reply to
 * a "commit" statement.  The server may have completed the commit, or not, but
 * it can't tell you because there's no longer a connection.
 *
 * Using this still takes a bit of care.  If your callback makes use of data
 * from the database, you'll probably have to query that data within your
 * callback.  If the attempt to perform your callback fails, and the framework
 * tries again, you'll be in a new transaction and the data in the database may
 * have changed under your feet.
 *
 * Also be careful about changing variables or data structures from within
 * your callback.  The run may still fail, and perhaps get run again.  The
 * ideal way to do it (in most cases) is to return your result from your
 * callback, and change your program's data state only after @c perform
 * completes successfully.
 *
 * @param callback Transaction code that can be called with no arguments.
 * @param attempts Maximum number of times to attempt performing callback.
 *	Must be greater than zero.
 * @return Whatever your callback returns.
 */
template<typename TRANSACTION_CALLBACK>
inline auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3)
  -> decltype(callback())
{
  if (attempts <= 0)
    throw std::invalid_argument{
	"Zero or negative number of attempts passed to pqxx::perform()."};

  for (; attempts > 0; --attempts)
  {
    try
    {
      return callback();
    }
    catch (const in_doubt_error &)
    {
      // Not sure whether transaction went through or not.  The last thing in
      // the world that we should do now is try again!
      throw;
    }
    catch (const statement_completion_unknown &)
    {
      // Not sure whether our last statement succeeded.  Don't risk running it
      // again.
      throw;
    }
    catch (const broken_connection &)
    {
      // Connection failed.  Definitely worth retrying.
      if (attempts <= 1) throw;
      continue;
    }
    catch (const transaction_rollback &)
    {
      // Some error that may well be transient, such as serialization failure
      // or deadlock.  Worth retrying.
      if (attempts <= 1) throw;
      continue;
    }
  }
  throw pqxx::internal_error{"No outcome reached on perform()."};
}

/// @deprecated Pre-C++11 wrapper for automatically retrying transactions.
/**
 * Pass an object of your transactor-based class to connection_base::perform()
 * to execute the transaction code embedded in it.
 *
 * connection_base::perform() is actually a template, specializing itself to any
 * transactor type you pass to it.  This means you will have to pass it a
 * reference of your object's ultimate static type; runtime polymorphism is
 * not allowed.  Hence the absence of virtual methods in transactor.  The
 * exact methods to be called at runtime *must* be resolved at compile time.
 *
 * Your transactor-derived class must define a copy constructor.  This will be
 * used to create a "clean" copy of your transactor for every attempt that
 * perform() makes to run it.
 */
template<typename TRANSACTION=transaction<read_committed>> class transactor
{
public:
  using argument_type = TRANSACTION;
  PQXX_DEPRECATED explicit transactor(					//[t04]
	const std::string &TName="transactor") :
    m_name{TName} { }

  /// Overridable transaction definition; insert your database code here
  /** The operation will be retried if the connection to the backend is lost or
   * the operation fails, but not if the connection is broken in such a way as
   * to leave the library in doubt as to whether the operation succeeded.  In
   * that case, an in_doubt_error will be thrown.
   *
   * Recommended practice is to allow this operator to modify only the
   * transactor itself, and the dedicated transaction object it is passed as an
   * argument.  This is what makes side effects, retrying etc. controllable in
   * the transactor framework.
   * @param T Dedicated transaction context created to perform this operation.
   */
  void operator()(TRANSACTION &T);					//[t04]

  // Overridable member functions, called by connection_base::perform() if an
  // attempt to run transaction fails/succeeds, respectively, or if the
  // connection is lost at just the wrong moment, goes into an indeterminate
  // state.  Use these to patch up runtime state to match events, if needed, or
  // to report failure conditions.

  /// Optional overridable function to be called if transaction is aborted
  /** This need not imply complete failure; the transactor will automatically
   * retry the operation a number of times before giving up.  on_abort() will be
   * called for each of the failed attempts.
   *
   * One parameter is passed in by the framework: an error string describing why
   * the transaction failed.  This will also be logged to the connection's
   * notice processor.
   */
  void on_abort(const char[]) noexcept {}				//[t13]

  /// Optional overridable function to be called after successful commit
  /** If your on_commit() throws an exception, the actual back-end transaction
   * will remain committed, so any changes in the database remain regardless of
   * how this function terminates.
   */
  void on_commit() {}							//[t07]

  /// Overridable function to be called when "in doubt" about outcome
  /** This may happen if the connection to the backend is lost while attempting
   * to commit.  In that case, the backend may have committed the transaction
   * but is unable to confirm this to the frontend; or the transaction may have
   * failed, causing it to be rolled back, but again without acknowledgement to
   * the client program.  The best way to deal with this situation is typically
   * to wave red flags in the user's face and ask him to investigate.
   *
   * The robusttransaction class is intended to reduce the chances of this
   * error occurring, at a certain cost in performance.
   * @see robusttransaction
   */
  void on_doubt() noexcept {}						//[t13]

  /// The transactor's name.
  std::string name() const { return m_name; }				//[t13]

private:
  std::string m_name;
};

template<typename TRANSACTOR>
inline void connection_base::perform(
	const TRANSACTOR &T,
        int Attempts)
{
  if (Attempts <= 0) return;

  bool Done = false;

  // Make attempts to perform T
  do
  {
    --Attempts;

    // Work on a copy of T2 so we can restore the starting situation if need be
    TRANSACTOR T2{T};
    try
    {
      typename TRANSACTOR::argument_type X{*this, T2.name()};
      T2(X);
      X.commit();
      Done = true;
    }
    catch (const in_doubt_error &)
    {
      // Not sure whether transaction went through or not.  The last thing in
      // the world that we should do now is retry.
      T2.on_doubt();
      throw;
    }
    catch (const std::exception &e)
    {
      // Could be any kind of error.
      T2.on_abort(e.what());
      if (Attempts <= 0) throw;
      continue;
    }
    catch (...)
    {
      // Don't try to forge ahead if we don't even know what happened
      T2.on_abort("Unknown exception");
      throw;
    }

    T2.on_commit();
  } while (not Done);
}
} // namespace pqxx
//@}
#include "pqxx/compiler-internal-post.hxx"
#endif
<commit_msg>Remove deprecated pre-C++11 transactor.<commit_after>/* Transactor framework, a wrapper for safely retryable transactions.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
 *
 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#ifndef PQXX_H_TRANSACTOR
#define PQXX_H_TRANSACTOR

#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

#include "pqxx/connection_base.hxx"
#include "pqxx/transaction.hxx"

// Methods tested in eg. test module test01 are marked with "//[t01]".

namespace pqxx
{
/**
 * @defgroup transactor Transactor framework
 *
 * Sometimes a transaction can fail for completely transient reasons, such as a
 * conflict with another transaction in SERIALIZABLE isolation.  The right way
 * to handle those failures is often just to re-run the transaction from
 * scratch.
 *
 * For example, your REST API might be handling each HTTP request in its own
 * database transaction, and if this kind of transient failure happens, you
 * simply want to "replay" the whole request, in a fresh transaction.
 *
 * You won't necessarily want to execute the exact same SQL commands with the
 * exact same data.  Some of your SQL statements may depend on state that can
 * vary between retries.  Data in the database may already have changed, for
 * instance.  So instead of dumbly replaying the SQL, you re-run the same
 * application code that produced those SQL commands, from the start.
 *
 * The transactor framework makes it a little easier for you to do this safely,
 * and avoid typical pitfalls.  You encapsulate the work that you want to do
 * into a callable that you pass to the @c perform function.
 *
 * Here's how it works.  You write your transaction code as a lambda or
 * function, which creates its own transaction object, does its work, and
 * commits at the end.  You pass that callback to @c pqxx::perform, which runs
 * it for you.
 *
 * If there's a failure inside your callback, there will be an exception.  Your
 * transaction object goes out of scope and gets destroyed, so that it aborts
 * implicitly.  Seeing this, @c perform tries running your callback again.  It
 * stops doing that when the callback succeeds, or when it has failed too many
 * times, or when there's an error that leaves the database in an unknown
 * state, such as a lost connection just while we're waiting for the database
 * to confirm a commit.  It all depends on the type of exception.
 *
 * The callback takes no arguments.  If you're using lambdas, the easy way to
 * pass arguments is for the lambda to "capture" them from your variables.  Or,
 * if you're using functions, you may want to use @c std::bind.
 *
 * Once your callback succeeds, it can return a result, and @c perform will
 * return that result back to you.
 */
//@{

/// Simple way to execute a transaction with automatic retry.
/**
 * Executes your transaction code as a callback.  Repeats it until it completes
 * normally, or it throws an error other than the few libpqxx-generated
 * exceptions that the framework understands, or after a given number of failed
 * attempts, or if the transaction ends in an "in-doubt" state.
 *
 * (An in-doubt state is one where libpqxx cannot determine whether the server
 * finally committed a transaction or not.  This can happen if the network
 * connection to the server is lost just while we're waiting for its reply to
 * a "commit" statement.  The server may have completed the commit, or not, but
 * it can't tell you because there's no longer a connection.
 *
 * Using this still takes a bit of care.  If your callback makes use of data
 * from the database, you'll probably have to query that data within your
 * callback.  If the attempt to perform your callback fails, and the framework
 * tries again, you'll be in a new transaction and the data in the database may
 * have changed under your feet.
 *
 * Also be careful about changing variables or data structures from within
 * your callback.  The run may still fail, and perhaps get run again.  The
 * ideal way to do it (in most cases) is to return your result from your
 * callback, and change your program's data state only after @c perform
 * completes successfully.
 *
 * @param callback Transaction code that can be called with no arguments.
 * @param attempts Maximum number of times to attempt performing callback.
 *	Must be greater than zero.
 * @return Whatever your callback returns.
 */
template<typename TRANSACTION_CALLBACK>
inline auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3)
  -> decltype(callback())
{
  if (attempts <= 0)
    throw std::invalid_argument{
	"Zero or negative number of attempts passed to pqxx::perform()."};

  for (; attempts > 0; --attempts)
  {
    try
    {
      return callback();
    }
    catch (const in_doubt_error &)
    {
      // Not sure whether transaction went through or not.  The last thing in
      // the world that we should do now is try again!
      throw;
    }
    catch (const statement_completion_unknown &)
    {
      // Not sure whether our last statement succeeded.  Don't risk running it
      // again.
      throw;
    }
    catch (const broken_connection &)
    {
      // Connection failed.  Definitely worth retrying.
      if (attempts <= 1) throw;
      continue;
    }
    catch (const transaction_rollback &)
    {
      // Some error that may well be transient, such as serialization failure
      // or deadlock.  Worth retrying.
      if (attempts <= 1) throw;
      continue;
    }
  }
  throw pqxx::internal_error{"No outcome reached on perform()."};
}
} // namespace pqxx
//@}
#include "pqxx/compiler-internal-post.hxx"
#endif
<|endoftext|>