<commit_before>// Copyright (c) 2014-2017 Michael J. Sullivan
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

#include <atomic>
#include <utility>
#include <functional>
#include <memory>
#include "epoch_c11.hpp"
#include "remote_fence.hpp"
#include "util.hpp"
// Very very closely modeled after crossbeam by aturon.

namespace rmclib {
/////////////////////////////

const int kNumEpochs = 3;

thread_local LocalEpoch Epoch::local_epoch_;
std::atomic<Participant::Ptr> Participants::head_;

// XXX: Should this be in a class??
static std::atomic<uintptr_t> global_epoch_{0};
static ConcurrentBag global_garbage_[kNumEpochs];

Participant *Participants::enroll() {
    Participant *p = new Participant();

    Participant::Ptr head = head_;
    for (;;) {
        p->next_ = head;
        if (head_.compare_exchange_weak(head, p)) break;
    }

    return p;
}

/////// Participant is where most of the interesting stuff happens
bool Participant::quickEnter() noexcept {
    uintptr_t new_count = in_critical_.load(mo_rlx) + 1;
    in_critical_.store(new_count, mo_rlx);
    // Nothing to do if we were already in a critical section
    if (new_count > 1) return false;

    remote_thread_fence::placeholder(mo_sc);

    // Copy the global epoch to the local one
    uintptr_t global_epoch = global_epoch_.load(mo_rlx);
    epoch_.store(global_epoch, mo_rlx);
    return true;
}

void Participant::enter() noexcept {
    uintptr_t epoch = epoch_.load(mo_rlx);
    if (!quickEnter()) return;

    // If the epoch has changed, garbage collect
    if (epoch != epoch_.load(mo_rlx)) {
        garbage_.collect();
    }

    if (garbage_.needsCollect()) {
        tryCollect();
    }
}

void Participant::exit() noexcept {
    uintptr_t new_count = in_critical_.load(mo_rlx) - 1;
    // XXX: this may not need to be release
    // in our current setup, nothing can get freed until we do another
    // enter.
    // wait, does anything about the claim make any sense??
    in_critical_.store(new_count, mo_rel);
}

bool Participant::tryCollect() {
    uintptr_t cur_epoch = global_epoch_.load(mo_acq);

    remote_thread_fence::trigger();

    // Check whether all active threads are in the current epoch so we
    // can advance it.
    // As we do it, we lazily clean up exited threads.
    //
    // XXX: Do we want to factor out the list traversal?
try_again:
    std::atomic<Participant::Ptr> *prevp = &Participants::head_;
    Participant::Ptr cur = prevp->load(mo_acq);
    while (cur) {
        Participant::Ptr next = cur->next_.load(mo_rlx);
        if (next.tag()) {
            // This node has exited. Try to unlink it from the
            // list. This will fail if it's already been unlinked or
            // the previous node has exited; in those cases, we start
            // back over at the head of the list.
            next = Ptr(next, 0); // clear next's tag
            if (prevp->compare_exchange_strong(cur, next, mo_acq)) {
                Guard g(this);
                g.unlinked(cur.ptr());
            } else {
                goto try_again;
            }
        } else {
            // We can only advance the epoch if every thread in a critical
            // section is in the current epoch.
            if (cur->in_critical_.load(mo_acq) &&
                cur->epoch_.load(mo_acq) != cur_epoch) {
                return false;
            }
            prevp = &cur->next_;
        }

        cur = next;
    }

    // Try to advance the global epoch
    uintptr_t new_epoch = cur_epoch + 1;
    if (!global_epoch_.compare_exchange_strong(cur_epoch, new_epoch,
                                               mo_acq_rel)) {
        return false;
    }

    // Garbage collect
    global_garbage_[(new_epoch+1) % kNumEpochs].collect();
    garbage_.collect();
    // Now that the collection is done, we can safely update our
    // local epoch.
    epoch_.store(new_epoch, mo_rel);

    return true;
}

void Participant::shutdown() noexcept {
    Participant::Ptr next = next_.load(mo_acq);
    Participant::Ptr exited_next;
    do {
        exited_next = Participant::Ptr(next, 1);
    } while (!next_.compare_exchange_weak(next, exited_next, mo_acq_rel));
}

/////////////
void RealLocalGarbage::collectBag(Bag &bag) {
    for (auto f : bag) {
        f();
    }
    // XXX: should we shrink capacity?
    bag.clear();
}

void RealLocalGarbage::collect() {
    if (size() == 0) return;

    collectBag(old_);
    std::swap(old_, cur_);
    std::swap(cur_, new_);
}

void RealLocalGarbage::migrateGarbage() {
    // We put all three local bags into the current global bag.
    // We could do better than this but why bother, I think.
    auto cleanup = [old = std::move(old_),
                    cur = std::move(cur_),
                    newp = std::move(new_)]() mutable {
        collectBag(old);
        collectBag(cur);
        collectBag(newp);
    };
    global_garbage_[global_epoch_ % kNumEpochs].registerCleanup(cleanup);
}

void DummyLocalGarbage::registerCleanup(GarbageCleanup f) {
    global_garbage_[global_epoch_ % kNumEpochs].registerCleanup(f);
}

/////////////
void ConcurrentBag::registerCleanup(ConcurrentBag::Cleanup f) {
    stack_.pushNode(new Node(std::move(f)));
}

void ConcurrentBag::collect() {
    // Pop the whole stack off
    // Since we only ever unconditionally destroy the whole stack,
    // we don't need to worry about ABA really.
    // (Which for stacks comes up if pop() believes that the address
    // of a node being the same means the next pointer is also...)
    std::unique_ptr<ConcurrentBag::Node> head(stack_.popAll());

    while (head) {
        head->data_();
        head.reset(head->next_);
    }
}

}
<commit_msg>Actually switch c11simp back to being the "almost always SC" version<commit_after>// Copyright (c) 2014-2017 Michael J. Sullivan
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

#include <atomic>
#include <utility>
#include <functional>
#include <memory>
#include "epoch_c11.hpp"
#include "remote_fence.hpp"
// Very very closely modeled after crossbeam by aturon.

namespace rmclib {
/////////////////////////////

const int kNumEpochs = 3;

thread_local LocalEpoch Epoch::local_epoch_;
std::atomic<Participant::Ptr> Participants::head_;

// XXX: Should this be in a class??
static std::atomic<uintptr_t> global_epoch_{0};
static ConcurrentBag global_garbage_[kNumEpochs];

Participant *Participants::enroll() {
    Participant *p = new Participant();

    Participant::Ptr head = head_;
    for (;;) {
        p->next_ = head;
        if (head_.compare_exchange_weak(head, p)) break;
    }

    return p;
}

/////// Participant is where most of the interesting stuff happens
bool Participant::quickEnter() noexcept {
    uintptr_t new_count = in_critical_.load(mo_rlx) + 1;
    in_critical_.store(new_count, mo_rlx);
    // Nothing to do if we were already in a critical section
    if (new_count > 1) return false;

    remote_thread_fence::placeholder(mo_sc);

    // Copy the global epoch to the local one
    uintptr_t global_epoch = global_epoch_.load(mo_rlx);
    epoch_.store(global_epoch, mo_rlx);
    return true;
}

void Participant::enter() noexcept {
    uintptr_t epoch = epoch_.load(mo_rlx);
    if (!quickEnter()) return;

    // If the epoch has changed, garbage collect
    if (epoch != epoch_.load(mo_rlx)) {
        garbage_.collect();
    }

    if (garbage_.needsCollect()) {
        tryCollect();
    }
}

void Participant::exit() noexcept {
    uintptr_t new_count = in_critical_.load(mo_rlx) - 1;
    // XXX: this may not need to be release
    // in our current setup, nothing can get freed until we do another
    // enter.
    // wait, does anything about the claim make any sense??
    in_critical_.store(new_count, mo_rel);
}

bool Participant::tryCollect() {
    uintptr_t cur_epoch = global_epoch_;

    remote_thread_fence::trigger();

    // Check whether all active threads are in the current epoch so we
    // can advance it.
    // As we do it, we lazily clean up exited threads.
    //
    // XXX: Do we want to factor out the list traversal?
try_again:
    std::atomic<Participant::Ptr> *prevp = &Participants::head_;
    Participant::Ptr cur = *prevp;
    while (cur) {
        Participant::Ptr next = cur->next_;
        if (next.tag()) {
            // This node has exited. Try to unlink it from the
            // list. This will fail if it's already been unlinked or
            // the previous node has exited; in those cases, we start
            // back over at the head of the list.
            next = Ptr(next, 0); // clear next's tag
            if (prevp->compare_exchange_strong(cur, next)) {
                Guard g(this);
                g.unlinked(cur.ptr());
            } else {
                goto try_again;
            }
        } else {
            // We can only advance the epoch if every thread in a critical
            // section is in the current epoch.
            if (cur->in_critical_ && cur->epoch_ != cur_epoch) {
                return false;
            }
            prevp = &cur->next_;
        }

        cur = next;
    }

    // Try to advance the global epoch
    uintptr_t new_epoch = cur_epoch + 1;
    if (!global_epoch_.compare_exchange_strong(cur_epoch, new_epoch)) {
        return false;
    }

    // Garbage collect
    global_garbage_[(new_epoch+1) % kNumEpochs].collect();
    garbage_.collect();
    // Now that the collection is done, we can safely update our
    // local epoch.
    epoch_ = new_epoch;

    return true;
}

void Participant::shutdown() noexcept {
    Participant::Ptr next = next_;
    Participant::Ptr exited_next;
    do {
        exited_next = Participant::Ptr(next, 1);
    } while (!next_.compare_exchange_weak(next, exited_next));
}

/////////////
void RealLocalGarbage::collectBag(Bag &bag) {
    for (auto f : bag) {
        f();
    }
    // XXX: should we shrink capacity?
    bag.clear();
}

void RealLocalGarbage::collect() {
    if (size() == 0) return;

    collectBag(old_);
    std::swap(old_, cur_);
    std::swap(cur_, new_);
}

void RealLocalGarbage::migrateGarbage() {
    // We put all three local bags into the current global bag.
    // We could do better than this but why bother, I think.
    auto cleanup = [old = std::move(old_),
                    cur = std::move(cur_),
                    newp = std::move(new_)]() mutable {
        collectBag(old);
        collectBag(cur);
        collectBag(newp);
    };
    global_garbage_[global_epoch_ % kNumEpochs].registerCleanup(cleanup);
}

void DummyLocalGarbage::registerCleanup(GarbageCleanup f) {
    global_garbage_[global_epoch_ % kNumEpochs].registerCleanup(f);
}

/////////////
void ConcurrentBag::registerCleanup(ConcurrentBag::Cleanup f) {
    stack_.pushNode(new Node(std::move(f)));
}

void ConcurrentBag::collect() {
    // Pop the whole stack off
    // Since we only ever unconditionally destroy the whole stack,
    // we don't need to worry about ABA really.
    // (Which for stacks comes up if pop() believes that the address
    // of a node being the same means the next pointer is also...)
    std::unique_ptr<ConcurrentBag::Node> head(stack_.popAll());

    while (head) {
        head->data_();
        head.reset(head->next_);
    }
}

}
<|endoftext|>


