<commit_before>#include "DDR.h"
#include "VirtualMemory.h"
#include "sim/config.h"
#include "sim/log2.h"
#include <sstream>
#include <limits>
#include <cstdio>

namespace Simulator
{

template <typename T>
static T GET_BITS(const T& value, unsigned int offset, unsigned int size)
{
    return (value >> offset) & ((T(1) << size) - 1);
}

static const unsigned long INVALID_ROW = std::numeric_limits<unsigned long>::max();

bool DDRChannel::Read(MemAddr address, MemSize size)
{
    if (m_busy.IsSet())
    {
        // We're still busy
        return false;
    }

    // Accept request
    COMMIT
    {
        m_request.address   = address;
        m_request.offset    = 0;
        m_request.data.size = size;
        m_request.write     = false;
        m_next_command = 0;
    }

    // Get the actual data
    m_memory.Read(address, m_request.data.data, size);

    if (!m_busy.Set())
    {
        return false;
    }
    return true;
}

bool DDRChannel::Write(MemAddr address, const void* data, MemSize size)
{
    if (m_busy.IsSet())
    {
        // We're still busy
        return false;
    }

    // Accept request
    COMMIT
    {
        m_request.address   = address;
        m_request.offset    = 0;
        m_request.data.size = size;
        m_request.write     = true;

        m_next_command = 0;
    }

    // Write the actual data
    m_memory.Write(address, data, size);

    if (!m_busy.Set())
    {
        return false;
    }
    return true;
}

// Main process for timing the current active request
Result DDRChannel::DoRequest()
{
    assert(m_busy.IsSet());

    const CycleNo now = GetClock().GetCycleNo();
    if (now < m_next_command)
    {
        // Can't continue yet
        return SUCCESS;
    }

    // We read from m_nDevicesPerRank devices, each providing m_nBurstLength bytes in the burst.
    const unsigned burst_size = m_ddrconfig.m_nBurstSize;

    // Decode the burst address and offset-within-burst
    const MemAddr      address = (m_request.address + m_request.offset) / burst_size;
    const unsigned int offset  = (m_request.address + m_request.offset) % burst_size;
    const unsigned int rank    = GET_BITS(address, m_ddrconfig.m_nRankStart, m_ddrconfig.m_nRankBits),
                       row     = GET_BITS(address, m_ddrconfig.m_nRowStart,  m_ddrconfig.m_nRowBits);

    if (m_currentRow[rank] != row)
    {
        if (m_currentRow[rank] != INVALID_ROW)
        {
            // Precharge (close) the currently active row
            COMMIT
            {
                m_next_command = std::max(m_next_precharge, now) + m_ddrconfig.m_tRP;
                m_currentRow[rank] = INVALID_ROW;
            }
            return SUCCESS;
        }

        // Activate (open) the desired row
        COMMIT
        {
            m_next_command   = now + m_ddrconfig.m_tRCD;
            m_next_precharge = now + m_ddrconfig.m_tRAS;

            m_currentRow[rank] = row;
        }
        return SUCCESS;
    }

    // Process a single burst
    unsigned int remainder = m_request.data.size - m_request.offset;
    unsigned int size      = std::min(burst_size - offset, remainder);

    if (m_request.write)
    {
        COMMIT
        {
            // Update address to reflect written portion
            m_request.offset += size;

            m_next_command   = now + m_ddrconfig.m_tCWL;
            m_next_precharge = now + m_ddrconfig.m_tWR;
        }

        if (size < remainder)
        {
            // We're not done yet
            return SUCCESS;
        }
    }
    else
    {
        COMMIT
        {
            // Update address to reflect read portion
            m_request.offset += size;
            m_request.done    = now + m_ddrconfig.m_tCL;

            // Schedule next read
            m_next_command = now + m_ddrconfig.m_tCCD;
        }

        if (size < remainder)
        {
            // We're not done yet
            return SUCCESS;
        }

        // We're done with this read; queue it into the pipeline
        if (!m_pipeline.Push(m_request))
        {
            // The read pipeline should be big enough
            assert(false);
            return FAILED;
        }
    }

    // We've completed this request
    if (!m_busy.Clear())
    {
        return FAILED;
    }
    return SUCCESS;
}

Result DDRChannel::DoPipeline()
{
    assert(!m_pipeline.Empty());
    const CycleNo  now     = GetClock().GetCycleNo();
    const Request& request = m_pipeline.Front();
    if (request.done >= now)
    {
        // The last burst has completed, send the assembled data back
        assert(!request.write);
        if (!m_callback->OnReadCompleted(request.address, request.data))
        {
            return FAILED;
        }
        m_pipeline.Pop();
    }
    return SUCCESS;
}

DDRChannel::DDRConfig::DDRConfig(const std::string& name, Object& parent, Clock& clock, Config& config)
    : Object(name, parent, clock)
{
    // DDR 3
    m_nBurstLength = config.getValue<size_t> (*this, "BurstLength");
    if (m_nBurstLength != 8)
        throw SimulationException(*this, "This implementation only supports m_nBurstLength = 8");
    size_t cellsize = config.getValue<size_t> (*this, "CellSize");
    if (cellsize != 8)
        throw SimulationException(*this, "This implementation only supports CellSize = 8");

    m_tCL  = config.getValue<unsigned> (*this, "tCL");
    m_tRCD = config.getValue<unsigned> (*this, "tRCD");
    m_tRP  = config.getValue<unsigned> (*this, "tRP");
    m_tRAS = config.getValue<unsigned> (*this, "tRAS");
    m_tCWL = config.getValue<unsigned> (*this, "tCWL");
    m_tCCD = config.getValue<unsigned> (*this, "tCCD");

    // tWR is expressed in DDR specs in nanoseconds, see
    // http://www.samsung.com/global/business/semiconductor/products/dram/downloads/applicationnote/tWR.pdf
    // Frequency is in MHz.
    m_tWR = config.getValue<unsigned> (*this, "tWR") / 1e3 * clock.GetFrequency();

    // Address bit mapping.
    // One row bit added for a 4GB DIMM with ECC.
    m_nDevicesPerRank = config.getValue<size_t> (*this, "DevicesPerRank");
    m_nRankBits = ilog2(config.getValue<size_t> (*this, "Ranks"));
    m_nRowBits = config.getValue<size_t> (*this, "RowBits");
    m_nColumnBits = config.getValue<size_t> (*this, "ColumnBits");
    m_nBurstSize = m_nDevicesPerRank * m_nBurstLength;

    // ordering of bits in address:
    m_nColumnStart = 0;
    m_nRowStart = m_nColumnStart + m_nColumnBits;
    m_nRankStart = m_nRowStart + m_nRowBits;

}

DDRChannel::DDRChannel(const std::string& name, Object& parent, Clock& clock, VirtualMemory& memory, Config& config)
    : Object(name, parent, clock),
      m_registry(config),
      m_ddrconfig("config", *this, clock, config),
      // Initialize each rank at 'no row selected'
      m_currentRow(1 << m_ddrconfig.m_nRankBits, INVALID_ROW),

      m_memory(memory),
      m_callback(0),
      m_pipeline("b_pipeline", *this, clock, m_ddrconfig.m_tCL),
      m_busy("f_busy", *this, clock, false),
      m_next_command(0),
      m_next_precharge(0),

      p_Request (*this, "request",  delegate::create<DDRChannel, &DDRChannel::DoRequest >(*this)),
      p_Pipeline(*this, "pipeline", delegate::create<DDRChannel, &DDRChannel::DoPipeline>(*this))
{
    m_busy.Sensitive(p_Request);
    m_pipeline.Sensitive(p_Pipeline);

    config.registerObject(*this, "ddr");
    config.registerProperty(*this, "CL", (uint32_t)m_ddrconfig.m_tCL);
    config.registerProperty(*this, "RCD", (uint32_t)m_ddrconfig.m_tRCD);
    config.registerProperty(*this, "RP", (uint32_t)m_ddrconfig.m_tRP);
    config.registerProperty(*this, "RAS", (uint32_t)m_ddrconfig.m_tRAS);
    config.registerProperty(*this, "CWL", (uint32_t)m_ddrconfig.m_tCWL);
    config.registerProperty(*this, "CCD", (uint32_t)m_ddrconfig.m_tCCD);
    config.registerProperty(*this, "WR", (uint32_t)m_ddrconfig.m_tWR);
    config.registerProperty(*this, "chips/rank", (uint32_t)m_ddrconfig.m_nDevicesPerRank);
    config.registerProperty(*this, "ranks", (uint32_t)(1UL<<m_ddrconfig.m_nRankBits));
    config.registerProperty(*this, "rows", (uint32_t)(1UL<<m_ddrconfig.m_nRowBits));
    config.registerProperty(*this, "columns", (uint32_t)(1UL<<m_ddrconfig.m_nColumnBits));
    config.registerProperty(*this, "freq", (uint32_t)clock.GetFrequency());
}

void DDRChannel::SetClient(ICallback& cb, StorageTraceSet& sts, const StorageTraceSet& storages)
{
    if (m_callback != NULL)
    {
        throw InvalidArgumentException(*this, "DDR channel can be connected to at most one root directory.");
    }
    m_callback = &cb;

    sts = m_busy;
    p_Request.SetStorageTraces(opt(m_pipeline));
    p_Pipeline.SetStorageTraces(opt(storages));

    m_registry.registerBidiRelation(*this, cb, "ddr");
}

DDRChannel::~DDRChannel()
{
}

DDRChannelRegistry::DDRChannelRegistry(const std::string& name, Object& parent, VirtualMemory& memory, Config& config)
    : Object(name, parent)
{
    size_t numChannels = config.getValueOrDefault<size_t>(*this, "NumChannels",
                                                          config.getValue<size_t>(parent, "NumRootDirectories"));

    for (size_t i = 0; i < numChannels; ++i)
    {
        std::stringstream ss;
        ss << "channel" << i;
        Clock &ddrclock = GetKernel()->CreateClock(config.getValue<size_t>(*this, ss.str(), "Freq"));
        this->push_back(new DDRChannel(ss.str(), *this, ddrclock, memory, config));
    }
}

DDRChannelRegistry::~DDRChannelRegistry()
{
    for (size_t i = 0; i < size(); ++i)
        delete (*this)[i];
}

}

<commit_msg>[mgsim] Fixed read completion timing bug in DDR.<commit_after>#include "DDR.h"
#include "VirtualMemory.h"
#include "sim/config.h"
#include "sim/log2.h"
#include <sstream>
#include <limits>
#include <cstdio>