<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2012, Willow Garage, Inc.
*  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 Willow Garage 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: Ioan Sucan */

#include <ros/ros.h>
#include <planning_scene/planning_scene.h>
#include <robot_model_loader/robot_model_loader.h>
#include <pluginlib/class_loader.h>
#include <planning_interface/planning_interface.h>
#include <planning_models/conversions.h>

#include <moveit_msgs/ComputePlanningBenchmark.h>
#include <boost/lexical_cast.hpp>
#include <boost/progress.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/math/constants/constants.hpp>

#include <unistd.h>
#include <fstream>

static const std::string ROBOT_DESCRIPTION="robot_description";      // name of the robot description (a param name, so it can be changed externally)
static const std::string BENCHMARK_SERVICE_NAME="benchmark_planning_problem"; // name of the advertised service (within the ~ namespace)

class BenchmarkService
{
public:
  BenchmarkService(void)
  {
    // initialize a planning scene
    robot_model_loader::RobotModelLoader rml(ROBOT_DESCRIPTION);
    rml.getRobotDescription();
    if (rml.getURDF())
    {
      scene_.reset(new planning_scene::PlanningScene());
      scene_->configure(rml.getURDF(), rml.getSRDF() ? rml.getSRDF() : boost::shared_ptr<srdf::Model>(new srdf::Model()));
      if (scene_->isConfigured())
      {
        cscene_ = scene_;
        // load the planning plugins
        try
        {
          planner_plugin_loader_.reset(new pluginlib::ClassLoader<planning_interface::Planner>("planning_interface", "planning_interface::Planner"));
        }
        catch(pluginlib::PluginlibException& ex)
        {
          ROS_FATAL_STREAM("Exception while creating planning plugin loader " << ex.what());
        }

        const std::vector<std::string> &classes = planner_plugin_loader_->getDeclaredClasses();
        for (std::size_t i = 0 ; i < classes.size() ; ++i)
        {
          ROS_INFO("Attempting to load and configure %s", classes[i].c_str());
          try
          {
            planning_interface::Planner *p = planner_plugin_loader_->createClassInstance(classes[i]);
            p->init(scene_->getKinematicModel());
            planner_interfaces_[classes[i]].reset(p);
          }
          catch (pluginlib::PluginlibException& ex)
          {
            ROS_ERROR_STREAM("Exception while loading planner '" << classes[i] << "': " << ex.what());
          }
        }

        if (planner_interfaces_.empty())
          ROS_ERROR("No planning plugins have been loaded. Nothing to do for the benchmarking service.");
        else
        {
          std::stringstream ss;
          for (std::map<std::string, boost::shared_ptr<planning_interface::Planner> >::const_iterator it = planner_interfaces_.begin() ;
               it != planner_interfaces_.end(); ++it)
            ss << it->first << " ";
          ROS_INFO("Available planner instances: %s", ss.str().c_str());
          benchmark_service_ = nh_.advertiseService(BENCHMARK_SERVICE_NAME, &BenchmarkService::computeBenchmark, this);
        }
      }
      else
        ROS_ERROR("Unable to configure planning scene");
    }
    else
      ROS_ERROR("Unable to load URDF for parameter %s", ROBOT_DESCRIPTION.c_str());
  }

  bool computeBenchmark(moveit_msgs::ComputePlanningBenchmark::Request &req, moveit_msgs::ComputePlanningBenchmark::Response &res)
  {
    if (!req.planner_interfaces.empty())
      for (std::size_t i = 0 ; i < req.planner_interfaces.size() ; ++i)
        if (planner_interfaces_.find(req.planner_interfaces[i]) == planner_interfaces_.end())
          ROS_ERROR("Planning interface '%s' was not found", req.planner_interfaces[i].c_str());

    res.planner_interfaces.clear();
    std::vector<planning_interface::Planner*> pi;
    std::vector<planning_interface::PlannerCapability> pc;
    planning_interface::PlannerCapability capabilities;
    moveit_msgs::GetMotionPlan::Request mp_req;
    mp_req.motion_plan_request = req.motion_plan_request;

    for (std::map<std::string, boost::shared_ptr<planning_interface::Planner> >::const_iterator it = planner_interfaces_.begin() ;
         it != planner_interfaces_.end(); ++it)
    {
      if (!req.planner_interfaces.empty())
      {
        bool found = false;
        for (std::size_t i = 0 ; i < req.planner_interfaces.size() ; ++i)
          if (req.planner_interfaces[i] == it->first)
          {
            found = true;
            break;
          }
        if (!found)
          continue;
      }

      if (it->second->canServiceRequest(mp_req, capabilities))
      {
        res.planner_interfaces.push_back(it->first);
        pi.push_back(it->second.get());
        pc.push_back(capabilities);
      }
      else
        ROS_WARN_STREAM("Planning interface '" << it->second->getDescription() << "' is not able to solve the specified benchmark problem.");
    }

    if (pi.empty())
    {
      ROS_ERROR("There are no planning interfaces to benchmark");
      return false;
    }

    ROS_INFO("Benchmarking planning interfaces:");
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
      ROS_INFO_STREAM("  * " << pi[i]->getDescription());
    scene_->setPlanningSceneMsg(req.scene);
    res.responses.resize(pi.size());

    ros::WallTime startTime = ros::WallTime::now();
    boost::progress_display progress(pi.size() * req.average_count, std::cout);
    moveit_msgs::MotionPlanDetailedResponse mp_res;
    typedef std::vector<std::map<std::string, std::string> > RunData;
    std::vector<RunData> data;
    std::vector<bool> first(pi.size(), true);
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
    {
      RunData runs(req.average_count);
      for (unsigned int c = 0 ; c < req.average_count ; ++c)
      {
        ++progress;
        ros::WallTime start = ros::WallTime::now();
        bool solved = pi[i]->solve(cscene_, mp_req, mp_res);
        double total_time = (ros::WallTime::now() - start).toSec();

        // collect data
        runs[c]["total_time REAL"] = boost::lexical_cast<std::string>(total_time);
        runs[c]["solved BOOLEAN"] = boost::lexical_cast<std::string>(solved);
        double L = 0.0;
        double clearance = 0.0;
        double smoothness = 0.0;
        bool correct = true;
        if (solved)
        {
          double process_time = total_time;
          for (std::size_t j = 0 ; j < mp_res.trajectory.size() ; ++j)
          {
            std::vector<planning_models::KinematicStatePtr> p;
            scene_->convertToKinematicStates(mp_res.trajectory_start, mp_res.trajectory[j], p);

            // compute path length
            for (std::size_t k = 1 ; k < p.size() ; ++k)
              L += p[k-1]->distance(*p[k]);

            // compute correctness and clearance
            collision_detection::CollisionRequest req;
            for (std::size_t k = 0 ; k < p.size() ; ++k)
            {
              collision_detection::CollisionResult res;
              scene_->checkCollisionUnpadded(req, res, *p[k]);
              if (res.collision)
                correct = false;
              double d = scene_->distanceUnpadded(*p[k]);
              ROS_INFO("d = %lf", d);
              clearance += d;
            }
            clearance /= (double)p.size();

            // compute smoothness
            if (p.size() > 2)
            {
              double a = p[0]->distance(*p[1]);
              for (std::size_t k = 2 ; k < p.size() ; ++k)
              {
                // view the path as a sequence of segments, and look at the triangles it forms:
                //          s1
                //          /\          s4
                //      a  /  \ b       |
                //        /    \        |
                //       /......\_______|
                //     s0    c   s2     s3
                //
                // use Pythagoras generalized theorem to find the cos of the angle between segments a and b
                double b = p[k-1]->distance(*p[k]);
                double c = p[k-2]->distance(*p[k]);
                double acosValue = (a*a + b*b - c*c) / (2.0*a*b);
                if (acosValue > -1.0 && acosValue < 1.0)
                {
                  // the smoothness is actually the outside angle of the one we compute
                  double angle = (boost::math::constants::pi<double>() - acos(acosValue));

                  // and we normalize by the length of the segments
                  double u = 2.0 * angle / (a + b);
                  smoothness += u * u;
                }
                a = b;
              }
            }
            runs[c]["path_" + mp_res.description[j] + "_correct BOOLEAN"] = boost::lexical_cast<std::string>(correct);
            runs[c]["path_" + mp_res.description[j] + "_length REAL"] = boost::lexical_cast<std::string>(L);
            runs[c]["path_" + mp_res.description[j] + "_clearance REAL"] = boost::lexical_cast<std::string>(clearance);
            runs[c]["path_" + mp_res.description[j] + "_smoothness REAL"] = boost::lexical_cast<std::string>(smoothness);
            runs[c]["path_" + mp_res.description[j] + "_time REAL"] = boost::lexical_cast<std::string>(mp_res.processing_time[j]);
            process_time -= mp_res.processing_time[j].toSec();
          }
          if (process_time <= 0.0)
            process_time = 0.0;
          runs[c]["process_time REAL"] = boost::lexical_cast<std::string>(process_time);
        }

        // record the first solution in the response
        if (solved && first[i])
        {
          first[i] = false;
          res.responses[i] = mp_res;
        }
      }
      data.push_back(runs);
    }
    double duration = (ros::WallTime::now() - startTime).toSec();

    std::ofstream out(req.filename.c_str());
    std::string host = getHostname();

    out << "Experiment " << (cscene_->getName().empty() ? "NO_NAME" : cscene_->getName()) << std::endl;
    out << "Running on " << (host.empty() ? "UNKNOWN" : host) << std::endl;
    out << "Starting at " << boost::posix_time::to_iso_extended_string(startTime.toBoost()) << std::endl;
    out << "<<<|" << std::endl << "ROS" << std::endl << "|>>>" << std::endl;
    out << "0 is the random seed" << std::endl; // we do not record random seeds
    out << req.motion_plan_request.allowed_planning_time.toSec() << " seconds per run" << std::endl;
    out << "10240 MB per run" << std::endl; // we don't limit memory usage
    out << req.average_count << " runs per planner" << std::endl;
    out << duration << " seconds spent to collect the data" << std::endl;
    out << pi.size() << " planners" << std::endl;
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
    {
      out << pi[i]->getDescription() << std::endl;
      // in general, we could have properties specific for a planner;
      // right now, we do not include such properties
      out << "0 common properties" << std::endl;

      // construct the list of all possible properties for all runs
      std::set<std::string> propSeen;
      for (std::size_t j = 0 ; j < data[i].size() ; ++j)
        for (std::map<std::string, std::string>::const_iterator mit = data[i][j].begin() ; mit != data[i][j].end() ; ++mit)
          propSeen.insert(mit->first);
      std::vector<std::string> properties;
      for (std::set<std::string>::iterator it = propSeen.begin() ; it != propSeen.end() ; ++it)
        properties.push_back(*it);
      out << properties.size() << " properties for each run" << std::endl;
      for (unsigned int j = 0 ; j < properties.size() ; ++j)
        out << properties[j] << std::endl;
      out << data[i].size() << " runs" << std::endl;
      for (std::size_t j = 0 ; j < data[i].size() ; ++j)
      {
        for (unsigned int k = 0 ; k < properties.size() ; ++k)
        {
          std::map<std::string, std::string>::const_iterator it = data[i][j].find(properties[k]);
          if (it != data[i][j].end())
            out << it->second;
          out << "; ";
        }
        out << std::endl;
      }
      out << '.' << std::endl;
    }
    out.close();
    ROS_INFO("Results saved to '%s'", req.filename.c_str());
    res.error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
    return true;
  }

  void status(void) const
  {
  }

private:

  std::string getHostname(void) const
  {
    static const int BUF_SIZE = 1024;
    char buffer[BUF_SIZE];
    int err = gethostname(buffer, sizeof(buffer));
    if (err != 0)
      return std::string();
    else
    {
      buffer[BUF_SIZE - 1] = '\0';
      return std::string(buffer);
    }
  }

  ros::NodeHandle nh_;
  planning_scene::PlanningScenePtr scene_;
  planning_scene::PlanningSceneConstPtr cscene_;
  boost::shared_ptr<pluginlib::ClassLoader<planning_interface::Planner> > planner_plugin_loader_;
  std::map<std::string, boost::shared_ptr<planning_interface::Planner> > planner_interfaces_;
  ros::ServiceServer benchmark_service_;
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "planning_scene_benchmark", ros::init_options::AnonymousName);
  ros::AsyncSpinner spinner(1);
  spinner.start();

  BenchmarkService bs;
  bs.status();
  ros::waitForShutdown();

  return 0;
}
<commit_msg>remove extra output<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2012, Willow Garage, Inc.
*  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 Willow Garage 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: Ioan Sucan */

#include <ros/ros.h>
#include <planning_scene/planning_scene.h>
#include <robot_model_loader/robot_model_loader.h>
#include <pluginlib/class_loader.h>
#include <planning_interface/planning_interface.h>
#include <planning_models/conversions.h>

#include <moveit_msgs/ComputePlanningBenchmark.h>
#include <boost/lexical_cast.hpp>
#include <boost/progress.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/math/constants/constants.hpp>

#include <unistd.h>
#include <fstream>

static const std::string ROBOT_DESCRIPTION="robot_description";      // name of the robot description (a param name, so it can be changed externally)
static const std::string BENCHMARK_SERVICE_NAME="benchmark_planning_problem"; // name of the advertised service (within the ~ namespace)

class BenchmarkService
{
public:
  BenchmarkService(void)
  {
    // initialize a planning scene
    robot_model_loader::RobotModelLoader rml(ROBOT_DESCRIPTION);
    rml.getRobotDescription();
    if (rml.getURDF())
    {
      scene_.reset(new planning_scene::PlanningScene());
      scene_->configure(rml.getURDF(), rml.getSRDF() ? rml.getSRDF() : boost::shared_ptr<srdf::Model>(new srdf::Model()));
      if (scene_->isConfigured())
      {
        cscene_ = scene_;
        // load the planning plugins
        try
        {
          planner_plugin_loader_.reset(new pluginlib::ClassLoader<planning_interface::Planner>("planning_interface", "planning_interface::Planner"));
        }
        catch(pluginlib::PluginlibException& ex)
        {
          ROS_FATAL_STREAM("Exception while creating planning plugin loader " << ex.what());
        }

        const std::vector<std::string> &classes = planner_plugin_loader_->getDeclaredClasses();
        for (std::size_t i = 0 ; i < classes.size() ; ++i)
        {
          ROS_INFO("Attempting to load and configure %s", classes[i].c_str());
          try
          {
            planning_interface::Planner *p = planner_plugin_loader_->createClassInstance(classes[i]);
            p->init(scene_->getKinematicModel());
            planner_interfaces_[classes[i]].reset(p);
          }
          catch (pluginlib::PluginlibException& ex)
          {
            ROS_ERROR_STREAM("Exception while loading planner '" << classes[i] << "': " << ex.what());
          }
        }

        if (planner_interfaces_.empty())
          ROS_ERROR("No planning plugins have been loaded. Nothing to do for the benchmarking service.");
        else
        {
          std::stringstream ss;
          for (std::map<std::string, boost::shared_ptr<planning_interface::Planner> >::const_iterator it = planner_interfaces_.begin() ;
               it != planner_interfaces_.end(); ++it)
            ss << it->first << " ";
          ROS_INFO("Available planner instances: %s", ss.str().c_str());
          benchmark_service_ = nh_.advertiseService(BENCHMARK_SERVICE_NAME, &BenchmarkService::computeBenchmark, this);
        }
      }
      else
        ROS_ERROR("Unable to configure planning scene");
    }
    else
      ROS_ERROR("Unable to load URDF for parameter %s", ROBOT_DESCRIPTION.c_str());
  }