namespace Simulator
{

template <typename T>
static T GET_BITS(const T& value, unsigned int offset, unsigned int size)
{
    return (value >> offset) & ((T(1) << size) - 1);
}

static const unsigned long INVALID_ROW = std::numeric_limits<unsigned long>::max();

bool DDRChannel::Read(MemAddr address, MemSize size)
{
    if (m_busy.IsSet())
    {
        // We're still busy
        return false;
    }

    // Accept request
    COMMIT
    {
        m_request.address   = address;
        m_request.offset    = 0;
        m_request.data.size = size;
        m_request.write     = false;
        m_next_command = 0;
    }

    // Get the actual data
    m_memory.Read(address, m_request.data.data, size);

    if (!m_busy.Set())
    {
        return false;
    }
    return true;
}

bool DDRChannel::Write(MemAddr address, const void* data, MemSize size)
{
    if (m_busy.IsSet())
    {
        // We're still busy
        return false;
    }

    // Accept request
    COMMIT
    {
        m_request.address   = address;
        m_request.offset    = 0;
        m_request.data.size = size;
        m_request.write     = true;

        m_next_command = 0;
    }

    // Write the actual data
    m_memory.Write(address, data, size);

    if (!m_busy.Set())
    {
        return false;
    }
    return true;
}

// Main process for timing the current active request
Result DDRChannel::DoRequest()
{
    assert(m_busy.IsSet());

    const CycleNo now = GetClock().GetCycleNo();
    if (now < m_next_command)
    {
        // Can't continue yet
        return SUCCESS;
    }

    // We read from m_nDevicesPerRank devices, each providing m_nBurstLength bytes in the burst.
    const unsigned burst_size = m_ddrconfig.m_nBurstSize;

    // Decode the burst address and offset-within-burst
    const MemAddr      address = (m_request.address + m_request.offset) / burst_size;
    const unsigned int offset  = (m_request.address + m_request.offset) % burst_size;
    const unsigned int rank    = GET_BITS(address, m_ddrconfig.m_nRankStart, m_ddrconfig.m_nRankBits),
                       row     = GET_BITS(address, m_ddrconfig.m_nRowStart,  m_ddrconfig.m_nRowBits);

    if (m_currentRow[rank] != row)
    {
        if (m_currentRow[rank] != INVALID_ROW)
        {
            // Precharge (close) the currently active row
            COMMIT
            {
                m_next_command = std::max(m_next_precharge, now) + m_ddrconfig.m_tRP;
                m_currentRow[rank] = INVALID_ROW;
            }
            return SUCCESS;
        }

        // Activate (open) the desired row
        COMMIT
        {
            m_next_command   = now + m_ddrconfig.m_tRCD;
            m_next_precharge = now + m_ddrconfig.m_tRAS;

            m_currentRow[rank] = row;
        }
        return SUCCESS;
    }

    // Process a single burst
    unsigned int remainder = m_request.data.size - m_request.offset;
    unsigned int size      = std::min(burst_size - offset, remainder);

    if (m_request.write)
    {
        COMMIT
        {
            // Update address to reflect written portion
            m_request.offset += size;

            m_next_command   = now + m_ddrconfig.m_tCWL;
            m_next_precharge = now + m_ddrconfig.m_tWR;
        }

        if (size < remainder)
        {
            // We're not done yet
            return SUCCESS;
        }
    }
    else
    {
        COMMIT
        {
            // Update address to reflect read portion
            m_request.offset += size;
            m_request.done    = now + m_ddrconfig.m_tCL;

            // Schedule next read
            m_next_command = now + m_ddrconfig.m_tCCD;
        }

        if (size < remainder)
        {
            // We're not done yet
            return SUCCESS;
        }

        // We're done with this read; queue it into the pipeline
        if (!m_pipeline.Push(m_request))
        {
            // The read pipeline should be big enough
            assert(false);
            return FAILED;
        }
    }

    // We've completed this request
    if (!m_busy.Clear())
    {
        return FAILED;
    }
    return SUCCESS;
}

Result DDRChannel::DoPipeline()
{
    assert(!m_pipeline.Empty());
    const CycleNo  now     = GetClock().GetCycleNo();
    const Request& request = m_pipeline.Front();
    if (now >= request.done)
    {
        // The last burst has completed, send the assembled data back
        assert(!request.write);
        if (!m_callback->OnReadCompleted(request.address, request.data))
        {
            return FAILED;
        }
        m_pipeline.Pop();
    }
    return SUCCESS;
}

DDRChannel::DDRConfig::DDRConfig(const std::string& name, Object& parent, Clock& clock, Config& config)
    : Object(name, parent, clock)
{
    // DDR 3
    m_nBurstLength = config.getValue<size_t> (*this, "BurstLength");
    if (m_nBurstLength != 8)
        throw SimulationException(*this, "This implementation only supports m_nBurstLength = 8");
    size_t cellsize = config.getValue<size_t> (*this, "CellSize");
    if (cellsize != 8)
        throw SimulationException(*this, "This implementation only supports CellSize = 8");

    m_tCL  = config.getValue<unsigned> (*this, "tCL");
    m_tRCD = config.getValue<unsigned> (*this, "tRCD");
    m_tRP  = config.getValue<unsigned> (*this, "tRP");
    m_tRAS = config.getValue<unsigned> (*this, "tRAS");
    m_tCWL = config.getValue<unsigned> (*this, "tCWL");
    m_tCCD = config.getValue<unsigned> (*this, "tCCD");

    // tWR is expressed in DDR specs in nanoseconds, see
    // http://www.samsung.com/global/business/semiconductor/products/dram/downloads/applicationnote/tWR.pdf
    // Frequency is in MHz.
    m_tWR = config.getValue<unsigned> (*this, "tWR") / 1e3 * clock.GetFrequency();

    // Address bit mapping.
    // One row bit added for a 4GB DIMM with ECC.
    m_nDevicesPerRank = config.getValue<size_t> (*this, "DevicesPerRank");
    m_nRankBits = ilog2(config.getValue<size_t> (*this, "Ranks"));
    m_nRowBits = config.getValue<size_t> (*this, "RowBits");
    m_nColumnBits = config.getValue<size_t> (*this, "ColumnBits");
    m_nBurstSize = m_nDevicesPerRank * m_nBurstLength;

    // ordering of bits in address:
    m_nColumnStart = 0;
    m_nRowStart = m_nColumnStart + m_nColumnBits;
    m_nRankStart = m_nRowStart + m_nRowBits;

}

DDRChannel::DDRChannel(const std::string& name, Object& parent, Clock& clock, VirtualMemory& memory, Config& config)
    : Object(name, parent, clock),
      m_registry(config),
      m_ddrconfig("config", *this, clock, config),
      // Initialize each rank at 'no row selected'
      m_currentRow(1 << m_ddrconfig.m_nRankBits, INVALID_ROW),

      m_memory(memory),
      m_callback(0),
      m_pipeline("b_pipeline", *this, clock, m_ddrconfig.m_tCL),
      m_busy("f_busy", *this, clock, false),
      m_next_command(0),
      m_next_precharge(0),

      p_Request (*this, "request",  delegate::create<DDRChannel, &DDRChannel::DoRequest >(*this)),
      p_Pipeline(*this, "pipeline", delegate::create<DDRChannel, &DDRChannel::DoPipeline>(*this))
{
    m_busy.Sensitive(p_Request);
    m_pipeline.Sensitive(p_Pipeline);

    config.registerObject(*this, "ddr");
    config.registerProperty(*this, "CL", (uint32_t)m_ddrconfig.m_tCL);
    config.registerProperty(*this, "RCD", (uint32_t)m_ddrconfig.m_tRCD);
    config.registerProperty(*this, "RP", (uint32_t)m_ddrconfig.m_tRP);
    config.registerProperty(*this, "RAS", (uint32_t)m_ddrconfig.m_tRAS);
    config.registerProperty(*this, "CWL", (uint32_t)m_ddrconfig.m_tCWL);
    config.registerProperty(*this, "CCD", (uint32_t)m_ddrconfig.m_tCCD);
    config.registerProperty(*this, "WR", (uint32_t)m_ddrconfig.m_tWR);
    config.registerProperty(*this, "chips/rank", (uint32_t)m_ddrconfig.m_nDevicesPerRank);
    config.registerProperty(*this, "ranks", (uint32_t)(1UL<<m_ddrconfig.m_nRankBits));
    config.registerProperty(*this, "rows", (uint32_t)(1UL<<m_ddrconfig.m_nRowBits));
    config.registerProperty(*this, "columns", (uint32_t)(1UL<<m_ddrconfig.m_nColumnBits));
    config.registerProperty(*this, "freq", (uint32_t)clock.GetFrequency());
}

void DDRChannel::SetClient(ICallback& cb, StorageTraceSet& sts, const StorageTraceSet& storages)
{
    if (m_callback != NULL)
    {
        throw InvalidArgumentException(*this, "DDR channel can be connected to at most one root directory.");
    }
    m_callback = &cb;

    sts = m_busy;
    p_Request.SetStorageTraces(opt(m_pipeline));
    p_Pipeline.SetStorageTraces(opt(storages));

    m_registry.registerBidiRelation(*this, cb, "ddr");
}

DDRChannel::~DDRChannel()
{
}

DDRChannelRegistry::DDRChannelRegistry(const std::string& name, Object& parent, VirtualMemory& memory, Config& config)
    : Object(name, parent)
{
    size_t numChannels = config.getValueOrDefault<size_t>(*this, "NumChannels",
                                                          config.getValue<size_t>(parent, "NumRootDirectories"));

    for (size_t i = 0; i < numChannels; ++i)
    {
        std::stringstream ss;
        ss << "channel" << i;
        Clock &ddrclock = GetKernel()->CreateClock(config.getValue<size_t>(*this, ss.str(), "Freq"));
        this->push_back(new DDRChannel(ss.str(), *this, ddrclock, memory, config));
    }
}

DDRChannelRegistry::~DDRChannelRegistry()
{
    for (size_t i = 0; i < size(); ++i)
        delete (*this)[i];
}

}

<|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 <limits>

#include "chrome/browser/jankometer.h"

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/watchdog.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/chrome_switches.h"

#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_util.h"
#endif

using base::TimeDelta;
using base::TimeTicks;

namespace {

// The maximum threshold of delay of the message  before considering it a delay.
// For a debug build, you may want to set IO delay around 500ms.
// For a release build, setting it around 350ms is sensible.
// Visit about:histograms to see what the distribution is on your system, with
// your build. Be sure to do some work to get interesting stats.
// The numbers below came from a warm start (you'll get about 5-10 alarms with
// a cold start), and running the page-cycler for 5 rounds.
#ifdef NDEBUG
const int kMaxUIMessageDelayMs = 350;
const int kMaxIOMessageDelayMs = 200;
#else
const int kMaxUIMessageDelayMs = 500;
const int kMaxIOMessageDelayMs = 400;
#endif

// Maximum processing time (excluding queueing delay) for a message before
// considering it delayed.
const int kMaxMessageProcessingMs = 100;

// TODO(brettw) Consider making this a pref.
const bool kPlaySounds = false;

//------------------------------------------------------------------------------
// Provide a special watchdog to make it easy to set the breakpoint on this
// class only.
class JankWatchdog : public Watchdog {
 public:
  JankWatchdog(const TimeDelta& duration,
               const std::string& thread_watched_name,
               bool enabled)
      : Watchdog(duration, thread_watched_name, enabled),
        thread_name_watched_(thread_watched_name),
        alarm_count_(0) {
  }

  virtual ~JankWatchdog() {}

  virtual void Alarm() {
    // Put break point here if you want to stop threads and look at what caused
    // the jankiness.
    alarm_count_++;
    Watchdog::Alarm();
  }

 private:
  std::string thread_name_watched_;
  int alarm_count_;

  DISALLOW_COPY_AND_ASSIGN(JankWatchdog);
};

class JankObserverHelper {
 public:
  JankObserverHelper(const std::string& thread_name,
                     const TimeDelta& excessive_duration,
                     bool watchdog_enable);
  ~JankObserverHelper();

  void StartProcessingTimers(const TimeDelta& queueing_time);
  void EndProcessingTimers();

  // Indicate if we will bother to measuer this message.
  bool MessageWillBeMeasured();

  static void SetDefaultMessagesToSkip(int count) { discard_count_ = count; }