  bool computeBenchmark(moveit_msgs::ComputePlanningBenchmark::Request &req, moveit_msgs::ComputePlanningBenchmark::Response &res)
  {
    if (!req.planner_interfaces.empty())
      for (std::size_t i = 0 ; i < req.planner_interfaces.size() ; ++i)
        if (planner_interfaces_.find(req.planner_interfaces[i]) == planner_interfaces_.end())
          ROS_ERROR("Planning interface '%s' was not found", req.planner_interfaces[i].c_str());

    res.planner_interfaces.clear();
    std::vector<planning_interface::Planner*> pi;
    std::vector<planning_interface::PlannerCapability> pc;
    planning_interface::PlannerCapability capabilities;
    moveit_msgs::GetMotionPlan::Request mp_req;
    mp_req.motion_plan_request = req.motion_plan_request;

    for (std::map<std::string, boost::shared_ptr<planning_interface::Planner> >::const_iterator it = planner_interfaces_.begin() ;
         it != planner_interfaces_.end(); ++it)
    {
      if (!req.planner_interfaces.empty())
      {
        bool found = false;
        for (std::size_t i = 0 ; i < req.planner_interfaces.size() ; ++i)
          if (req.planner_interfaces[i] == it->first)
          {
            found = true;
            break;
          }
        if (!found)
          continue;
      }

      if (it->second->canServiceRequest(mp_req, capabilities))
      {
        res.planner_interfaces.push_back(it->first);
        pi.push_back(it->second.get());
        pc.push_back(capabilities);
      }
      else
        ROS_WARN_STREAM("Planning interface '" << it->second->getDescription() << "' is not able to solve the specified benchmark problem.");
    }

    if (pi.empty())
    {
      ROS_ERROR("There are no planning interfaces to benchmark");
      return false;
    }

    ROS_INFO("Benchmarking planning interfaces:");
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
      ROS_INFO_STREAM("  * " << pi[i]->getDescription());
    scene_->setPlanningSceneMsg(req.scene);
    res.responses.resize(pi.size());

    ros::WallTime startTime = ros::WallTime::now();
    boost::progress_display progress(pi.size() * req.average_count, std::cout);
    moveit_msgs::MotionPlanDetailedResponse mp_res;
    typedef std::vector<std::map<std::string, std::string> > RunData;
    std::vector<RunData> data;
    std::vector<bool> first(pi.size(), true);
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
    {
      RunData runs(req.average_count);
      for (unsigned int c = 0 ; c < req.average_count ; ++c)
      {
        ++progress;
        ros::WallTime start = ros::WallTime::now();
        bool solved = pi[i]->solve(cscene_, mp_req, mp_res);
        double total_time = (ros::WallTime::now() - start).toSec();

        // collect data
        runs[c]["total_time REAL"] = boost::lexical_cast<std::string>(total_time);
        runs[c]["solved BOOLEAN"] = boost::lexical_cast<std::string>(solved);
        double L = 0.0;
        double clearance = 0.0;
        double smoothness = 0.0;
        bool correct = true;
        if (solved)
        {
          double process_time = total_time;
          for (std::size_t j = 0 ; j < mp_res.trajectory.size() ; ++j)
          {
            std::vector<planning_models::KinematicStatePtr> p;
            scene_->convertToKinematicStates(mp_res.trajectory_start, mp_res.trajectory[j], p);

            // compute path length
            for (std::size_t k = 1 ; k < p.size() ; ++k)
              L += p[k-1]->distance(*p[k]);

            // compute correctness and clearance
            collision_detection::CollisionRequest req;
            for (std::size_t k = 0 ; k < p.size() ; ++k)
            {
              collision_detection::CollisionResult res;
              scene_->checkCollisionUnpadded(req, res, *p[k]);
              if (res.collision)
                correct = false;
              double d = scene_->distanceUnpadded(*p[k]);
              clearance += d;
            }
            clearance /= (double)p.size();

            // compute smoothness
            if (p.size() > 2)
            {
              double a = p[0]->distance(*p[1]);
              for (std::size_t k = 2 ; k < p.size() ; ++k)
              {
                // view the path as a sequence of segments, and look at the triangles it forms:
                //          s1
                //          /\          s4
                //      a  /  \ b       |
                //        /    \        |
                //       /......\_______|
                //     s0    c   s2     s3
                //
                // use Pythagoras generalized theorem to find the cos of the angle between segments a and b
                double b = p[k-1]->distance(*p[k]);
                double c = p[k-2]->distance(*p[k]);
                double acosValue = (a*a + b*b - c*c) / (2.0*a*b);
                if (acosValue > -1.0 && acosValue < 1.0)
                {
                  // the smoothness is actually the outside angle of the one we compute
                  double angle = (boost::math::constants::pi<double>() - acos(acosValue));

                  // and we normalize by the length of the segments
                  double u = 2.0 * angle / (a + b);
                  smoothness += u * u;
                }
                a = b;
              }
            }
            runs[c]["path_" + mp_res.description[j] + "_correct BOOLEAN"] = boost::lexical_cast<std::string>(correct);
            runs[c]["path_" + mp_res.description[j] + "_length REAL"] = boost::lexical_cast<std::string>(L);
            runs[c]["path_" + mp_res.description[j] + "_clearance REAL"] = boost::lexical_cast<std::string>(clearance);
            runs[c]["path_" + mp_res.description[j] + "_smoothness REAL"] = boost::lexical_cast<std::string>(smoothness);
            runs[c]["path_" + mp_res.description[j] + "_time REAL"] = boost::lexical_cast<std::string>(mp_res.processing_time[j]);
            process_time -= mp_res.processing_time[j].toSec();
          }
          if (process_time <= 0.0)
            process_time = 0.0;
          runs[c]["process_time REAL"] = boost::lexical_cast<std::string>(process_time);
        }

        // record the first solution in the response
        if (solved && first[i])
        {
          first[i] = false;
          res.responses[i] = mp_res;
        }
      }
      data.push_back(runs);
    }
    double duration = (ros::WallTime::now() - startTime).toSec();

    std::ofstream out(req.filename.c_str());
    std::string host = getHostname();

    out << "Experiment " << (cscene_->getName().empty() ? "NO_NAME" : cscene_->getName()) << std::endl;
    out << "Running on " << (host.empty() ? "UNKNOWN" : host) << std::endl;
    out << "Starting at " << boost::posix_time::to_iso_extended_string(startTime.toBoost()) << std::endl;
    out << "<<<|" << std::endl << "ROS" << std::endl << "|>>>" << std::endl;
    out << "0 is the random seed" << std::endl; // we do not record random seeds
    out << req.motion_plan_request.allowed_planning_time.toSec() << " seconds per run" << std::endl;
    out << "10240 MB per run" << std::endl; // we don't limit memory usage
    out << req.average_count << " runs per planner" << std::endl;
    out << duration << " seconds spent to collect the data" << std::endl;
    out << pi.size() << " planners" << std::endl;
    for (std::size_t i = 0 ; i < pi.size() ; ++i)
    {
      out << pi[i]->getDescription() << std::endl;
      // in general, we could have properties specific for a planner;
      // right now, we do not include such properties
      out << "0 common properties" << std::endl;

      // construct the list of all possible properties for all runs
      std::set<std::string> propSeen;
      for (std::size_t j = 0 ; j < data[i].size() ; ++j)
        for (std::map<std::string, std::string>::const_iterator mit = data[i][j].begin() ; mit != data[i][j].end() ; ++mit)
          propSeen.insert(mit->first);
      std::vector<std::string> properties;
      for (std::set<std::string>::iterator it = propSeen.begin() ; it != propSeen.end() ; ++it)
        properties.push_back(*it);
      out << properties.size() << " properties for each run" << std::endl;
      for (unsigned int j = 0 ; j < properties.size() ; ++j)
        out << properties[j] << std::endl;
      out << data[i].size() << " runs" << std::endl;
      for (std::size_t j = 0 ; j < data[i].size() ; ++j)
      {
        for (unsigned int k = 0 ; k < properties.size() ; ++k)
        {
          std::map<std::string, std::string>::const_iterator it = data[i][j].find(properties[k]);
          if (it != data[i][j].end())
            out << it->second;
          out << "; ";
        }
        out << std::endl;
      }
      out << '.' << std::endl;
    }
    out.close();
    ROS_INFO("Results saved to '%s'", req.filename.c_str());
    res.error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
    return true;
  }

  void status(void) const
  {
  }

private:

  std::string getHostname(void) const
  {
    static const int BUF_SIZE = 1024;
    char buffer[BUF_SIZE];
    int err = gethostname(buffer, sizeof(buffer));
    if (err != 0)
      return std::string();
    else
    {
      buffer[BUF_SIZE - 1] = '\0';
      return std::string(buffer);
    }
  }

  ros::NodeHandle nh_;
  planning_scene::PlanningScenePtr scene_;
  planning_scene::PlanningSceneConstPtr cscene_;
  boost::shared_ptr<pluginlib::ClassLoader<planning_interface::Planner> > planner_plugin_loader_;
  std::map<std::string, boost::shared_ptr<planning_interface::Planner> > planner_interfaces_;
  ros::ServiceServer benchmark_service_;
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "planning_scene_benchmark", ros::init_options::AnonymousName);
  ros::AsyncSpinner spinner(1);
  spinner.start();

  BenchmarkService bs;
  bs.status();
  ros::waitForShutdown();

  return 0;
}
<|endoftext|>


<commit_before>// Vasilii Bodnariuk

#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <string>

using namespace std;

int good_str(char* data) {
    int i = 0;
    bool binary_operator = false;
    while(data[i] != '\0') {
        switch (data[i]) {
            case '+':
            case '/':
            case '*':
                if(binary_operator) {
                    return 0;
                }
                binary_operator = true;
                break;
            case ' ':
                break;
            case '-':
                if(binary_operator) {
                    data[i] = '~';
                }
                else {
                    binary_operator = true;
                }
                break;
            default:
                if(data[i] < '0' || data[i] > '9') {
                    return 0;
                }
                binary_operator = false;
        }
        ++i;
    }
    return i;
}

int digit(char c) {
    return int(c) - '0';
}

int skip_blanks(char* data, int start) {
    while(data[start] == ' ') {
        ++start;
    }

    return start;
}

int number(char* data, int start, int len) {
    int accumulator = 0;
    int i = skip_blanks(data, start);

    bool negative = data[i] == '~';
    if (negative) {
        ++i;
    }
    i = skip_blanks(data, i);

    while(data[i] >= '0' && data[i] <= '9')
    {
        accumulator = 10 * accumulator + digit(data[i]);
        ++i;
    }

    return negative ? -accumulator : accumulator;
}

double term(char* data, int start, int len, bool last_mult) {
    start = skip_blanks(data, start);
    int i = start;

    while(i < len) {
        switch (data[i]) {
            case '*':
            case '/':
                if (true) {
                    double tail = term(data, i + 1, len, data[i] == '*');
                    if((data[i] == '/') == last_mult) {
                        return number(data, start, i) / tail;
                    }
                    else {
                        return number(data, start, i) * tail;
                    }
                }
        }
        ++i;
        i = skip_blanks(data, i);
    }

    return number(data, start, len);
}

double expression(char* data, int start, int len, bool last_plus) {
    start = skip_blanks(data, start);
    int i = start;

    while(i < len) {
        switch (data[i]) {
            case '-':
            case '+':
                {
                    double tail = expression(data, i + 1, len, data[i] == '+');
                    if((data[i] == '-') == last_plus) {
                        tail = - tail;
                    }
                    return term(data, start, i, true) + tail;
                }
        }

        ++i;
        i = skip_blanks(data, i);
    }

    return term(data, start, len, true);
}

int main(int argc, char* argv[])
{
    if(argc != 2) {
        cout << "usage:" << '\n';
        cout << argv[0] << " expression" << '\n';
        cout << "example:" << '\n';
        cout << argv[0] << " \"-12 * 2 / 3 + 8 * 2 / 1\"" << '\n';
    } else {
        auto data = argv[1];
        double e;
        int len = good_str(data);
        if (len > 0) {
            e = expression(data, 0, len, true);
            cout << e << "\n";
        } else {
            cout << "r u kiddin' me?" << "\n";
            return -1;
        }
    }

    return 0;
}
<commit_msg>err msg changed<commit_after>// Vasilii Bodnariuk

#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <string>

using namespace std;

int good_str(char* data) {
    int i = 0;
    bool binary_operator = false;
    while(data[i] != '\0') {
        switch (data[i]) {
            case '+':
            case '/':
            case '*':
                if(binary_operator) {
                    return 0;
                }
                binary_operator = true;
                break;
            case ' ':
                break;
            case '-':
                if(binary_operator) {
                    data[i] = '~';
                }
                else {
                    binary_operator = true;
                }
                break;
            default:
                if(data[i] < '0' || data[i] > '9') {
                    return 0;
                }
                binary_operator = false;
        }
        ++i;
    }
    return i;
}

int digit(char c) {
    return int(c) - '0';
}

int skip_blanks(char* data, int start) {
    while(data[start] == ' ') {
        ++start;
    }

    return start;
}

int number(char* data, int start, int len) {
    int accumulator = 0;
    int i = skip_blanks(data, start);

    bool negative = data[i] == '~';
    if (negative) {
        ++i;
    }
    i = skip_blanks(data, i);

    while(data[i] >= '0' && data[i] <= '9')
    {
        accumulator = 10 * accumulator + digit(data[i]);
        ++i;
    }

    return negative ? -accumulator : accumulator;
}

double term(char* data, int start, int len, bool last_mult) {
    start = skip_blanks(data, start);
    int i = start;

    while(i < len) {
        switch (data[i]) {
            case '*':
            case '/':
                if (true) {
                    double tail = term(data, i + 1, len, data[i] == '*');
                    if((data[i] == '/') == last_mult) {
                        return number(data, start, i) / tail;
                    }
                    else {
                        return number(data, start, i) * tail;
                    }
                }
        }
        ++i;
        i = skip_blanks(data, i);
    }

    return number(data, start, len);
}

double expression(char* data, int start, int len, bool last_plus) {
    start = skip_blanks(data, start);
    int i = start;

    while(i < len) {
        switch (data[i]) {
            case '-':
            case '+':
                {
                    double tail = expression(data, i + 1, len, data[i] == '+');
                    if((data[i] == '-') == last_plus) {
                        tail = - tail;
                    }
                    return term(data, start, i, true) + tail;
                }
        }

        ++i;
        i = skip_blanks(data, i);
    }

    return term(data, start, len, true);
}

int main(int argc, char* argv[])
{
    if(argc != 2) {
        cout << "usage:" << '\n';
        cout << argv[0] << " expression" << '\n';
        cout << "example:" << '\n';
        cout << argv[0] << " \"-12 * 2 / 3 + 8 * 2 / 1\"" << '\n';
    } else {
        auto data = argv[1];
        double e;
        int len = good_str(data);
        if (len > 0) {
            e = expression(data, 0, len, true);
            cout << e << "\n";
        } else {
            cout << "The program processes an arithmetic expression of integers!" << "\n";
            return -1;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * 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
 *
 * 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.
 */

/*
 * Modified by ScyllaDB
 * Copyright (C) 2015-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>
#include "schema_fwd.hh"
#include "utils/UUID.hh"
#include "gms/inet_address.hh"
#include "query-result-set.hh"
#include "db_clock.hh"
#include "db/commitlog/replay_position.hh"
#include "mutation_query.hh"
#include <map>
#include <seastar/core/distributed.hh>
#include "cdc/generation_id.hh"

namespace service {

class storage_proxy;
class storage_service;

namespace paxos {
    class paxos_state;
    class proposal;
} // namespace service::paxos

}

namespace netw {
    class messaging_service;
}

namespace cql3 {
    class query_processor;
}

namespace gms {
    class feature;
    class feature_service;
}

namespace locator {
    class endpoint_dc_rack;
} // namespace locator

bool is_system_keyspace(std::string_view ks_name);

namespace db {

sstring system_keyspace_name();

class config;

namespace system_keyspace {

static constexpr auto NAME = "system";
static constexpr auto HINTS = "hints";
static constexpr auto BATCHLOG = "batchlog";
static constexpr auto PAXOS = "paxos";
static constexpr auto BUILT_INDEXES = "IndexInfo";
static constexpr auto LOCAL = "local";
static constexpr auto TRUNCATED = "truncated";
static constexpr auto PEERS = "peers";
static constexpr auto PEER_EVENTS = "peer_events";
static constexpr auto RANGE_XFERS = "range_xfers";
static constexpr auto COMPACTIONS_IN_PROGRESS = "compactions_in_progress";
static constexpr auto COMPACTION_HISTORY = "compaction_history";
static constexpr auto SSTABLE_ACTIVITY = "sstable_activity";
static constexpr auto SIZE_ESTIMATES = "size_estimates";
static constexpr auto LARGE_PARTITIONS = "large_partitions";
static constexpr auto LARGE_ROWS = "large_rows";
static constexpr auto LARGE_CELLS = "large_cells";
static constexpr auto SCYLLA_LOCAL = "scylla_local";
static constexpr auto RAFT = "raft";
static constexpr auto RAFT_SNAPSHOTS = "raft_snapshots";
static constexpr auto RAFT_CONFIG = "raft_config";
extern const char *const CLIENTS;

namespace v3 {
static constexpr auto BATCHES = "batches";
static constexpr auto PAXOS = "paxos";
static constexpr auto BUILT_INDEXES = "IndexInfo";
static constexpr auto LOCAL = "local";
static constexpr auto PEERS = "peers";
static constexpr auto PEER_EVENTS = "peer_events";
static constexpr auto RANGE_XFERS = "range_xfers";
static constexpr auto COMPACTION_HISTORY = "compaction_history";
static constexpr auto SSTABLE_ACTIVITY = "sstable_activity";
static constexpr auto SIZE_ESTIMATES = "size_estimates";
static constexpr auto AVAILABLE_RANGES = "available_ranges";
static constexpr auto VIEWS_BUILDS_IN_PROGRESS = "views_builds_in_progress";
static constexpr auto BUILT_VIEWS = "built_views";
static constexpr auto SCYLLA_VIEWS_BUILDS_IN_PROGRESS = "scylla_views_builds_in_progress";
static constexpr auto CDC_LOCAL = "cdc_local";
}

namespace legacy {
static constexpr auto HINTS = "hints";
static constexpr auto BATCHLOG = "batchlog";
static constexpr auto KEYSPACES = "schema_keyspaces";
static constexpr auto COLUMNFAMILIES = "schema_columnfamilies";
static constexpr auto COLUMNS = "schema_columns";
static constexpr auto TRIGGERS = "schema_triggers";
static constexpr auto USERTYPES = "schema_usertypes";
static constexpr auto FUNCTIONS = "schema_functions";
static constexpr auto AGGREGATES = "schema_aggregates";
}

static constexpr const char* extra_durable_tables[] = { PAXOS };

bool is_extra_durable(const sstring& name);

// Partition estimates for a given range of tokens.
struct range_estimates {
    schema_ptr schema;
    bytes range_start_token;
    bytes range_end_token;
    int64_t partitions_count;
    int64_t mean_partition_size;
};

using view_name = std::pair<sstring, sstring>;
struct view_build_progress;

extern schema_ptr hints();
extern schema_ptr batchlog();
extern schema_ptr paxos();
extern schema_ptr built_indexes(); // TODO (from Cassandra): make private
schema_ptr raft();
schema_ptr raft_snapshots();

namespace legacy {

schema_ptr keyspaces();
schema_ptr column_families();
schema_ptr columns();
schema_ptr triggers();
schema_ptr usertypes();
schema_ptr functions();
schema_ptr aggregates();

}

table_schema_version generate_schema_version(utils::UUID table_id, uint16_t offset = 0);

// Only for testing.
void minimal_setup(distributed<cql3::query_processor>& qp);

future<> init_local_cache();
future<> deinit_local_cache();
future<> setup(distributed<database>& db,
               distributed<cql3::query_processor>& qp,
               distributed<gms::feature_service>& feat,
               sharded<netw::messaging_service>& ms);
future<> update_schema_version(utils::UUID version);

/*
 * Save tokens used by this node in the LOCAL table.
 */
future<> update_tokens(const std::unordered_set<dht::token>& tokens);

/**
 * Record tokens being used by another node in the PEERS table.
 */
future<> update_tokens(gms::inet_address ep, const std::unordered_set<dht::token>& tokens);

future<> update_preferred_ip(gms::inet_address ep, gms::inet_address preferred_ip);
future<std::unordered_map<gms::inet_address, gms::inet_address>> get_preferred_ips();

template <typename Value>
future<> update_peer_info(gms::inet_address ep, sstring column_name, Value value);

future<> remove_endpoint(gms::inet_address ep);

future<> set_scylla_local_param(const sstring& key, const sstring& value);
future<std::optional<sstring>> get_scylla_local_param(const sstring& key);

std::vector<schema_ptr> all_tables(const db::config& cfg);
future<> make(database& db, service::storage_service& ss);

/// overloads

future<foreign_ptr<lw_shared_ptr<reconcilable_result>>>
query_mutations(distributed<service::storage_proxy>& proxy,
                const sstring& ks_name,
                const sstring& cf_name);

// Returns all data from given system table.
// Intended to be used by code which is not performance critical.
future<lw_shared_ptr<query::result_set>> query(distributed<service::storage_proxy>& proxy,
                const sstring& ks_name,
                const sstring& cf_name);

// Returns a slice of given system table.
// Intended to be used by code which is not performance critical.
future<lw_shared_ptr<query::result_set>> query(
    distributed<service::storage_proxy>& proxy,
    const sstring& ks_name,
    const sstring& cf_name,
    const dht::decorated_key& key,
    query::clustering_range row_ranges = query::clustering_range::make_open_ended_both_sides());

/**
 * Return a map of IP addresses containing a map of dc and rack info
 */
std::unordered_map<gms::inet_address, locator::endpoint_dc_rack>
load_dc_rack_info();

enum class bootstrap_state {
    NEEDS_BOOTSTRAP,
    COMPLETED,
    IN_PROGRESS,
    DECOMMISSIONED
};

    struct compaction_history_entry {
        utils::UUID id;
        sstring ks;
        sstring cf;
        int64_t compacted_at = 0;
        int64_t bytes_in = 0;
        int64_t bytes_out = 0;
        // Key: number of rows merged
        // Value: counter
        std::unordered_map<int32_t, int64_t> rows_merged;
    };

    future<> update_compaction_history(utils::UUID uuid, sstring ksname, sstring cfname, int64_t compacted_at, int64_t bytes_in, int64_t bytes_out,
                                       std::unordered_map<int32_t, int64_t> rows_merged);
    using compaction_history_consumer = noncopyable_function<future<>(const compaction_history_entry&)>;
    future<> get_compaction_history(compaction_history_consumer&& f);

    typedef std::vector<db::replay_position> replay_positions;

    future<> save_truncation_record(utils::UUID, db_clock::time_point truncated_at, db::replay_position);
    future<> save_truncation_record(const column_family&, db_clock::time_point truncated_at, db::replay_position);
    future<replay_positions> get_truncated_position(utils::UUID);
    future<db::replay_position> get_truncated_position(utils::UUID, uint32_t shard);
    future<db_clock::time_point> get_truncated_at(utils::UUID);

    /**
     * Return a map of stored tokens to IP addresses
     *
     */
    future<std::unordered_map<gms::inet_address, std::unordered_set<dht::token>>> load_tokens();

    /**
     * Return a map of store host_ids to IP addresses
     *
     */
    future<std::unordered_map<gms::inet_address, utils::UUID>> load_host_ids();

    /*
     * Read this node's tokens stored in the LOCAL table.
     * Used to initialize a restarting node.
     */
    future<std::unordered_set<dht::token>> get_saved_tokens();

    /*
     * Gets this node's non-empty set of tokens.
     * TODO: maybe get this data from token_metadata instance?
     */
    future<std::unordered_set<dht::token>> get_local_tokens();

    future<std::unordered_map<gms::inet_address, sstring>> load_peer_features();

future<int> increment_and_get_generation();
bool bootstrap_complete();
bool bootstrap_in_progress();
bootstrap_state get_bootstrap_state();
bool was_decommissioned();
future<> set_bootstrap_state(bootstrap_state state);

    /**
     * Read the host ID from the system keyspace, creating (and storing) one if
     * none exists.
     */
    future<utils::UUID> get_local_host_id();

    /**
     * Sets the local host ID explicitly.  Should only be called outside of SystemTable when replacing a node.
     */
    future<utils::UUID> set_local_host_id(const utils::UUID& host_id);

    api::timestamp_type schema_creation_timestamp();

/**
 * Builds a mutation for SIZE_ESTIMATES_CF containing the specified estimates.
 */
mutation make_size_estimates_mutation(const sstring& ks, std::vector<range_estimates> estimates);

future<> register_view_for_building(sstring ks_name, sstring view_name, const dht::token& token);
future<> update_view_build_progress(sstring ks_name, sstring view_name, const dht::token& token);
future<> remove_view_build_progress(sstring ks_name, sstring view_name);
future<> remove_view_build_progress_across_all_shards(sstring ks_name, sstring view_name);
future<> mark_view_as_built(sstring ks_name, sstring view_name);
future<> remove_built_view(sstring ks_name, sstring view_name);
future<std::vector<view_name>> load_built_views();
future<std::vector<view_build_progress>> load_view_build_progress();

// Paxos related functions
future<service::paxos::paxos_state> load_paxos_state(partition_key_view key, schema_ptr s, gc_clock::time_point now,
        db::timeout_clock::time_point timeout);
future<> save_paxos_promise(const schema& s, const partition_key& key, const utils::UUID& ballot, db::timeout_clock::time_point timeout);
future<> save_paxos_proposal(const schema& s, const service::paxos::proposal& proposal, db::timeout_clock::time_point timeout);
future<> save_paxos_decision(const schema& s, const service::paxos::proposal& decision, db::timeout_clock::time_point timeout);
future<> delete_paxos_decision(const schema& s, const partition_key& key, const utils::UUID& ballot, db::timeout_clock::time_point timeout);

// CDC related functions

/*
 * Save the CDC generation ID announced by this node in persistent storage.
 */
future<> update_cdc_generation_id(cdc::generation_id);

/*
 * Read the CDC generation ID announced by this node from persistent storage.
 * Used to initialize a restarting node.
 */
future<std::optional<cdc::generation_id>> get_cdc_generation_id();

future<bool> cdc_is_rewritten();
future<> cdc_set_rewritten(std::optional<cdc::generation_id_v1>);

} // namespace system_keyspace
} // namespace db
<commit_msg>system_keyspace: rearrange legacy subnamespace<commit_after>/*
 * 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
 *
 * 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.
 */

/*
 * Modified by ScyllaDB
 * Copyright (C) 2015-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>
#include "schema_fwd.hh"
#include "utils/UUID.hh"
#include "gms/inet_address.hh"
#include "query-result-set.hh"
#include "db_clock.hh"
#include "db/commitlog/replay_position.hh"
#include "mutation_query.hh"
#include <map>
#include <seastar/core/distributed.hh>
#include "cdc/generation_id.hh"

namespace service {

class storage_proxy;
class storage_service;

namespace paxos {
    class paxos_state;
    class proposal;
} // namespace service::paxos

}

namespace netw {
    class messaging_service;
}

namespace cql3 {
    class query_processor;
}

namespace gms {
    class feature;
    class feature_service;
}

namespace locator {
    class endpoint_dc_rack;
} // namespace locator

bool is_system_keyspace(std::string_view ks_name);

namespace db {

sstring system_keyspace_name();

class config;

namespace system_keyspace {

static constexpr auto NAME = "system";
static constexpr auto HINTS = "hints";
static constexpr auto BATCHLOG = "batchlog";
static constexpr auto PAXOS = "paxos";
static constexpr auto BUILT_INDEXES = "IndexInfo";
static constexpr auto LOCAL = "local";
static constexpr auto TRUNCATED = "truncated";
static constexpr auto PEERS = "peers";
static constexpr auto PEER_EVENTS = "peer_events";
static constexpr auto RANGE_XFERS = "range_xfers";
static constexpr auto COMPACTIONS_IN_PROGRESS = "compactions_in_progress";
static constexpr auto COMPACTION_HISTORY = "compaction_history";
static constexpr auto SSTABLE_ACTIVITY = "sstable_activity";
static constexpr auto SIZE_ESTIMATES = "size_estimates";
static constexpr auto LARGE_PARTITIONS = "large_partitions";
static constexpr auto LARGE_ROWS = "large_rows";
static constexpr auto LARGE_CELLS = "large_cells";
static constexpr auto SCYLLA_LOCAL = "scylla_local";
static constexpr auto RAFT = "raft";
static constexpr auto RAFT_SNAPSHOTS = "raft_snapshots";
static constexpr auto RAFT_CONFIG = "raft_config";
extern const char *const CLIENTS;

namespace v3 {
static constexpr auto BATCHES = "batches";
static constexpr auto PAXOS = "paxos";
static constexpr auto BUILT_INDEXES = "IndexInfo";
static constexpr auto LOCAL = "local";
static constexpr auto PEERS = "peers";
static constexpr auto PEER_EVENTS = "peer_events";
static constexpr auto RANGE_XFERS = "range_xfers";
static constexpr auto COMPACTION_HISTORY = "compaction_history";
static constexpr auto SSTABLE_ACTIVITY = "sstable_activity";
static constexpr auto SIZE_ESTIMATES = "size_estimates";
static constexpr auto AVAILABLE_RANGES = "available_ranges";
static constexpr auto VIEWS_BUILDS_IN_PROGRESS = "views_builds_in_progress";
static constexpr auto BUILT_VIEWS = "built_views";
static constexpr auto SCYLLA_VIEWS_BUILDS_IN_PROGRESS = "scylla_views_builds_in_progress";
static constexpr auto CDC_LOCAL = "cdc_local";
}

namespace legacy {
static constexpr auto HINTS = "hints";
static constexpr auto BATCHLOG = "batchlog";
static constexpr auto KEYSPACES = "schema_keyspaces";
static constexpr auto COLUMNFAMILIES = "schema_columnfamilies";
static constexpr auto COLUMNS = "schema_columns";
static constexpr auto TRIGGERS = "schema_triggers";
static constexpr auto USERTYPES = "schema_usertypes";
static constexpr auto FUNCTIONS = "schema_functions";
static constexpr auto AGGREGATES = "schema_aggregates";

schema_ptr keyspaces();
schema_ptr column_families();
schema_ptr columns();
schema_ptr triggers();
schema_ptr usertypes();
schema_ptr functions();
schema_ptr aggregates();

}

static constexpr const char* extra_durable_tables[] = { PAXOS };

bool is_extra_durable(const sstring& name);

// Partition estimates for a given range of tokens.
struct range_estimates {
    schema_ptr schema;
    bytes range_start_token;
    bytes range_end_token;
    int64_t partitions_count;
    int64_t mean_partition_size;
};

using view_name = std::pair<sstring, sstring>;
struct view_build_progress;

extern schema_ptr hints();
extern schema_ptr batchlog();
extern schema_ptr paxos();
extern schema_ptr built_indexes(); // TODO (from Cassandra): make private
schema_ptr raft();
schema_ptr raft_snapshots();

table_schema_version generate_schema_version(utils::UUID table_id, uint16_t offset = 0);

// Only for testing.
void minimal_setup(distributed<cql3::query_processor>& qp);

future<> init_local_cache();
future<> deinit_local_cache();
future<> setup(distributed<database>& db,
               distributed<cql3::query_processor>& qp,
               distributed<gms::feature_service>& feat,
               sharded<netw::messaging_service>& ms);
future<> update_schema_version(utils::UUID version);

/*
 * Save tokens used by this node in the LOCAL table.
 */
future<> update_tokens(const std::unordered_set<dht::token>& tokens);

/**
 * Record tokens being used by another node in the PEERS table.
 */
future<> update_tokens(gms::inet_address ep, const std::unordered_set<dht::token>& tokens);

future<> update_preferred_ip(gms::inet_address ep, gms::inet_address preferred_ip);
future<std::unordered_map<gms::inet_address, gms::inet_address>> get_preferred_ips();

template <typename Value>
future<> update_peer_info(gms::inet_address ep, sstring column_name, Value value);

future<> remove_endpoint(gms::inet_address ep);

future<> set_scylla_local_param(const sstring& key, const sstring& value);
future<std::optional<sstring>> get_scylla_local_param(const sstring& key);

std::vector<schema_ptr> all_tables(const db::config& cfg);
future<> make(database& db, service::storage_service& ss);

/// overloads

future<foreign_ptr<lw_shared_ptr<reconcilable_result>>>
query_mutations(distributed<service::storage_proxy>& proxy,
                const sstring& ks_name,
                const sstring& cf_name);

// Returns all data from given system table.
// Intended to be used by code which is not performance critical.
future<lw_shared_ptr<query::result_set>> query(distributed<service::storage_proxy>& proxy,
                const sstring& ks_name,
                const sstring& cf_name);

// Returns a slice of given system table.
// Intended to be used by code which is not performance critical.
future<lw_shared_ptr<query::result_set>> query(
    distributed<service::storage_proxy>& proxy,
    const sstring& ks_name,
    const sstring& cf_name,
    const dht::decorated_key& key,
    query::clustering_range row_ranges = query::clustering_range::make_open_ended_both_sides());

/**
 * Return a map of IP addresses containing a map of dc and rack info
 */
std::unordered_map<gms::inet_address, locator::endpoint_dc_rack>
load_dc_rack_info();

enum class bootstrap_state {
    NEEDS_BOOTSTRAP,
    COMPLETED,
    IN_PROGRESS,
    DECOMMISSIONED
};

    struct compaction_history_entry {
        utils::UUID id;
        sstring ks;
        sstring cf;
        int64_t compacted_at = 0;
        int64_t bytes_in = 0;
        int64_t bytes_out = 0;
        // Key: number of rows merged
        // Value: counter
        std::unordered_map<int32_t, int64_t> rows_merged;
    };

    future<> update_compaction_history(utils::UUID uuid, sstring ksname, sstring cfname, int64_t compacted_at, int64_t bytes_in, int64_t bytes_out,
                                       std::unordered_map<int32_t, int64_t> rows_merged);
    using compaction_history_consumer = noncopyable_function<future<>(const compaction_history_entry&)>;
    future<> get_compaction_history(compaction_history_consumer&& f);

    typedef std::vector<db::replay_position> replay_positions;

    future<> save_truncation_record(utils::UUID, db_clock::time_point truncated_at, db::replay_position);
    future<> save_truncation_record(const column_family&, db_clock::time_point truncated_at, db::replay_position);
    future<replay_positions> get_truncated_position(utils::UUID);
    future<db::replay_position> get_truncated_position(utils::UUID, uint32_t shard);
    future<db_clock::time_point> get_truncated_at(utils::UUID);

    /**
     * Return a map of stored tokens to IP addresses
     *
     */
    future<std::unordered_map<gms::inet_address, std::unordered_set<dht::token>>> load_tokens();

    /**
     * Return a map of store host_ids to IP addresses
     *
     */
    future<std::unordered_map<gms::inet_address, utils::UUID>> load_host_ids();

    /*
     * Read this node's tokens stored in the LOCAL table.
     * Used to initialize a restarting node.
     */
    future<std::unordered_set<dht::token>> get_saved_tokens();

    /*
     * Gets this node's non-empty set of tokens.
     * TODO: maybe get this data from token_metadata instance?
     */
    future<std::unordered_set<dht::token>> get_local_tokens();

    future<std::unordered_map<gms::inet_address, sstring>> load_peer_features();

future<int> increment_and_get_generation();
bool bootstrap_complete();
bool bootstrap_in_progress();
bootstrap_state get_bootstrap_state();
bool was_decommissioned();
future<> set_bootstrap_state(bootstrap_state state);

    /**
     * Read the host ID from the system keyspace, creating (and storing) one if
     * none exists.
     */
    future<utils::UUID> get_local_host_id();

    /**
     * Sets the local host ID explicitly.  Should only be called outside of SystemTable when replacing a node.
     */
    future<utils::UUID> set_local_host_id(const utils::UUID& host_id);

    api::timestamp_type schema_creation_timestamp();

/**
 * Builds a mutation for SIZE_ESTIMATES_CF containing the specified estimates.
 */
mutation make_size_estimates_mutation(const sstring& ks, std::vector<range_estimates> estimates);

future<> register_view_for_building(sstring ks_name, sstring view_name, const dht::token& token);
future<> update_view_build_progress(sstring ks_name, sstring view_name, const dht::token& token);
future<> remove_view_build_progress(sstring ks_name, sstring view_name);
future<> remove_view_build_progress_across_all_shards(sstring ks_name, sstring view_name);
future<> mark_view_as_built(sstring ks_name, sstring view_name);
future<> remove_built_view(sstring ks_name, sstring view_name);
future<std::vector<view_name>> load_built_views();
future<std::vector<view_build_progress>> load_view_build_progress();

// Paxos related functions
future<service::paxos::paxos_state> load_paxos_state(partition_key_view key, schema_ptr s, gc_clock::time_point now,
        db::timeout_clock::time_point timeout);
future<> save_paxos_promise(const schema& s, const partition_key& key, const utils::UUID& ballot, db::timeout_clock::time_point timeout);
future<> save_paxos_proposal(const schema& s, const service::paxos::proposal& proposal, db::timeout_clock::time_point timeout);
future<> save_paxos_decision(const schema& s, const service::paxos::proposal& decision, db::timeout_clock::time_point timeout);
future<> delete_paxos_decision(const schema& s, const partition_key& key, const utils::UUID& ballot, db::timeout_clock::time_point timeout);

// CDC related functions

/*
 * Save the CDC generation ID announced by this node in persistent storage.
 */
future<> update_cdc_generation_id(cdc::generation_id);

/*
 * Read the CDC generation ID announced by this node from persistent storage.
 * Used to initialize a restarting node.
 */
future<std::optional<cdc::generation_id>> get_cdc_generation_id();

future<bool> cdc_is_rewritten();
future<> cdc_set_rewritten(std::optional<cdc::generation_id_v1>);

} // namespace system_keyspace
} // namespace db
<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "chrome/browser/views/cookie_info_view.h"