 private:
  const TimeDelta max_message_delay_;

  // Indicate if we'll bother measuring this message.
  bool measure_current_message_;

  // Down counter which will periodically hit 0, and only then bother to measure
  // the corresponding message.
  int events_till_measurement_;

  // The value to re-initialize events_till_measurement_ after it reaches 0.
  static int discard_count_;

  // Time at which the current message processing began.
  TimeTicks begin_process_message_;

  // Time the current message spent in the queue -- delta between message
  // construction time and message processing time.
  TimeDelta queueing_time_;

  // Counters for the two types of jank we measure.
  base::StatsCounter slow_processing_counter_;  // Msgs w/ long proc time.
  base::StatsCounter queueing_delay_counter_;   // Msgs w/ long queueing delay.
  scoped_refptr<base::Histogram> process_times_;  // Time spent proc. task.
  scoped_refptr<base::Histogram> total_times_;  // Total queueing plus proc.
  JankWatchdog total_time_watchdog_;  // Watching for excessive total_time.

  DISALLOW_COPY_AND_ASSIGN(JankObserverHelper);
};

JankObserverHelper::JankObserverHelper(
    const std::string& thread_name,
    const TimeDelta& excessive_duration,
    bool watchdog_enable)
    : max_message_delay_(excessive_duration),
      measure_current_message_(true),
      events_till_measurement_(0),
      slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name),
      queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name),
      total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) {
  process_times_ = base::Histogram::FactoryGet(
      std::string("Chrome.ProcMsgL ") + thread_name,
      1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag);
  total_times_ = base::Histogram::FactoryGet(
      std::string("Chrome.TotalMsgL ") + thread_name,
      1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag);
  if (discard_count_ > 0) {
    // Select a vaguely random sample-start-point.
    events_till_measurement_ =
        (TimeTicks::Now() - TimeTicks()).InSeconds() % (discard_count_ + 1);
  }
}

JankObserverHelper::~JankObserverHelper() {}

// Called when a message has just begun processing, initializes
// per-message variables and timers.
void JankObserverHelper::StartProcessingTimers(const TimeDelta& queueing_time) {
  DCHECK(measure_current_message_);
  begin_process_message_ = TimeTicks::Now();
  queueing_time_ = queueing_time;

  // Simulate arming when the message entered the queue.
  total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_);
  if (queueing_time_ > max_message_delay_) {
    // Message is too delayed.
    queueing_delay_counter_.Increment();
#if defined(OS_WIN)
    if (kPlaySounds)
      MessageBeep(MB_ICONASTERISK);
#endif
  }
}

// Called when a message has just finished processing, finalizes
// per-message variables and timers.
void JankObserverHelper::EndProcessingTimers() {
  if (!measure_current_message_)
    return;
  total_time_watchdog_.Disarm();
  TimeTicks now = TimeTicks::Now();
  if (begin_process_message_ != TimeTicks()) {
    TimeDelta processing_time = now - begin_process_message_;
    process_times_->AddTime(processing_time);
    total_times_->AddTime(queueing_time_ + processing_time);
  }
  if (now - begin_process_message_ >
      TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) {
    // Message took too long to process.
    slow_processing_counter_.Increment();
#if defined(OS_WIN)
    if (kPlaySounds)
      MessageBeep(MB_ICONHAND);
#endif
  }

  // Reset message specific times.
  begin_process_message_ = base::TimeTicks();
  queueing_time_ = base::TimeDelta();
}

bool JankObserverHelper::MessageWillBeMeasured() {
  measure_current_message_ = events_till_measurement_ <= 0;
  if (!measure_current_message_)
    --events_till_measurement_;
  else
    events_till_measurement_ = discard_count_;
  return measure_current_message_;
}

// static
int JankObserverHelper::discard_count_ = 99;  // Measure only 1 in 100.

//------------------------------------------------------------------------------
class IOJankObserver : public base::RefCountedThreadSafe<IOJankObserver>,
                       public MessageLoopForIO::IOObserver,
                       public MessageLoop::TaskObserver {
 public:
  IOJankObserver(const char* thread_name,
                 TimeDelta excessive_duration,
                 bool watchdog_enable)
      : helper_(thread_name, excessive_duration, watchdog_enable) {}

  ~IOJankObserver() {}

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    MessageLoop::current()->AddTaskObserver(this);
    MessageLoopForIO::current()->AddIOObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    MessageLoopForIO::current()->RemoveIOObserver(this);
    MessageLoop::current()->RemoveTaskObserver(this);
  }

  virtual void WillProcessIOEvent() {
    if (!helper_.MessageWillBeMeasured())
      return;
    helper_.StartProcessingTimers(base::TimeDelta());
  }

  virtual void DidProcessIOEvent() {
    helper_.EndProcessingTimers();
  }

  virtual void WillProcessTask(const Task* task) {
    if (!helper_.MessageWillBeMeasured())
      return;
    base::TimeTicks now = base::TimeTicks::Now();
    const base::TimeDelta queueing_time = now - task->tracked_birth_time();
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessTask(const Task* task) {
    helper_.EndProcessingTimers();
  }

 private:
  friend class base::RefCountedThreadSafe<IOJankObserver>;

  JankObserverHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(IOJankObserver);
};

//------------------------------------------------------------------------------
class UIJankObserver : public base::RefCountedThreadSafe<UIJankObserver>,
                       public MessageLoop::TaskObserver,
                       public MessageLoopForUI::Observer {
 public:
  UIJankObserver(const char* thread_name,
                 TimeDelta excessive_duration,
                 bool watchdog_enable)
      : helper_(thread_name, excessive_duration, watchdog_enable) {}

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
    MessageLoopForUI::current()->AddObserver(this);
    MessageLoop::current()->AddTaskObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
    MessageLoop::current()->RemoveTaskObserver(this);
    MessageLoopForUI::current()->RemoveObserver(this);
  }

  virtual void WillProcessTask(const Task* task) {
    if (!helper_.MessageWillBeMeasured())
      return;
    base::TimeTicks now = base::TimeTicks::Now();
    const base::TimeDelta queueing_time = now - task->tracked_birth_time();
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessTask(const Task* task) {
    helper_.EndProcessingTimers();
  }

#if defined(OS_WIN)
  virtual void WillProcessMessage(const MSG& msg) {
    if (!helper_.MessageWillBeMeasured())
      return;
    // GetMessageTime returns a LONG (signed 32-bit) and GetTickCount returns
    // a DWORD (unsigned 32-bit). They both wrap around when the time is longer
    // than they can hold. I'm not sure if GetMessageTime wraps around to 0,
    // or if the original time comes from GetTickCount, it might wrap around
    // to -1.
    //
    // Therefore, I cast to DWORD so if it wraps to -1 we will correct it. If
    // it doesn't, then our time delta will be negative if a message happens
    // to straddle the wraparound point, it will still be OK.
    DWORD cur_message_issue_time = static_cast<DWORD>(msg.time);
    DWORD cur_time = GetTickCount();
    base::TimeDelta queueing_time =
        base::TimeDelta::FromMilliseconds(cur_time - cur_message_issue_time);

    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessMessage(const MSG& msg) {
    helper_.EndProcessingTimers();
  }
#elif defined(TOOLKIT_USES_GTK)
  virtual void WillProcessEvent(GdkEvent* event) {
    if (!helper_.MessageWillBeMeasured())
      return;
    // TODO(evanm): we want to set queueing_time_ using
    // gdk_event_get_time, but how do you convert that info
    // into a delta?
    // guint event_time = gdk_event_get_time(event);
    base::TimeDelta queueing_time = base::TimeDelta::FromMilliseconds(0);
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessEvent(GdkEvent* event) {
    helper_.EndProcessingTimers();
  }
#endif

 private:
  friend class base::RefCountedThreadSafe<UIJankObserver>;

  ~UIJankObserver() {}

  JankObserverHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(UIJankObserver);
};

// These objects are created by InstallJankometer and leaked.
const scoped_refptr<UIJankObserver>* ui_observer = NULL;
const scoped_refptr<IOJankObserver>* io_observer = NULL;

}  // namespace

void InstallJankometer(const CommandLine& parsed_command_line) {
  if (ui_observer || io_observer) {
    NOTREACHED() << "Initializing jank-o-meter twice";
    return;
  }

  bool ui_watchdog_enabled = false;
  bool io_watchdog_enabled = false;
  if (parsed_command_line.HasSwitch(switches::kEnableWatchdog)) {
    std::string list =
        parsed_command_line.GetSwitchValueASCII(switches::kEnableWatchdog);
    if (list.npos != list.find("ui"))
      ui_watchdog_enabled = true;
    if (list.npos != list.find("io"))
      io_watchdog_enabled = true;
  }

  if (ui_watchdog_enabled || io_watchdog_enabled)
    JankObserverHelper::SetDefaultMessagesToSkip(0);  // Watch everything.

  // Install on the UI thread.
  ui_observer = new scoped_refptr<UIJankObserver>(
      new UIJankObserver(
          "UI",
          TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs),
          ui_watchdog_enabled));
  (*ui_observer)->AttachToCurrentThread();

  // Now install on the I/O thread. Hiccups on that thread will block
  // interaction with web pages. We must proxy to that thread before we can
  // add our observer.
  io_observer = new scoped_refptr<IOJankObserver>(
      new IOJankObserver(
          "IO",
          TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs),
          io_watchdog_enabled));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(io_observer->get(),
                        &IOJankObserver::AttachToCurrentThread));
}

void UninstallJankometer() {
  if (ui_observer) {
    (*ui_observer)->DetachFromCurrentThread();
    delete ui_observer;
    ui_observer = NULL;
  }
  if (io_observer) {
    // IO thread can't be running when we remove observers.
    DCHECK((!g_browser_process) || !(g_browser_process->io_thread()));
    delete io_observer;
    io_observer = NULL;
  }
}
<commit_msg>Add static cast to remove warning about loss of precision<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 <limits>

#include "chrome/browser/jankometer.h"

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/stats_counters.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/watchdog.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/common/chrome_switches.h"

#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/gtk/gtk_util.h"
#endif

using base::TimeDelta;
using base::TimeTicks;

namespace {

// The maximum threshold of delay of the message  before considering it a delay.
// For a debug build, you may want to set IO delay around 500ms.
// For a release build, setting it around 350ms is sensible.
// Visit about:histograms to see what the distribution is on your system, with
// your build. Be sure to do some work to get interesting stats.
// The numbers below came from a warm start (you'll get about 5-10 alarms with
// a cold start), and running the page-cycler for 5 rounds.
#ifdef NDEBUG
const int kMaxUIMessageDelayMs = 350;
const int kMaxIOMessageDelayMs = 200;
#else
const int kMaxUIMessageDelayMs = 500;
const int kMaxIOMessageDelayMs = 400;
#endif

// Maximum processing time (excluding queueing delay) for a message before
// considering it delayed.
const int kMaxMessageProcessingMs = 100;

// TODO(brettw) Consider making this a pref.
const bool kPlaySounds = false;

//------------------------------------------------------------------------------
// Provide a special watchdog to make it easy to set the breakpoint on this
// class only.
class JankWatchdog : public Watchdog {
 public:
  JankWatchdog(const TimeDelta& duration,
               const std::string& thread_watched_name,
               bool enabled)
      : Watchdog(duration, thread_watched_name, enabled),
        thread_name_watched_(thread_watched_name),
        alarm_count_(0) {
  }