#include <algorithm>

#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/cookies_tree_model.h"
#include "chrome/browser/profile.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "views/border.h"
#include "views/grid_layout.h"
#include "views/controls/label.h"
#include "views/controls/button/native_button.h"
#include "views/controls/tree/tree_view.h"
#include "views/controls/textfield/textfield.h"
#include "views/standard_layout.h"

static const int kCookieInfoViewBorderSize = 1;
static const int kCookieInfoViewInsetSize = 3;

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, public:

CookieInfoView::CookieInfoView(bool editable_expiration_date)
    : name_label_(NULL),
      name_value_field_(NULL),
      content_label_(NULL),
      content_value_field_(NULL),
      domain_label_(NULL),
      domain_value_field_(NULL),
      path_label_(NULL),
      path_value_field_(NULL),
      send_for_label_(NULL),
      send_for_value_field_(NULL),
      created_label_(NULL),
      created_value_field_(NULL),
      expires_label_(NULL),
      expires_value_field_(NULL),
      expires_value_combobox_(NULL),
      expire_view_(NULL),
      editable_expiration_date_(editable_expiration_date),
      delegate_(NULL) {
}

CookieInfoView::~CookieInfoView() {
}

void CookieInfoView::SetCookie(
    const std::string& domain,
    const net::CookieMonster::CanonicalCookie& cookie) {
  name_value_field_->SetText(UTF8ToWide(cookie.Name()));
  content_value_field_->SetText(UTF8ToWide(cookie.Value()));
  domain_value_field_->SetText(UTF8ToWide(domain));
  path_value_field_->SetText(UTF8ToWide(cookie.Path()));
  created_value_field_->SetText(
      base::TimeFormatFriendlyDateAndTime(cookie.CreationDate()));

  std::wstring expire_text = cookie.DoesExpire() ?
      base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate()) :
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_SESSION);

  if (editable_expiration_date_) {
    expire_combo_values_.clear();
    if (cookie.DoesExpire())
      expire_combo_values_.push_back(expire_text);
    expire_combo_values_.push_back(
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_SESSION));
    expires_value_combobox_->ModelChanged();
    expires_value_combobox_->SetSelectedItem(0);
    expires_value_combobox_->SetEnabled(true);
  } else {
    expires_value_field_->SetText(expire_text);
  }

  send_for_value_field_->SetText(cookie.IsSecure() ?
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_SECURE) :
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_ANY));
  EnableCookieDisplay(true);
  Layout();
}

void CookieInfoView::SetCookieString(const GURL& url,
                                     const std::string& cookie_line) {
  net::CookieMonster::ParsedCookie pc(cookie_line);
  net::CookieMonster::CanonicalCookie cookie(url, pc);
  SetCookie(pc.HasDomain() ? pc.Domain() : url.host(), cookie);
}

void CookieInfoView::ClearCookieDisplay() {
  std::wstring no_cookie_string =
      l10n_util::GetString(IDS_COOKIES_COOKIE_NONESELECTED);
  name_value_field_->SetText(no_cookie_string);
  content_value_field_->SetText(no_cookie_string);
  domain_value_field_->SetText(no_cookie_string);
  path_value_field_->SetText(no_cookie_string);
  send_for_value_field_->SetText(no_cookie_string);
  created_value_field_->SetText(no_cookie_string);
  if (expires_value_field_)
    expires_value_field_->SetText(no_cookie_string);
  EnableCookieDisplay(false);
}

void CookieInfoView::EnableCookieDisplay(bool enabled) {
  name_value_field_->SetEnabled(enabled);
  content_value_field_->SetEnabled(enabled);
  domain_value_field_->SetEnabled(enabled);
  path_value_field_->SetEnabled(enabled);
  send_for_value_field_->SetEnabled(enabled);
  created_value_field_->SetEnabled(enabled);
  if (expires_value_field_)
    expires_value_field_->SetEnabled(enabled);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, views::View overrides.

void CookieInfoView::ViewHierarchyChanged(bool is_add,
                                          views::View* parent,
                                          views::View* child) {
  if (is_add && child == this)
    Init();
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, views::Combobox::Listener overrides.

void CookieInfoView::ItemChanged(views::Combobox* combo_box,
                                 int prev_index,
                                 int new_index) {
  DCHECK(combo_box == expires_value_combobox_);
  if (delegate_)
    delegate_->ModifyExpireDate(new_index != 0);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, ComboboxModel overrides.
int CookieInfoView::GetItemCount() {
  return static_cast<int>(expire_combo_values_.size());
}

std::wstring CookieInfoView::GetItemAt(int index) {
  return expire_combo_values_[index];
}

void CookieInfoView::AddLabelRow(int layout_id, views::GridLayout* layout,
                                 views::View* label, views::View* value) {
  layout->StartRow(0, layout_id);
  layout->AddView(label);
  layout->AddView(value, 2, 1, views::GridLayout::FILL,
                  views::GridLayout::CENTER);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
}

void CookieInfoView::AddControlRow(int layout_id, views::GridLayout* layout,
                                 views::View* label, views::View* control) {
  layout->StartRow(0, layout_id);
  layout->AddView(label);
  layout->AddView(control, 1, 1);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, private:

void CookieInfoView::Init() {
  // Ensure we don't run this more than once and leak memory.
  DCHECK(!name_label_);

  SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
  views::Border* border = views::Border::CreateSolidBorder(
      kCookieInfoViewBorderSize, border_color);
  set_border(border);

  name_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_NAME_LABEL));
  name_value_field_ = new views::Textfield;
  content_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_CONTENT_LABEL));
  content_value_field_ = new views::Textfield;
  domain_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_DOMAIN_LABEL));
  domain_value_field_ = new views::Textfield;
  path_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_PATH_LABEL));
  path_value_field_ = new views::Textfield;
  send_for_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_LABEL));
  send_for_value_field_ = new views::Textfield;
  created_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_CREATED_LABEL));
  created_value_field_ = new views::Textfield;
  expires_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_LABEL));
  if (editable_expiration_date_)
    expires_value_combobox_ = new views::Combobox(this);
  else
    expires_value_field_ = new views::Textfield;

  using views::GridLayout;
  using views::ColumnSet;

  GridLayout* layout = new GridLayout(this);
  layout->SetInsets(kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize);
  SetLayoutManager(layout);

  int three_column_layout_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id);
  column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                        GridLayout::USE_PREF, 0, 0);

  AddLabelRow(three_column_layout_id, layout, name_label_, name_value_field_);
  AddLabelRow(three_column_layout_id, layout, content_label_,
              content_value_field_);
  AddLabelRow(three_column_layout_id, layout, domain_label_,
              domain_value_field_);
  AddLabelRow(three_column_layout_id, layout, path_label_, path_value_field_);
  AddLabelRow(three_column_layout_id, layout, send_for_label_,
              send_for_value_field_);
  AddLabelRow(three_column_layout_id, layout, created_label_,
              created_value_field_);

  if (editable_expiration_date_) {
    AddControlRow(three_column_layout_id, layout, expires_label_,
                  expires_value_combobox_);
  } else {
    AddLabelRow(three_column_layout_id, layout, expires_label_,
                expires_value_field_);
  }

  // Color these borderless text areas the same as the containing dialog.
  SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE);
  // Now that the Textfields are in the view hierarchy, we can initialize them.
  name_value_field_->SetReadOnly(true);
  name_value_field_->RemoveBorder();
  name_value_field_->SetBackgroundColor(text_area_background);
  content_value_field_->SetReadOnly(true);
  content_value_field_->RemoveBorder();
  content_value_field_->SetBackgroundColor(text_area_background);
  domain_value_field_->SetReadOnly(true);
  domain_value_field_->RemoveBorder();
  domain_value_field_->SetBackgroundColor(text_area_background);
  path_value_field_->SetReadOnly(true);
  path_value_field_->RemoveBorder();
  path_value_field_->SetBackgroundColor(text_area_background);
  send_for_value_field_->SetReadOnly(true);
  send_for_value_field_->RemoveBorder();
  send_for_value_field_->SetBackgroundColor(text_area_background);
  created_value_field_->SetReadOnly(true);
  created_value_field_->RemoveBorder();
  created_value_field_->SetBackgroundColor(text_area_background);
  if (expires_value_field_) {
    expires_value_field_->SetReadOnly(true);
    expires_value_field_->RemoveBorder();
    expires_value_field_->SetBackgroundColor(text_area_background);
  }
}