  virtual ~JankWatchdog() {}

  virtual void Alarm() {
    // Put break point here if you want to stop threads and look at what caused
    // the jankiness.
    alarm_count_++;
    Watchdog::Alarm();
  }

 private:
  std::string thread_name_watched_;
  int alarm_count_;

  DISALLOW_COPY_AND_ASSIGN(JankWatchdog);
};

class JankObserverHelper {
 public:
  JankObserverHelper(const std::string& thread_name,
                     const TimeDelta& excessive_duration,
                     bool watchdog_enable);
  ~JankObserverHelper();

  void StartProcessingTimers(const TimeDelta& queueing_time);
  void EndProcessingTimers();

  // Indicate if we will bother to measuer this message.
  bool MessageWillBeMeasured();

  static void SetDefaultMessagesToSkip(int count) { discard_count_ = count; }

 private:
  const TimeDelta max_message_delay_;

  // Indicate if we'll bother measuring this message.
  bool measure_current_message_;

  // Down counter which will periodically hit 0, and only then bother to measure
  // the corresponding message.
  int events_till_measurement_;

  // The value to re-initialize events_till_measurement_ after it reaches 0.
  static int discard_count_;

  // Time at which the current message processing began.
  TimeTicks begin_process_message_;

  // Time the current message spent in the queue -- delta between message
  // construction time and message processing time.
  TimeDelta queueing_time_;

  // Counters for the two types of jank we measure.
  base::StatsCounter slow_processing_counter_;  // Msgs w/ long proc time.
  base::StatsCounter queueing_delay_counter_;   // Msgs w/ long queueing delay.
  scoped_refptr<base::Histogram> process_times_;  // Time spent proc. task.
  scoped_refptr<base::Histogram> total_times_;  // Total queueing plus proc.
  JankWatchdog total_time_watchdog_;  // Watching for excessive total_time.

  DISALLOW_COPY_AND_ASSIGN(JankObserverHelper);
};

JankObserverHelper::JankObserverHelper(
    const std::string& thread_name,
    const TimeDelta& excessive_duration,
    bool watchdog_enable)
    : max_message_delay_(excessive_duration),
      measure_current_message_(true),
      events_till_measurement_(0),
      slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name),
      queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name),
      total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) {
  process_times_ = base::Histogram::FactoryGet(
      std::string("Chrome.ProcMsgL ") + thread_name,
      1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag);
  total_times_ = base::Histogram::FactoryGet(
      std::string("Chrome.TotalMsgL ") + thread_name,
      1, 3600000, 50, base::Histogram::kUmaTargetedHistogramFlag);
  if (discard_count_ > 0) {
    // Select a vaguely random sample-start-point.
    events_till_measurement_ = static_cast<int>(
        (TimeTicks::Now() - TimeTicks()).InSeconds() % (discard_count_ + 1));
  }
}

JankObserverHelper::~JankObserverHelper() {}

// Called when a message has just begun processing, initializes
// per-message variables and timers.
void JankObserverHelper::StartProcessingTimers(const TimeDelta& queueing_time) {
  DCHECK(measure_current_message_);
  begin_process_message_ = TimeTicks::Now();
  queueing_time_ = queueing_time;

  // Simulate arming when the message entered the queue.
  total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_);
  if (queueing_time_ > max_message_delay_) {
    // Message is too delayed.
    queueing_delay_counter_.Increment();
#if defined(OS_WIN)
    if (kPlaySounds)
      MessageBeep(MB_ICONASTERISK);
#endif
  }
}

// Called when a message has just finished processing, finalizes
// per-message variables and timers.
void JankObserverHelper::EndProcessingTimers() {
  if (!measure_current_message_)
    return;
  total_time_watchdog_.Disarm();
  TimeTicks now = TimeTicks::Now();
  if (begin_process_message_ != TimeTicks()) {
    TimeDelta processing_time = now - begin_process_message_;
    process_times_->AddTime(processing_time);
    total_times_->AddTime(queueing_time_ + processing_time);
  }
  if (now - begin_process_message_ >
      TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) {
    // Message took too long to process.
    slow_processing_counter_.Increment();
#if defined(OS_WIN)
    if (kPlaySounds)
      MessageBeep(MB_ICONHAND);
#endif
  }

  // Reset message specific times.
  begin_process_message_ = base::TimeTicks();
  queueing_time_ = base::TimeDelta();
}

bool JankObserverHelper::MessageWillBeMeasured() {
  measure_current_message_ = events_till_measurement_ <= 0;
  if (!measure_current_message_)
    --events_till_measurement_;
  else
    events_till_measurement_ = discard_count_;
  return measure_current_message_;
}

// static
int JankObserverHelper::discard_count_ = 99;  // Measure only 1 in 100.

//------------------------------------------------------------------------------
class IOJankObserver : public base::RefCountedThreadSafe<IOJankObserver>,
                       public MessageLoopForIO::IOObserver,
                       public MessageLoop::TaskObserver {
 public:
  IOJankObserver(const char* thread_name,
                 TimeDelta excessive_duration,
                 bool watchdog_enable)
      : helper_(thread_name, excessive_duration, watchdog_enable) {}

  ~IOJankObserver() {}

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    MessageLoop::current()->AddTaskObserver(this);
    MessageLoopForIO::current()->AddIOObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    MessageLoopForIO::current()->RemoveIOObserver(this);
    MessageLoop::current()->RemoveTaskObserver(this);
  }

  virtual void WillProcessIOEvent() {
    if (!helper_.MessageWillBeMeasured())
      return;
    helper_.StartProcessingTimers(base::TimeDelta());
  }

  virtual void DidProcessIOEvent() {
    helper_.EndProcessingTimers();
  }

  virtual void WillProcessTask(const Task* task) {
    if (!helper_.MessageWillBeMeasured())
      return;
    base::TimeTicks now = base::TimeTicks::Now();
    const base::TimeDelta queueing_time = now - task->tracked_birth_time();
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessTask(const Task* task) {
    helper_.EndProcessingTimers();
  }

 private:
  friend class base::RefCountedThreadSafe<IOJankObserver>;

  JankObserverHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(IOJankObserver);
};

//------------------------------------------------------------------------------
class UIJankObserver : public base::RefCountedThreadSafe<UIJankObserver>,
                       public MessageLoop::TaskObserver,
                       public MessageLoopForUI::Observer {
 public:
  UIJankObserver(const char* thread_name,
                 TimeDelta excessive_duration,
                 bool watchdog_enable)
      : helper_(thread_name, excessive_duration, watchdog_enable) {}

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
    MessageLoopForUI::current()->AddObserver(this);
    MessageLoop::current()->AddTaskObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
    MessageLoop::current()->RemoveTaskObserver(this);
    MessageLoopForUI::current()->RemoveObserver(this);
  }

  virtual void WillProcessTask(const Task* task) {
    if (!helper_.MessageWillBeMeasured())
      return;
    base::TimeTicks now = base::TimeTicks::Now();
    const base::TimeDelta queueing_time = now - task->tracked_birth_time();
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessTask(const Task* task) {
    helper_.EndProcessingTimers();
  }

#if defined(OS_WIN)
  virtual void WillProcessMessage(const MSG& msg) {
    if (!helper_.MessageWillBeMeasured())
      return;
    // GetMessageTime returns a LONG (signed 32-bit) and GetTickCount returns
    // a DWORD (unsigned 32-bit). They both wrap around when the time is longer
    // than they can hold. I'm not sure if GetMessageTime wraps around to 0,
    // or if the original time comes from GetTickCount, it might wrap around
    // to -1.
    //
    // Therefore, I cast to DWORD so if it wraps to -1 we will correct it. If
    // it doesn't, then our time delta will be negative if a message happens
    // to straddle the wraparound point, it will still be OK.
    DWORD cur_message_issue_time = static_cast<DWORD>(msg.time);
    DWORD cur_time = GetTickCount();
    base::TimeDelta queueing_time =
        base::TimeDelta::FromMilliseconds(cur_time - cur_message_issue_time);

    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessMessage(const MSG& msg) {
    helper_.EndProcessingTimers();
  }
#elif defined(TOOLKIT_USES_GTK)
  virtual void WillProcessEvent(GdkEvent* event) {
    if (!helper_.MessageWillBeMeasured())
      return;
    // TODO(evanm): we want to set queueing_time_ using
    // gdk_event_get_time, but how do you convert that info
    // into a delta?
    // guint event_time = gdk_event_get_time(event);
    base::TimeDelta queueing_time = base::TimeDelta::FromMilliseconds(0);
    helper_.StartProcessingTimers(queueing_time);
  }

  virtual void DidProcessEvent(GdkEvent* event) {
    helper_.EndProcessingTimers();
  }
#endif

 private:
  friend class base::RefCountedThreadSafe<UIJankObserver>;

  ~UIJankObserver() {}

  JankObserverHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(UIJankObserver);
};

// These objects are created by InstallJankometer and leaked.
const scoped_refptr<UIJankObserver>* ui_observer = NULL;
const scoped_refptr<IOJankObserver>* io_observer = NULL;

}  // namespace

void InstallJankometer(const CommandLine& parsed_command_line) {
  if (ui_observer || io_observer) {
    NOTREACHED() << "Initializing jank-o-meter twice";
    return;
  }

  bool ui_watchdog_enabled = false;
  bool io_watchdog_enabled = false;
  if (parsed_command_line.HasSwitch(switches::kEnableWatchdog)) {
    std::string list =
        parsed_command_line.GetSwitchValueASCII(switches::kEnableWatchdog);
    if (list.npos != list.find("ui"))
      ui_watchdog_enabled = true;
    if (list.npos != list.find("io"))
      io_watchdog_enabled = true;
  }

  if (ui_watchdog_enabled || io_watchdog_enabled)
    JankObserverHelper::SetDefaultMessagesToSkip(0);  // Watch everything.

  // Install on the UI thread.
  ui_observer = new scoped_refptr<UIJankObserver>(
      new UIJankObserver(
          "UI",
          TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs),
          ui_watchdog_enabled));
  (*ui_observer)->AttachToCurrentThread();

  // Now install on the I/O thread. Hiccups on that thread will block
  // interaction with web pages. We must proxy to that thread before we can
  // add our observer.
  io_observer = new scoped_refptr<IOJankObserver>(
      new IOJankObserver(
          "IO",
          TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs),
          io_watchdog_enabled));
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(io_observer->get(),
                        &IOJankObserver::AttachToCurrentThread));
}