<commit_msg>Register the cookie info view as listener to the expiry date combobox.<commit_after>// Copyright (c) 2010 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 "chrome/browser/views/cookie_info_view.h"

#include <algorithm>

#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/cookies_tree_model.h"
#include "chrome/browser/profile.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "views/border.h"
#include "views/grid_layout.h"
#include "views/controls/label.h"
#include "views/controls/button/native_button.h"
#include "views/controls/tree/tree_view.h"
#include "views/controls/textfield/textfield.h"
#include "views/standard_layout.h"

static const int kCookieInfoViewBorderSize = 1;
static const int kCookieInfoViewInsetSize = 3;

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, public:

CookieInfoView::CookieInfoView(bool editable_expiration_date)
    : name_label_(NULL),
      name_value_field_(NULL),
      content_label_(NULL),
      content_value_field_(NULL),
      domain_label_(NULL),
      domain_value_field_(NULL),
      path_label_(NULL),
      path_value_field_(NULL),
      send_for_label_(NULL),
      send_for_value_field_(NULL),
      created_label_(NULL),
      created_value_field_(NULL),
      expires_label_(NULL),
      expires_value_field_(NULL),
      expires_value_combobox_(NULL),
      expire_view_(NULL),
      editable_expiration_date_(editable_expiration_date),
      delegate_(NULL) {
}

CookieInfoView::~CookieInfoView() {
}

void CookieInfoView::SetCookie(
    const std::string& domain,
    const net::CookieMonster::CanonicalCookie& cookie) {
  name_value_field_->SetText(UTF8ToWide(cookie.Name()));
  content_value_field_->SetText(UTF8ToWide(cookie.Value()));
  domain_value_field_->SetText(UTF8ToWide(domain));
  path_value_field_->SetText(UTF8ToWide(cookie.Path()));
  created_value_field_->SetText(
      base::TimeFormatFriendlyDateAndTime(cookie.CreationDate()));

  std::wstring expire_text = cookie.DoesExpire() ?
      base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate()) :
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_SESSION);

  if (editable_expiration_date_) {
    expire_combo_values_.clear();
    if (cookie.DoesExpire())
      expire_combo_values_.push_back(expire_text);
    expire_combo_values_.push_back(
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_SESSION));
    expires_value_combobox_->ModelChanged();
    expires_value_combobox_->SetSelectedItem(0);
    expires_value_combobox_->SetEnabled(true);
    expires_value_combobox_->set_listener(this);
  } else {
    expires_value_field_->SetText(expire_text);
  }

  send_for_value_field_->SetText(cookie.IsSecure() ?
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_SECURE) :
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_ANY));
  EnableCookieDisplay(true);
  Layout();
}

void CookieInfoView::SetCookieString(const GURL& url,
                                     const std::string& cookie_line) {
  net::CookieMonster::ParsedCookie pc(cookie_line);
  net::CookieMonster::CanonicalCookie cookie(url, pc);
  SetCookie(pc.HasDomain() ? pc.Domain() : url.host(), cookie);
}

void CookieInfoView::ClearCookieDisplay() {
  std::wstring no_cookie_string =
      l10n_util::GetString(IDS_COOKIES_COOKIE_NONESELECTED);
  name_value_field_->SetText(no_cookie_string);
  content_value_field_->SetText(no_cookie_string);
  domain_value_field_->SetText(no_cookie_string);
  path_value_field_->SetText(no_cookie_string);
  send_for_value_field_->SetText(no_cookie_string);
  created_value_field_->SetText(no_cookie_string);
  if (expires_value_field_)
    expires_value_field_->SetText(no_cookie_string);
  EnableCookieDisplay(false);
}

void CookieInfoView::EnableCookieDisplay(bool enabled) {
  name_value_field_->SetEnabled(enabled);
  content_value_field_->SetEnabled(enabled);
  domain_value_field_->SetEnabled(enabled);
  path_value_field_->SetEnabled(enabled);
  send_for_value_field_->SetEnabled(enabled);
  created_value_field_->SetEnabled(enabled);
  if (expires_value_field_)
    expires_value_field_->SetEnabled(enabled);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, views::View overrides.

void CookieInfoView::ViewHierarchyChanged(bool is_add,
                                          views::View* parent,
                                          views::View* child) {
  if (is_add && child == this)
    Init();
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, views::Combobox::Listener overrides.

void CookieInfoView::ItemChanged(views::Combobox* combo_box,
                                 int prev_index,
                                 int new_index) {
  DCHECK(combo_box == expires_value_combobox_);
  if (delegate_)
    delegate_->ModifyExpireDate(new_index != 0);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, ComboboxModel overrides.
int CookieInfoView::GetItemCount() {
  return static_cast<int>(expire_combo_values_.size());
}

std::wstring CookieInfoView::GetItemAt(int index) {
  return expire_combo_values_[index];
}

void CookieInfoView::AddLabelRow(int layout_id, views::GridLayout* layout,
                                 views::View* label, views::View* value) {
  layout->StartRow(0, layout_id);
  layout->AddView(label);
  layout->AddView(value, 2, 1, views::GridLayout::FILL,
                  views::GridLayout::CENTER);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
}

void CookieInfoView::AddControlRow(int layout_id, views::GridLayout* layout,
                                 views::View* label, views::View* control) {
  layout->StartRow(0, layout_id);
  layout->AddView(label);
  layout->AddView(control, 1, 1);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
}

///////////////////////////////////////////////////////////////////////////////
// CookieInfoView, private:

void CookieInfoView::Init() {
  // Ensure we don't run this more than once and leak memory.
  DCHECK(!name_label_);

  SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW);
  views::Border* border = views::Border::CreateSolidBorder(
      kCookieInfoViewBorderSize, border_color);
  set_border(border);

  name_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_NAME_LABEL));
  name_value_field_ = new views::Textfield;
  content_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_CONTENT_LABEL));
  content_value_field_ = new views::Textfield;
  domain_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_DOMAIN_LABEL));
  domain_value_field_ = new views::Textfield;
  path_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_PATH_LABEL));
  path_value_field_ = new views::Textfield;
  send_for_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_LABEL));
  send_for_value_field_ = new views::Textfield;
  created_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_CREATED_LABEL));
  created_value_field_ = new views::Textfield;
  expires_label_ = new views::Label(
      l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_LABEL));
  if (editable_expiration_date_)
    expires_value_combobox_ = new views::Combobox(this);
  else
    expires_value_field_ = new views::Textfield;

  using views::GridLayout;
  using views::ColumnSet;

  GridLayout* layout = new GridLayout(this);
  layout->SetInsets(kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize,
                    kCookieInfoViewInsetSize);
  SetLayoutManager(layout);

  int three_column_layout_id = 0;
  ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id);
  column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                        GridLayout::USE_PREF, 0, 0);

  AddLabelRow(three_column_layout_id, layout, name_label_, name_value_field_);
  AddLabelRow(three_column_layout_id, layout, content_label_,
              content_value_field_);
  AddLabelRow(three_column_layout_id, layout, domain_label_,
              domain_value_field_);
  AddLabelRow(three_column_layout_id, layout, path_label_, path_value_field_);
  AddLabelRow(three_column_layout_id, layout, send_for_label_,
              send_for_value_field_);
  AddLabelRow(three_column_layout_id, layout, created_label_,
              created_value_field_);

  if (editable_expiration_date_) {
    AddControlRow(three_column_layout_id, layout, expires_label_,
                  expires_value_combobox_);
  } else {
    AddLabelRow(three_column_layout_id, layout, expires_label_,
                expires_value_field_);
  }

  // Color these borderless text areas the same as the containing dialog.
  SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE);
  // Now that the Textfields are in the view hierarchy, we can initialize them.
  name_value_field_->SetReadOnly(true);
  name_value_field_->RemoveBorder();
  name_value_field_->SetBackgroundColor(text_area_background);
  content_value_field_->SetReadOnly(true);
  content_value_field_->RemoveBorder();
  content_value_field_->SetBackgroundColor(text_area_background);
  domain_value_field_->SetReadOnly(true);
  domain_value_field_->RemoveBorder();
  domain_value_field_->SetBackgroundColor(text_area_background);
  path_value_field_->SetReadOnly(true);
  path_value_field_->RemoveBorder();
  path_value_field_->SetBackgroundColor(text_area_background);
  send_for_value_field_->SetReadOnly(true);
  send_for_value_field_->RemoveBorder();
  send_for_value_field_->SetBackgroundColor(text_area_background);
  created_value_field_->SetReadOnly(true);
  created_value_field_->RemoveBorder();
  created_value_field_->SetBackgroundColor(text_area_background);
  if (expires_value_field_) {
    expires_value_field_->SetReadOnly(true);
    expires_value_field_->RemoveBorder();
    expires_value_field_->SetBackgroundColor(text_area_background);
  }
}

<|endoftext|>