void UninstallJankometer() {
  if (ui_observer) {
    (*ui_observer)->DetachFromCurrentThread();
    delete ui_observer;
    ui_observer = NULL;
  }
  if (io_observer) {
    // IO thread can't be running when we remove observers.
    DCHECK((!g_browser_process) || !(g_browser_process->io_thread()));
    delete io_observer;
    io_observer = NULL;
  }
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef STRING_H
#define STRING_H

#include <types.hpp>
#include <algorithms.hpp>
#include <vector.hpp>

namespace std {

inline uint64_t str_len(const char* a){
    uint64_t length = 0;
    while(*a++){
        ++length;
    }
    return length;
}

template<typename CharT>
struct basic_string {
public:
    typedef CharT*             iterator;
    typedef const CharT*       const_iterator;

private:
    size_t _size;
    size_t _capacity;
    CharT* _data;

public:
    //Constructors

    basic_string() : _size(0), _capacity(1), _data(new CharT[1]) {
        _data[0] = '\0';
    }

    basic_string(const CharT* s) : _size(str_len(s)), _capacity(_size + 1), _data(new CharT[_capacity]) {
        std::copy_n(_data, s, _capacity);
    }

    explicit basic_string(size_t __capacity) : _size(0), _capacity(__capacity), _data(new CharT[_capacity]) {
        _data[0] = '\0';
    }

    //Copy constructors

    basic_string(const basic_string& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(new CharT[_capacity]) {
        std::copy_n(_data, rhs._data, _size + 1);
    }

    basic_string& operator=(const basic_string& rhs){
        if(this != &rhs){
            if(_capacity < rhs._capacity || !_data){
                if(_data){
                    delete[] _data;
                }

                _capacity = rhs._capacity;
                _data = new CharT[_capacity];
            }

            _size = rhs._size;
            std::copy_n(_data, rhs._data, _size + 1);
        }

        return *this;
    }

    //Move constructors

    basic_string(basic_string&& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(rhs._data) {
        rhs._size = 0;
        rhs._capacity = 0;
        rhs._data = nullptr;
    }

    basic_string& operator=(basic_string&& rhs){
        if(_data){
            delete[] _data;
        }

        _size = rhs._size;
        _capacity = rhs._capacity;
        _data = rhs._data;

        rhs._size = 0;
        rhs._capacity = 0;
        rhs._data = nullptr;

        return *this;
    }

    //Destructors

    ~basic_string(){
        if(_data){
            delete[] _data;
        }
    }

    //Modifiers

    void clear(){
        _size = 0;
        _data[0] = '\0';
    }

    void pop_back(){
        _data[--_size] = '\0';
    }

    basic_string operator+(CharT c) const {
        basic_string copy(*this);

        copy += c;

        return move(copy);
    }

    basic_string& operator+=(CharT c){
        if(!_data || _capacity <= _size + 1){
            _capacity = _capacity ? _capacity * 2 : 1;
            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        _data[_size] = c;
        _data[++_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const char* rhs){
        auto len = str_len(rhs);
        if(!_data || _capacity <= _size + len){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < _size + len){
                _capacity = _size + len + 1;
            }

            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        std::copy_n(_data + _size, rhs, len);

        _size += len;

        _data[_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const basic_string& rhs){
        if(!_data || _capacity <= _size + rhs.size()){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < _size + rhs.size()){
                _capacity = _size + rhs.size() + 1;
            }

            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        std::copy_n(_data + _size, rhs.c_str(), rhs.size());

        _size += rhs.size();

        _data[_size] = '\0';

        return *this;
    }

    //Accessors

    size_t size() const {
        return _size;
    }

    size_t capacity() const {
        return _capacity;
    }

    bool empty() const {
        return !_size;
    }

    CharT* c_str(){
        return _data;
    }

    const CharT* c_str() const {
        return _data;
    }

    CharT& operator[](size_t i){
        return _data[i];
    }

    const CharT& operator[](size_t i) const {
        return _data[i];
    }

    //Operators

    bool operator==(const CharT* s) const {
        if(size() != str_len(s)){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != s[i]){
                return false;
            }
        }

        return true;
    }

    bool operator==(const basic_string& rhs) const {
        if(size() != rhs.size()){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != rhs._data[i]){
                return false;
            }
        }

        return true;
    }

    //Iterators

    iterator begin(){
        return iterator(&_data[0]);
    }

    iterator end(){
        return iterator(&_data[_size]);
    }

    const_iterator begin() const {
        return const_iterator(&_data[0]);
    }

    const_iterator end() const {
        return const_iterator(&_data[_size]);
    }
};

typedef basic_string<char> string;

inline uint64_t parse(const char* it, const char* end){
    int i = end - it - 1;

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (it[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const char* str){
    int i = 0;

    const char* it = str;
    while(*++it){
        ++i;
    }

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (str[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const string& str){
    return parse(str.begin(), str.end());
}

template<typename N>
size_t digits(N number){
    if(number < 10){
        return 1;
    }

    size_t i = 0;

    while(number != 0){
        number /= 10;
        ++i;
    }

    return i;
}

template<typename Char>
std::vector<std::basic_string<Char>> split(const std::basic_string<Char>& s){
    std::vector<std::basic_string<Char>> parts;

    std::basic_string<Char> current(s.size());

    for(char c : s){
        if(c == ' ' && !current.empty()){
            parts.push_back(current);
            current.clear();
        } else {
            current += c;
        }
    }

    if(!current.empty()){
        parts.push_back(current);
    }

    return std::move(parts);
}

template<typename T>
std::string to_string(T value);

template<>
inline std::string to_string<uint64_t>(uint64_t value){
    if(value == 0){
        return "0";
    }

    std::string s;

    char buffer[20];
    int i = 0;

    while(value != 0){
        buffer[i++] = '0' + value % 10;
        value /= 10;
    }

    --i;

    for(; i >= 0; --i){
        s += buffer[i];
    }

    return std::move(s);
}

template<>
inline std::string to_string<int64_t>(int64_t value){
    if(value < 0){
        std::string s("-");
        s += to_string(static_cast<uint64_t>(value));
        return std::move(s);
    } else {
        return to_string(static_cast<uint64_t>(value));
    }
}

} //end of namespace std

#endif
<commit_msg>Review to_string<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef STRING_H
#define STRING_H

#include <types.hpp>
#include <algorithms.hpp>
#include <vector.hpp>

namespace std {

inline uint64_t str_len(const char* a){
    uint64_t length = 0;
    while(*a++){
        ++length;
    }
    return length;
}

template<typename CharT>
struct basic_string {
public:
    typedef CharT*             iterator;
    typedef const CharT*       const_iterator;

private:
    size_t _size;
    size_t _capacity;
    CharT* _data;

public:
    //Constructors

    basic_string() : _size(0), _capacity(1), _data(new CharT[1]) {
        _data[0] = '\0';
    }

    basic_string(const CharT* s) : _size(str_len(s)), _capacity(_size + 1), _data(new CharT[_capacity]) {
        std::copy_n(_data, s, _capacity);
    }

    explicit basic_string(size_t __capacity) : _size(0), _capacity(__capacity), _data(new CharT[_capacity]) {
        _data[0] = '\0';
    }

    //Copy constructors

    basic_string(const basic_string& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(new CharT[_capacity]) {
        std::copy_n(_data, rhs._data, _size + 1);
    }

    basic_string& operator=(const basic_string& rhs){
        if(this != &rhs){
            if(_capacity < rhs._capacity || !_data){
                if(_data){
                    delete[] _data;
                }

                _capacity = rhs._capacity;
                _data = new CharT[_capacity];
            }

            _size = rhs._size;
            std::copy_n(_data, rhs._data, _size + 1);
        }

        return *this;
    }

    //Move constructors

    basic_string(basic_string&& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(rhs._data) {
        rhs._size = 0;
        rhs._capacity = 0;
        rhs._data = nullptr;
    }

    basic_string& operator=(basic_string&& rhs){
        if(_data){
            delete[] _data;
        }

        _size = rhs._size;
        _capacity = rhs._capacity;
        _data = rhs._data;

        rhs._size = 0;
        rhs._capacity = 0;
        rhs._data = nullptr;

        return *this;
    }

    //Destructors

    ~basic_string(){
        if(_data){
            delete[] _data;
        }
    }

    //Modifiers

    void clear(){
        _size = 0;
        _data[0] = '\0';
    }

    void pop_back(){
        _data[--_size] = '\0';
    }

    basic_string operator+(CharT c) const {
        basic_string copy(*this);

        copy += c;

        return move(copy);
    }

    basic_string& operator+=(CharT c){
        if(!_data || _capacity <= _size + 1){
            _capacity = _capacity ? _capacity * 2 : 1;
            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        _data[_size] = c;
        _data[++_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const char* rhs){
        auto len = str_len(rhs);
        if(!_data || _capacity <= _size + len){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < _size + len){
                _capacity = _size + len + 1;
            }

            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        std::copy_n(_data + _size, rhs, len);

        _size += len;

        _data[_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const basic_string& rhs){
        if(!_data || _capacity <= _size + rhs.size()){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < _size + rhs.size()){
                _capacity = _size + rhs.size() + 1;
            }

            auto new_data = new CharT[_capacity];

            if(_data){
                std::copy_n(new_data, _data, _size);
                delete[] _data;
            }

            _data = new_data;
        }

        std::copy_n(_data + _size, rhs.c_str(), rhs.size());

        _size += rhs.size();

        _data[_size] = '\0';

        return *this;
    }

    //Accessors

    size_t size() const {
        return _size;
    }

    size_t capacity() const {
        return _capacity;
    }

    bool empty() const {
        return !_size;
    }

    CharT* c_str(){
        return _data;
    }

    const CharT* c_str() const {
        return _data;
    }

    CharT& operator[](size_t i){
        return _data[i];
    }

    const CharT& operator[](size_t i) const {
        return _data[i];
    }

    //Operators

    bool operator==(const CharT* s) const {
        if(size() != str_len(s)){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != s[i]){
                return false;
            }
        }

        return true;
    }

    bool operator==(const basic_string& rhs) const {
        if(size() != rhs.size()){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != rhs._data[i]){
                return false;
            }
        }

        return true;
    }

    //Iterators

    iterator begin(){
        return iterator(&_data[0]);
    }

    iterator end(){
        return iterator(&_data[_size]);
    }

    const_iterator begin() const {
        return const_iterator(&_data[0]);
    }

    const_iterator end() const {
        return const_iterator(&_data[_size]);
    }
};

typedef basic_string<char> string;

inline uint64_t parse(const char* it, const char* end){
    int i = end - it - 1;

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (it[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const char* str){
    int i = 0;

    const char* it = str;
    while(*++it){
        ++i;
    }

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (str[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const string& str){
    return parse(str.begin(), str.end());
}

template<typename N>
size_t digits(N number){
    if(number < 10){
        return 1;
    }

    size_t i = 0;

    while(number != 0){
        number /= 10;
        ++i;
    }

    return i;
}

template<typename Char>
std::vector<std::basic_string<Char>> split(const std::basic_string<Char>& s){
    std::vector<std::basic_string<Char>> parts;

    std::basic_string<Char> current(s.size());

    for(char c : s){
        if(c == ' ' && !current.empty()){
            parts.push_back(current);
            current.clear();
        } else {
            current += c;
        }
    }

    if(!current.empty()){
        parts.push_back(current);
    }

    return std::move(parts);
}

template<typename T>
std::string to_string(const T& value);

template<>
inline std::string to_string<uint64_t>(const uint64_t& value){
    if(value == 0){
        return "0";
    }

    std::string s;

    char buffer[20];
    int i = 0;
    auto rem = value;

    while(rem != 0){
        buffer[i++] = '0' + rem  % 10;
        rem /= 10;
    }

    --i;

    for(; i >= 0; --i){
        s += buffer[i];
    }

    return std::move(s);
}

template<>
inline std::string to_string<int64_t>(const int64_t& value){
    if(value < 0){
        std::string s("-");
        s += to_string(static_cast<uint64_t>(value));
        return std::move(s);
    } else {
        return to_string(static_cast<uint64_t>(value));
    }
}

template<>
inline std::string to_string<unsigned int>(const unsigned int& value){
    return to_string(static_cast<size_t>(value));
}

} //end of namespace std

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef STRING_H
#define STRING_H

#include <types.hpp>
#include <algorithms.hpp>
#include <vector.hpp>
#include <unique_ptr.hpp>

namespace std {

inline uint64_t str_len(const char* a){
    uint64_t length = 0;
    while(*a++){
        ++length;
    }
    return length;
}

template<typename CharT>
struct basic_string {
public:
    typedef CharT*             iterator;
    typedef const CharT*       const_iterator;

    static constexpr const size_t npos = -1;

private:
    size_t _size;
    size_t _capacity;
    unique_ptr<CharT[]> _data;

public:
    //Constructors

    basic_string() : _size(0), _capacity(1), _data(new CharT[1]) {
        _data[0] = '\0';
    }

    basic_string(const CharT* s) : _size(str_len(s)), _capacity(_size + 1), _data(new CharT[_capacity]) {
        std::copy_n(_data.get(), s, _capacity);
    }

    explicit basic_string(size_t __capacity) : _size(0), _capacity(__capacity), _data(new CharT[_capacity]) {
        _data[0] = '\0';
    }

    //Copy constructors

    basic_string(const basic_string& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data() {
        if(_capacity > 0){
            _data.reset(new CharT[_capacity]);

            std::copy_n(_data.get(), rhs._data.get(), _size + 1);
        }
    }

    basic_string& operator=(const basic_string& rhs){
        if(this != &rhs){
            if(_capacity < rhs._capacity || !_data){
                _capacity = rhs._capacity;
                _data.reset(new CharT[_capacity]);
            }

            _size = rhs._size;
            std::copy_n(_data.get(), rhs._data.get(), _size + 1);
        }

        return *this;
    }

    //Move constructors

    basic_string(basic_string&& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(std::move(rhs._data)) {
        rhs._size = 0;
        rhs._capacity = 0;
        //rhs._data = nullptr;
    }

    basic_string& operator=(basic_string&& rhs){
        _size = rhs._size;
        _capacity = rhs._capacity;
        _data = std::move(rhs._data);

        rhs._size = 0;
        rhs._capacity = 0;
        //rhs._data = nullptr;

        return *this;
    }

    //Destructors

    ~basic_string() = default;

    //Modifiers

    void clear(){
        _size = 0;
        _data[0] = '\0';
    }

    void pop_back(){
        _data[--_size] = '\0';
    }

    void reserve(size_t new_capacity){
        ensure_capacity(new_capacity);
    }

    basic_string operator+(CharT c) const {
        basic_string copy(*this);

        copy += c;

        return move(copy);
    }

    basic_string& operator+=(CharT c){
        ensure_capacity(_size + 2);

        _data[_size] = c;
        _data[++_size] = '\0';

        return *this;
    }

    void ensure_capacity(size_t new_capacity){
        if(new_capacity > 0 && (!_data || _capacity < new_capacity)){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < new_capacity){
                _capacity = new_capacity;
            }

            auto new_data = new CharT[_capacity];

            std::copy_n(new_data, _data.get(), _size);

            _data.reset(new_data);
        }
    }

    basic_string& operator+=(const char* rhs){
        auto len = str_len(rhs);

        ensure_capacity(_size + len + 1);

        std::copy_n(_data.get() + _size, rhs, len);

        _size += len;

        _data[_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const basic_string& rhs){
        ensure_capacity(_size + rhs.size() + 1);

        std::copy_n(_data.get() + _size, rhs.c_str(), rhs.size());

        _size += rhs.size();

        _data[_size] = '\0';

        return *this;
    }

    //Accessors

    size_t size() const {
        return _size;
    }

    size_t capacity() const {
        return _capacity;
    }

    bool empty() const {
        return !_size;
    }

    CharT* c_str(){
        return _data.get();
    }

    const CharT* c_str() const {
        return _data.get();
    }

    CharT& operator[](size_t i){
        return _data[i];
    }

    const CharT& operator[](size_t i) const {
        return _data[i];
    }

    size_t find(char c) const {
        for(size_t i = 0; i < size(); ++i){
            if(_data[i] == c){
                return i;
            }
        }

        return npos;
    }

    //Operators

    bool operator==(const CharT* s) const {
        if(size() != str_len(s)){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != s[i]){
                return false;
            }
        }

        return true;
    }

    bool operator!=(const CharT* s) const {
        return !(*this == s);
    }

    bool operator==(const basic_string& rhs) const {
        if(size() != rhs.size()){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != rhs._data[i]){
                return false;
            }
        }

        return true;
    }

    bool operator!=(const basic_string& rhs) const {
        return !(*this == rhs);
    }

    //Iterators

    iterator begin(){
        return iterator(&_data[0]);
    }

    iterator end(){
        return iterator(&_data[_size]);
    }

    const_iterator begin() const {
        return const_iterator(&_data[0]);
    }

    const_iterator end() const {
        return const_iterator(&_data[_size]);
    }
};

template<typename C>
basic_string<C> operator+(const basic_string<C>& lhs, const basic_string<C>& rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

template<typename C>
basic_string<C> operator+(const C* lhs, const basic_string<C>& rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

template<typename C>
basic_string<C> operator+(const basic_string<C>& lhs, const C* rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

typedef basic_string<char> string;

inline uint64_t parse(const char* it, const char* end){
    int i = end - it - 1;

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (it[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const char* str){
    int i = 0;

    const char* it = str;
    while(*++it){
        ++i;
    }

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (str[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const string& str){
    return parse(str.begin(), str.end());
}

template<typename N>
size_t digits(N number){
    if(number < 10){
        return 1;
    }

    size_t i = 0;

    while(number != 0){
        number /= 10;
        ++i;
    }

    return i;
}

template<typename Char>
std::vector<std::basic_string<Char>> split(const std::basic_string<Char>& s, char sep = ' '){
    std::vector<std::basic_string<Char>> parts;

    std::basic_string<Char> current(s.size());

    for(char c : s){
        if(c == sep && !current.empty()){
            parts.push_back(current);
            current.clear();
        } else if(c == sep){
            continue;
        } else {
            current += c;
        }
    }

    if(!current.empty()){
        parts.push_back(current);
    }

    return std::move(parts);
}

template<typename T>
std::string to_string(const T& value);

template<>
inline std::string to_string<uint64_t>(const uint64_t& value){
    if(value == 0){
        return "0";
    }

    std::string s;

    char buffer[20];
    int i = 0;
    auto rem = value;

    while(rem != 0){
        buffer[i++] = '0' + rem  % 10;
        rem /= 10;
    }

    --i;

    for(; i >= 0; --i){
        s += buffer[i];
    }

    return std::move(s);
}

template<>
inline std::string to_string<int64_t>(const int64_t& value){
    if(value < 0){
        std::string s("-");
        s += to_string(static_cast<uint64_t>(value));
        return std::move(s);
    } else {
        return to_string(static_cast<uint64_t>(value));
    }
}

template<>
inline std::string to_string<uint8_t>(const uint8_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<uint16_t>(const uint16_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<uint32_t>(const uint32_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<int8_t>(const int8_t& value){
    return to_string(static_cast<int64_t>(value));
}

template<>
inline std::string to_string<int16_t>(const int16_t& value){
    return to_string(static_cast<int64_t>(value));
}

template<>
inline std::string to_string<int32_t>(const int32_t& value){
    return to_string(static_cast<int64_t>(value));
}

} //end of namespace std

#endif
<commit_msg>Start working on SSO<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef STRING_H
#define STRING_H

#include <types.hpp>
#include <algorithms.hpp>
#include <vector.hpp>
#include <unique_ptr.hpp>

namespace std {

inline uint64_t str_len(const char* a){
    uint64_t length = 0;
    while(*a++){
        ++length;
    }
    return length;
}

static constexpr const size_t SSO_SIZE = 16;

template<typename CharT>
struct base_small {
    CharT data[SSO_SIZE];
};

template<typename CharT>
struct base_big {
    size_t capacity;
    unique_ptr<CharT[]> data;

    base_big(size_t capacity, CharT* array) : capacity(capacity), data(array){
        //Nothing to do
    }
};

template<typename CharT>
union base_storage {
    base_small<CharT> small;
    base_big<CharT> big;

    base_storage(){
        //Default construction: Nothing to do
    }

    base_storage(size_t capacity, CharT* array) : big(capacity, array) {
        //Default construction: Nothing to do
    }

    ~base_storage() {}
};

static_assert(SSO_SIZE == sizeof(base_small<char>), "base_small must be the correct SSO size");
static_assert(SSO_SIZE == sizeof(base_big<char>), "base_big must be the correct SSO size");

template<typename CharT>
struct basic_string {
public:
    typedef CharT*             iterator;
    typedef const CharT*       const_iterator;

    static constexpr const size_t npos = -1;

private:
    size_t _size;

    base_storage<CharT> storage;

    bool is_small() const {
        return _size < 16;
    }

public:
    //Constructors

    basic_string() : _size(0){
        storage.small.data[0] = '\0';
    }

    basic_string(const CharT* s) : _size(str_len(s)) {
        auto capacity = _size + 1;

        if(is_small()){
            std::copy_n(&storage.small.data[0], s, capacity);
        } else {
            storage.big.capacity = capacity;
            storage.big.data.reset(new CharT[capacity]);
            std::copy_n(storage.big.data.get(), s, capacity);
        }
    }

    explicit basic_string(size_t __capacity) : _size(0), _capacity(__capacity), _data(new CharT[_capacity]) {
        _data[0] = '\0';
    }

    //Copy constructors

    basic_string(const basic_string& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data() {
        if(_capacity > 0){
            _data.reset(new CharT[_capacity]);

            std::copy_n(_data.get(), rhs._data.get(), _size + 1);
        }
    }

    basic_string& operator=(const basic_string& rhs){
        if(this != &rhs){
            if(_capacity < rhs._capacity || !_data){
                _capacity = rhs._capacity;
                _data.reset(new CharT[_capacity]);
            }

            _size = rhs._size;
            std::copy_n(_data.get(), rhs._data.get(), _size + 1);
        }

        return *this;
    }

    //Move constructors

    basic_string(basic_string&& rhs) : _size(rhs._size), _capacity(rhs._capacity), _data(std::move(rhs._data)) {
        rhs._size = 0;
        rhs._capacity = 0;
        //rhs._data = nullptr;
    }

    basic_string& operator=(basic_string&& rhs){
        _size = rhs._size;
        _capacity = rhs._capacity;
        _data = std::move(rhs._data);

        rhs._size = 0;
        rhs._capacity = 0;
        //rhs._data = nullptr;

        return *this;
    }

    //Destructors

    ~basic_string(){
        if(!is_small()){
            storage.big.~base_big();
        }
    }

    //Modifiers

    void clear(){
        _size = 0;
        _data[0] = '\0';
    }

    void pop_back(){
        _data[--_size] = '\0';
    }

    void reserve(size_t new_capacity){
        ensure_capacity(new_capacity);
    }

    basic_string operator+(CharT c) const {
        basic_string copy(*this);

        copy += c;

        return move(copy);
    }

    basic_string& operator+=(CharT c){
        ensure_capacity(_size + 2);

        _data[_size] = c;
        _data[++_size] = '\0';

        return *this;
    }

    void ensure_capacity(size_t new_capacity){
        if(new_capacity > 0 && (!_data || _capacity < new_capacity)){
            _capacity = _capacity ? _capacity * 2 : 1;

            if(_capacity < new_capacity){
                _capacity = new_capacity;
            }

            auto new_data = new CharT[_capacity];

            std::copy_n(new_data, _data.get(), _size);

            _data.reset(new_data);
        }
    }

    basic_string& operator+=(const char* rhs){
        auto len = str_len(rhs);

        ensure_capacity(_size + len + 1);

        std::copy_n(_data.get() + _size, rhs, len);

        _size += len;

        _data[_size] = '\0';

        return *this;
    }

    basic_string& operator+=(const basic_string& rhs){
        ensure_capacity(_size + rhs.size() + 1);

        std::copy_n(_data.get() + _size, rhs.c_str(), rhs.size());

        _size += rhs.size();

        _data[_size] = '\0';

        return *this;
    }

    //Accessors

    size_t size() const {
        return _size;
    }

    size_t capacity() const {
        return _capacity;
    }

    bool empty() const {
        return !_size;
    }

    CharT* c_str(){
        return _data.get();
    }

    const CharT* c_str() const {
        return _data.get();
    }

    CharT& operator[](size_t i){
        return _data[i];
    }

    const CharT& operator[](size_t i) const {
        return _data[i];
    }

    size_t find(char c) const {
        for(size_t i = 0; i < size(); ++i){
            if(_data[i] == c){
                return i;
            }
        }

        return npos;
    }

    //Operators

    bool operator==(const CharT* s) const {
        if(size() != str_len(s)){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != s[i]){
                return false;
            }
        }

        return true;
    }

    bool operator!=(const CharT* s) const {
        return !(*this == s);
    }

    bool operator==(const basic_string& rhs) const {
        if(size() != rhs.size()){
            return false;
        }

        for(size_t i = 0; i < size(); ++i){
            if(_data[i] != rhs._data[i]){
                return false;
            }
        }

        return true;
    }

    bool operator!=(const basic_string& rhs) const {
        return !(*this == rhs);
    }

    //Iterators

    iterator begin(){
        return iterator(&_data[0]);
    }

    iterator end(){
        return iterator(&_data[_size]);
    }

    const_iterator begin() const {
        return const_iterator(&_data[0]);
    }

    const_iterator end() const {
        return const_iterator(&_data[_size]);
    }
};

template<typename C>
basic_string<C> operator+(const basic_string<C>& lhs, const basic_string<C>& rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

template<typename C>
basic_string<C> operator+(const C* lhs, const basic_string<C>& rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

template<typename C>
basic_string<C> operator+(const basic_string<C>& lhs, const C* rhs){
    basic_string<C> result;
    result += lhs;
    result += rhs;
    return std::move(result);
}

typedef basic_string<char> string;

static_assert(sizeof(string) == 24, "The size of a string must always be 24 bytes");

inline uint64_t parse(const char* it, const char* end){
    int i = end - it - 1;

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (it[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const char* str){
    int i = 0;

    const char* it = str;
    while(*++it){
        ++i;
    }

    uint64_t factor = 1;
    uint64_t acc = 0;

    for(; i >= 0; --i){
        acc += (str[i] - '0') * factor;
        factor *= 10;
    }

    return acc;
}

inline uint64_t parse(const string& str){
    return parse(str.begin(), str.end());
}

template<typename N>
size_t digits(N number){
    if(number < 10){
        return 1;
    }

    size_t i = 0;

    while(number != 0){
        number /= 10;
        ++i;
    }

    return i;
}

template<typename Char>
std::vector<std::basic_string<Char>> split(const std::basic_string<Char>& s, char sep = ' '){
    std::vector<std::basic_string<Char>> parts;

    std::basic_string<Char> current(s.size());

    for(char c : s){
        if(c == sep && !current.empty()){
            parts.push_back(current);
            current.clear();
        } else if(c == sep){
            continue;
        } else {
            current += c;
        }
    }

    if(!current.empty()){
        parts.push_back(current);
    }

    return std::move(parts);
}

template<typename T>
std::string to_string(const T& value);

template<>
inline std::string to_string<uint64_t>(const uint64_t& value){
    if(value == 0){
        return "0";
    }

    std::string s;

    char buffer[20];
    int i = 0;
    auto rem = value;

    while(rem != 0){
        buffer[i++] = '0' + rem  % 10;
        rem /= 10;
    }

    --i;

    for(; i >= 0; --i){
        s += buffer[i];
    }

    return std::move(s);
}

template<>
inline std::string to_string<int64_t>(const int64_t& value){
    if(value < 0){
        std::string s("-");
        s += to_string(static_cast<uint64_t>(value));
        return std::move(s);
    } else {
        return to_string(static_cast<uint64_t>(value));
    }
}

template<>
inline std::string to_string<uint8_t>(const uint8_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<uint16_t>(const uint16_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<uint32_t>(const uint32_t& value){
    return to_string(static_cast<uint64_t>(value));
}

template<>
inline std::string to_string<int8_t>(const int8_t& value){
    return to_string(static_cast<int64_t>(value));
}

template<>
inline std::string to_string<int16_t>(const int16_t& value){
    return to_string(static_cast<int64_t>(value));
}

template<>
inline std::string to_string<int32_t>(const int32_t& value){
    return to_string(static_cast<int64_t>(value));
}

} //end of namespace std

#endif
<|endoftext|>


<commit_before>

#include <QDebug>
#include <QProcess>
#include <comboboxconfig.h>

PacmanPlugin::PacmanPlugin(QObject *parent) :
	PackageManagerPlugin(parent)
{

}

void PacmanPlugin::initialize()
{
	_settings = createSyncedSettings(this);
}

QList<PacmanPlugin::FilterInfo> PacmanPlugin::extraFilters()
{
	QList<PacmanPlugin::FilterInfo> list;
	list.append({QStringLiteral("&Explicitly installed"), QStringLiteral("Only explicitly installed packages"), false});
	list.append({QStringLiteral("&Leaf packages"), QStringLiteral("Only leaf packages"), false});
	list.append({QStringLiteral("&Foreign packages only"), QStringLiteral("Only packages that are not present in any mirror (includes AUR packages)"), false});
	list.append({QStringLiteral("&Native packages only"), QStringLiteral("Only packages that are present in any mirror (excludes AUR packages)"), false});
	return list;
}

QStringList PacmanPlugin::listAllPackages()
{
	return  listPackages({false, false, false, false});
}

QStringList PacmanPlugin::listPackages(QVector<bool> extraFilters)
{
	if(extraFilters[2] && extraFilters[3])
		return {};

	auto queryString = QStringLiteral("-Qq");

	if(extraFilters[0])
		queryString += QLatin1Char('e');
	if(extraFilters[1])
		queryString += QStringLiteral("tt");
	if(extraFilters[2])
		queryString += QLatin1Char('m');
	if(extraFilters[3])
		queryString += QLatin1Char('n');

	QProcess p;
	p.start(QStringLiteral("pacman"), {queryString});
	if(!p.waitForFinished(5000))
		return {};

	return QString::fromUtf8(p.readAll()).split(QStringLiteral("\n"), QString::SkipEmptyParts);
}

QString PacmanPlugin::installationCmd(const QStringList &packages)
{
	auto f = _settings->value(QStringLiteral("frontend"), QStringLiteral("pacaur")).toString();
	auto s = _settings->value(QStringLiteral("sudo")).toBool();

	return ;
}

QString PacmanPlugin::uninstallationCmd(const QStringList &packages)
{
	return {};
}

QList<PackageManagerPlugin::SettingsInfo> PacmanPlugin::listSettings()
{
	return {
		{
			tr("Pacman &frontend"),
			tr("Select a pacman frontend to be used for un/installation"),
			QStringLiteral("frontend"),
			qMetaTypeId<ComboboxConfig>(),
			QVariant::fromValue<ComboboxConfig>({
				{QStringLiteral("pacaur"), QStringLiteral("yaourt"), QStringLiteral("pacman")},
				{},
				QStringLiteral("pacaur"),
				true
			})
		},
		{
			tr("Requires &root"),
			tr("Specify if the frontend of your choice needs to be run as root"),
			QStringLiteral("sudo"),
			QMetaType::Bool
		},
		{
			tr("&Install parameters"),
			tr("The parameters to be used for installation. "
			   "%p is replaced by the list of packages (space seperated). "
			   "If missing, the packages are appended to the command line"),
			QStringLiteral("instparams"),
			QMetaType::QString,
			QStringLiteral("-S %p")
		},
		{
			tr("&Uninstall parameters"),
			tr("The parameters to be used for uninstallation. "
			   "%p is replaced by the list of packages (space seperated). "
			   "If missing, the packages are appended to the command line"),
			QStringLiteral("uninstparams"),
			QMetaType::QString,
			QStringLiteral("-R %p")
		}
	};
}
<commit_msg>fix stash fail<commit_after>#include "pacmanplugin.h"

#include <QDebug>
#include <QProcess>
#include <comboboxconfig.h>

PacmanPlugin::PacmanPlugin(QObject *parent) :
	PackageManagerPlugin(parent)
{

}

void PacmanPlugin::initialize()
{
	_settings = createSyncedSettings(this);
}

QList<PacmanPlugin::FilterInfo> PacmanPlugin::extraFilters()
{
	QList<PacmanPlugin::FilterInfo> list;
	list.append({QStringLiteral("&Explicitly installed"), QStringLiteral("Only explicitly installed packages"), false});
	list.append({QStringLiteral("&Leaf packages"), QStringLiteral("Only leaf packages"), false});
	list.append({QStringLiteral("&Foreign packages only"), QStringLiteral("Only packages that are not present in any mirror (includes AUR packages)"), false});
	list.append({QStringLiteral("&Native packages only"), QStringLiteral("Only packages that are present in any mirror (excludes AUR packages)"), false});
	return list;
}

QStringList PacmanPlugin::listAllPackages()
{
	return  listPackages({false, false, false, false});
}

QStringList PacmanPlugin::listPackages(QVector<bool> extraFilters)
{
	if(extraFilters[2] && extraFilters[3])
		return {};

	auto queryString = QStringLiteral("-Qq");

	if(extraFilters[0])
		queryString += QLatin1Char('e');
	if(extraFilters[1])
		queryString += QStringLiteral("tt");
	if(extraFilters[2])
		queryString += QLatin1Char('m');
	if(extraFilters[3])
		queryString += QLatin1Char('n');

	QProcess p;
	p.start(QStringLiteral("pacman"), {queryString});
	if(!p.waitForFinished(5000))
		return {};

	return QString::fromUtf8(p.readAll()).split(QStringLiteral("\n"), QString::SkipEmptyParts);
}

QString PacmanPlugin::installationCmd(const QStringList &packages)
{
	auto f = _settings->value(QStringLiteral("frontend"), QStringLiteral("pacaur")).toString();
	auto s = _settings->value(QStringLiteral("sudo")).toBool();

	return ;
}

QString PacmanPlugin::uninstallationCmd(const QStringList &packages)
{
	return {};
}

QList<PackageManagerPlugin::SettingsInfo> PacmanPlugin::listSettings()
{
	return {
		{
			tr("Pacman &frontend"),
			tr("Select a pacman frontend to be used for un/installation"),
			QStringLiteral("frontend"),
			qMetaTypeId<ComboboxConfig>(),
			QVariant::fromValue<ComboboxConfig>({
				{QStringLiteral("pacaur"), QStringLiteral("yaourt"), QStringLiteral("pacman")},
				{},
				QStringLiteral("pacaur"),
				true
			})
		},
		{
			tr("Requires &root"),
			tr("Specify if the frontend of your choice needs to be run as root"),
			QStringLiteral("sudo"),
			QMetaType::Bool
		},
		{
			tr("&Install parameters"),
			tr("The parameters to be used for installation. "
			   "%p is replaced by the list of packages (space seperated). "
			   "If missing, the packages are appended to the command line"),
			QStringLiteral("instparams"),
			QMetaType::QString,
			QStringLiteral("-S %p")
		},
		{
			tr("&Uninstall parameters"),
			tr("The parameters to be used for uninstallation. "
			   "%p is replaced by the list of packages (space seperated). "
			   "If missing, the packages are appended to the command line"),
			QStringLiteral("uninstparams"),
			QMetaType::QString,
			QStringLiteral("-R %p")
		}
	};
}
<|endoftext|>


<commit_before>#include <exotica/Exotica.h>
#undef NDEBUG
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <exotica_core_task_maps/CoM.h>
#include <exotica_core_task_maps/collision_distance.h>
#include <exotica_core_task_maps/continuous_collision.h>
#include <exotica_core_task_maps/distance.h>
#include <exotica_core_task_maps/eff_axis_alignment.h>
#include <exotica_core_task_maps/eff_frame.h>
#include <exotica_core_task_maps/eff_orientation.h>
#include <exotica_core_task_maps/eff_position.h>
#include <exotica_core_task_maps/identity.h>
#include <exotica_core_task_maps/interaction_mesh.h>
#include <exotica_core_task_maps/joint_acceleration_backward_difference.h>
#include <exotica_core_task_maps/joint_jerk_backward_difference.h>
#include <exotica_core_task_maps/joint_limit.h>
#include <exotica_core_task_maps/joint_velocity_backward_difference.h>
#include <exotica_core_task_maps/look_at.h>
#include <exotica_core_task_maps/point_to_line.h>
#include <exotica_core_task_maps/sphere_collision.h>

using namespace exotica;
namespace py = pybind11;

PYBIND11_MODULE(task_map_py, module)
{
    module.doc() = "Exotica task map definitions";

    py::module::import("pyexotica");

    py::class_<EffFrame, std::shared_ptr<EffFrame>, TaskMap>(module, "EffFrame")
        .def_readonly("rotation_type", &EffFrame::rotation_type_);

    py::class_<EffPosition, std::shared_ptr<EffPosition>, TaskMap>(module, "EffPosition");

    py::class_<EffOrientation, std::shared_ptr<EffOrientation>, TaskMap>(module, "EffOrientation")
        .def_readonly("rotation_type", &EffOrientation::rotation_type_);

    py::class_<EffAxisAlignment, std::shared_ptr<EffAxisAlignment>, TaskMap>(module, "EffAxisAlignment")
        .def("get_axis", &EffAxisAlignment::get_axis)
        .def("set_axis", &EffAxisAlignment::set_axis)
        .def("get_direction", &EffAxisAlignment::get_direction)
        .def("set_direction", &EffAxisAlignment::set_direction);

    py::class_<LookAt, std::shared_ptr<LookAt>, TaskMap>(module, "LookAt")
        .def("get_look_at_target_in_world", &LookAt::get_look_at_target_in_world);

    py::class_<Point2Line, std::shared_ptr<Point2Line>, TaskMap>(module, "Point2Line")
        .def_property("end_point", &Point2Line::getEndPoint, &Point2Line::setEndPoint);

    py::class_<JointVelocityBackwardDifference, std::shared_ptr<JointVelocityBackwardDifference>, TaskMap>(module, "JointVelocityBackwardDifference")
        .def("set_previous_joint_state", &JointVelocityBackwardDifference::set_previous_joint_state);

    py::class_<JointAccelerationBackwardDifference, std::shared_ptr<JointAccelerationBackwardDifference>, TaskMap>(module, "JointAccelerationBackwardDifference")
        .def("set_previous_joint_state", &JointAccelerationBackwardDifference::set_previous_joint_state);

    py::class_<JointJerkBackwardDifference, std::shared_ptr<JointJerkBackwardDifference>, TaskMap>(module, "JointJerkBackwardDifference")
        .def("set_previous_joint_state", &JointJerkBackwardDifference::set_previous_joint_state);

    py::class_<CoM, std::shared_ptr<CoM>, TaskMap>(module, "CoM");

    py::class_<Distance, std::shared_ptr<Distance>, TaskMap>(module, "Distance");

    py::class_<Identity, std::shared_ptr<Identity>, TaskMap>(module, "Identity")
        .def_readonly("N", &Identity::N_)
        .def_readonly("joint_map", &Identity::joint_map_)
        .def_readwrite("joint_ref", &Identity::joint_ref_);

    py::class_<IMesh, std::shared_ptr<IMesh>, TaskMap>(module, "IMesh")
        .def_property("W", &IMesh::get_weights, &IMesh::set_weights)
        .def("set_weight", &IMesh::set_weight)
        .def_static("compute_goal_laplace", [](const std::vector<KDL::Frame>& nodes, Eigen::MatrixXdRefConst weights) {
            Eigen::VectorXd goal;
            IMesh::compute_goal_laplace(nodes, goal, weights);
            return goal;
        })
        .def_static("compute_laplace", [](Eigen::VectorXdRefConst eff_phi, Eigen::MatrixXdRefConst weights) {
            return IMesh::compute_laplace(eff_phi, weights);
        });

    py::class_<JointLimit, std::shared_ptr<JointLimit>, TaskMap>(module, "JointLimit");

    py::class_<SphereCollision, std::shared_ptr<SphereCollision>, TaskMap>(module, "SphereCollision");

    py::class_<CollisionDistance, std::shared_ptr<CollisionDistance>, TaskMap>(module, "CollisionDistance")
        .def("get_collision_proxies", &CollisionDistance::get_collision_proxies);

    py::class_<ContinuousCollision, std::shared_ptr<ContinuousCollision>, TaskMap>(module, "ContinuousCollision")
        .def("get_collision_proxies", &ContinuousCollision::get_collision_proxies)
        .def("update_collision_objects", &ContinuousCollision::update_collision_objects);
}
<commit_msg>[exotica_core_task_maps] Fix exotica_core_task_map_py<commit_after>#include <exotica/Exotica.h>
#undef NDEBUG
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <exotica_core_task_maps/CoM.h>
#include <exotica_core_task_maps/collision_distance.h>
#include <exotica_core_task_maps/continuous_collision.h>
#include <exotica_core_task_maps/distance.h>
#include <exotica_core_task_maps/eff_axis_alignment.h>
#include <exotica_core_task_maps/eff_frame.h>
#include <exotica_core_task_maps/eff_orientation.h>
#include <exotica_core_task_maps/eff_position.h>
#include <exotica_core_task_maps/identity.h>
#include <exotica_core_task_maps/interaction_mesh.h>
#include <exotica_core_task_maps/joint_acceleration_backward_difference.h>
#include <exotica_core_task_maps/joint_jerk_backward_difference.h>
#include <exotica_core_task_maps/joint_limit.h>
#include <exotica_core_task_maps/joint_velocity_backward_difference.h>
#include <exotica_core_task_maps/look_at.h>
#include <exotica_core_task_maps/point_to_line.h>
#include <exotica_core_task_maps/sphere_collision.h>

using namespace exotica;
namespace py = pybind11;

PYBIND11_MODULE(exotica_core_task_maps_py, module)
{
    module.doc() = "Exotica task map definitions";

    py::module::import("pyexotica");

    py::class_<EffFrame, std::shared_ptr<EffFrame>, TaskMap>(module, "EffFrame")
        .def_readonly("rotation_type", &EffFrame::rotation_type_);

    py::class_<EffPosition, std::shared_ptr<EffPosition>, TaskMap>(module, "EffPosition");

    py::class_<EffOrientation, std::shared_ptr<EffOrientation>, TaskMap>(module, "EffOrientation")
        .def_readonly("rotation_type", &EffOrientation::rotation_type_);

    py::class_<EffAxisAlignment, std::shared_ptr<EffAxisAlignment>, TaskMap>(module, "EffAxisAlignment")
        .def("get_axis", &EffAxisAlignment::get_axis)
        .def("set_axis", &EffAxisAlignment::set_axis)
        .def("get_direction", &EffAxisAlignment::get_direction)
        .def("set_direction", &EffAxisAlignment::set_direction);

    py::class_<LookAt, std::shared_ptr<LookAt>, TaskMap>(module, "LookAt")
        .def("get_look_at_target_in_world", &LookAt::get_look_at_target_in_world);

    py::class_<Point2Line, std::shared_ptr<Point2Line>, TaskMap>(module, "Point2Line")
        .def_property("end_point", &Point2Line::getEndPoint, &Point2Line::setEndPoint);

    py::class_<JointVelocityBackwardDifference, std::shared_ptr<JointVelocityBackwardDifference>, TaskMap>(module, "JointVelocityBackwardDifference")
        .def("set_previous_joint_state", &JointVelocityBackwardDifference::set_previous_joint_state);

    py::class_<JointAccelerationBackwardDifference, std::shared_ptr<JointAccelerationBackwardDifference>, TaskMap>(module, "JointAccelerationBackwardDifference")
        .def("set_previous_joint_state", &JointAccelerationBackwardDifference::set_previous_joint_state);

    py::class_<JointJerkBackwardDifference, std::shared_ptr<JointJerkBackwardDifference>, TaskMap>(module, "JointJerkBackwardDifference")
        .def("set_previous_joint_state", &JointJerkBackwardDifference::set_previous_joint_state);

    py::class_<CoM, std::shared_ptr<CoM>, TaskMap>(module, "CoM");

    py::class_<Distance, std::shared_ptr<Distance>, TaskMap>(module, "Distance");

    py::class_<Identity, std::shared_ptr<Identity>, TaskMap>(module, "Identity")
        .def_readonly("N", &Identity::N_)
        .def_readonly("joint_map", &Identity::joint_map_)
        .def_readwrite("joint_ref", &Identity::joint_ref_);

    py::class_<IMesh, std::shared_ptr<IMesh>, TaskMap>(module, "IMesh")
        .def_property("W", &IMesh::get_weights, &IMesh::set_weights)
        .def("set_weight", &IMesh::set_weight)
        .def_static("compute_goal_laplace", [](const std::vector<KDL::Frame>& nodes, Eigen::MatrixXdRefConst weights) {
            Eigen::VectorXd goal;
            IMesh::compute_goal_laplace(nodes, goal, weights);
            return goal;
        })
        .def_static("compute_laplace", [](Eigen::VectorXdRefConst eff_phi, Eigen::MatrixXdRefConst weights) {
            return IMesh::compute_laplace(eff_phi, weights);
        });

    py::class_<JointLimit, std::shared_ptr<JointLimit>, TaskMap>(module, "JointLimit");

    py::class_<SphereCollision, std::shared_ptr<SphereCollision>, TaskMap>(module, "SphereCollision");

    py::class_<CollisionDistance, std::shared_ptr<CollisionDistance>, TaskMap>(module, "CollisionDistance")
        .def("get_collision_proxies", &CollisionDistance::get_collision_proxies);

    py::class_<ContinuousCollision, std::shared_ptr<ContinuousCollision>, TaskMap>(module, "ContinuousCollision")
        .def("get_collision_proxies", &ContinuousCollision::get_collision_proxies)
        .def("update_collision_objects", &ContinuousCollision::update_collision_objects);
}
<|endoftext|>