<commit_before>#include "builtin/block_as_method.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/system.hpp"
#include "builtin/class.hpp"

#include "dispatch.hpp"
#include "call_frame.hpp"
#include "arguments.hpp"

#include "object_utils.hpp"

namespace rubinius {
  BlockAsMethod* BlockAsMethod::create(STATE, Object* self, BlockEnvironment* be) {
    BlockAsMethod* pe = state->new_object<BlockAsMethod>(as<Class>(self));
    pe->block_env(state, be);
    pe->execute = block_executor;
    return pe;
  }

  Object* BlockAsMethod::block_executor(STATE, CallFrame* call_frame, Dispatch& msg,
                                       Arguments& args)
  {
    BlockAsMethod* bm = as<BlockAsMethod>(msg.method);

    int required = bm->block_env()->method()->required_args()->to_native();

    // Stupidly, if 0 or 1 args are required by the proc, we still
    // go ahead and call it.
    //
    // Calling with 0, args are ignored.
    // Calling with 1, args are put into an array and the local gets the array
    //   (this is handled by the bytecode prologue of the block)
    // Otherwise, it's strict arg checking.
    //
    if(required > 1 && (size_t)required != args.total()) {
      Exception* exc =
        Exception::make_argument_error(state, required, args.total(), msg.name);
      exc->locations(state, System::vm_backtrace(state, Fixnum::from(0), call_frame));
      state->thread_state()->raise_exception(exc);
      return NULL;
    }

    BlockInvocation invocation(args.recv(),
        bm->block_env()->method()->scope(),
        CallFrame::cIsLambda);

    invocation.module = msg.module;

    return (*bm->block_env()->execute)(state, call_frame, bm->block_env(), args, invocation);
  }
}
<commit_msg>Trap returns through a define_method {}<commit_after>#include "builtin/block_as_method.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/system.hpp"
#include "builtin/class.hpp"

#include "dispatch.hpp"
#include "call_frame.hpp"
#include "arguments.hpp"

#include "object_utils.hpp"

namespace rubinius {
  BlockAsMethod* BlockAsMethod::create(STATE, Object* self, BlockEnvironment* be) {
    BlockAsMethod* pe = state->new_object<BlockAsMethod>(as<Class>(self));
    pe->block_env(state, be);
    pe->execute = block_executor;
    return pe;
  }

  Object* BlockAsMethod::block_executor(STATE, CallFrame* call_frame, Dispatch& msg,
                                       Arguments& args)
  {
    BlockAsMethod* bm = as<BlockAsMethod>(msg.method);

    int required = bm->block_env()->method()->required_args()->to_native();

    // Stupidly, if 0 or 1 args are required by the proc, we still
    // go ahead and call it.
    //
    // Calling with 0, args are ignored.
    // Calling with 1, args are put into an array and the local gets the array
    //   (this is handled by the bytecode prologue of the block)
    // Otherwise, it's strict arg checking.
    //
    if(required > 1 && (size_t)required != args.total()) {
      Exception* exc =
        Exception::make_argument_error(state, required, args.total(), msg.name);
      exc->locations(state, System::vm_backtrace(state, Fixnum::from(0), call_frame));
      state->thread_state()->raise_exception(exc);
      return NULL;
    }

    BlockInvocation invocation(args.recv(),
        bm->block_env()->method()->scope(),
        CallFrame::cIsLambda);

    invocation.module = msg.module;

    Object* ret = (*bm->block_env()->execute)(state, call_frame,
                                       bm->block_env(), args, invocation);

    if(!ret) {
      RaiseReason reason = state->thread_state()->raise_reason();
      if(reason == cReturn || reason == cBreak) {
        // TODO investigate if we should check the destination_scope here.
        // It doesn't appear that MRI checks anything similar.
        ret = state->thread_state()->raise_value();
        state->thread_state()->clear_exception(true);
      }
    }

    return ret;
  }
}
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <algorithm>
#include <stdexcept>

namespace helene
{

namespace detail
{
}

template <class T>
class stable_vector
{
    typedef std::vector<T> vector_type;

public:
    typedef typename vector_type::size_type size_type;

public:
    size_type
    add(const T& value)
    {
        // check for vacant position
        if(erased_.size())
        {
            const auto vacant_index = erased_.back();
            erased_.pop_back();

            new(&data_[vacant_index]) T(value);

            return vacant_index;
        }

        const auto new_index = size();
        data_.push_back(value);

        return new_index;
    }

    // access with bounds checking
    T&
    at(size_type index)
    {
        if(std::find(erased_.begin(), erased_.end(), index) != erased_.end())
        {
            throw std::out_of_range("access of deleted element");
        }

        return data_.at(index);
    }

    // access with bounds checking
    const T&
    at(size_type index) const
    {
        if(std::find(erased_.cbegin(), erased_.cend(), index) != erased_.cend())
        {
            throw std::out_of_range("access of deleted element");
        }

        return data_.at(index);
    }

    void
    erase(size_type index)
    {
        (&data_[index])->~T();
        erased_.push_back(index);
    }

    T& operator[](size_type n)
    {
        return data_[n];
    }

    const T& operator[](size_type n) const
    {
        return data_[n];
    }

    size_type
    size() const
    {
        return data_.size() - erased_.size();
    }

private:
    vector_type data_;
    std::vector<size_type> erased_;
};
} // namespace helene
<commit_msg>Comments. 	modified:   include/stable_container.hpp<commit_after>#pragma once

#include <vector>
#include <algorithm>
#include <stdexcept>

namespace helene
{

namespace detail
{
}

// deleting an element of a stable_vector doesn't affect elements before or
// after, storage is not reallocated, and the slot of the previously deleted
// element will be recycled when adding additional elements.
template <class T>
class stable_vector
{
    typedef std::vector<T> vector_type;

public:
    typedef typename vector_type::size_type size_type;

public:
    size_type
    add(const T& value)
    {
        // check for vacant position
        if(erased_.size())
        {
            const auto vacant_index = erased_.back();
            erased_.pop_back();

            new(&data_[vacant_index]) T(value);

            return vacant_index;
        }

        const auto new_index = size();
        data_.push_back(value);

        return new_index;
    }

    // access with bounds checking
    T&
    at(size_type index)
    {
        if(std::find(erased_.begin(), erased_.end(), index) != erased_.end())
        {
            throw std::out_of_range("access of deleted element");
        }

        return data_.at(index);
    }

    // access with bounds checking
    const T&
    at(size_type index) const
    {
        if(std::find(erased_.cbegin(), erased_.cend(), index) != erased_.cend())
        {
            throw std::out_of_range("access of deleted element");
        }

        return data_.at(index);
    }

    void
    erase(size_type index)
    {
        (&data_[index])->~T();
        erased_.push_back(index);
    }

    T& operator[](size_type n)
    {
        return data_[n];
    }

    const T& operator[](size_type n) const
    {
        return data_[n];
    }

    size_type
    size() const
    {
        return data_.size() - erased_.size();
    }

private:
    vector_type data_;
    std::vector<size_type> erased_;
};
} // namespace helene
<|endoftext|>


<commit_before>#pragma once

#include <cmath>

namespace storm {

inline Quaternion::Quaternion( float x, float y, float z, float w ) :
    x( x ), y( y ), z( z ), w( w )
{
}

inline Quaternion& Quaternion::operator += ( const Quaternion &other ) {
    x += other.x;
    y += other.y;
    z += other.z;
    w += other.w;
    return *this;
}

inline Quaternion& Quaternion::operator -= ( const Quaternion &other ) {
    x -= other.x;
    y -= other.y;
    z -= other.z;
    w -= other.w;
    return *this;
}

inline Quaternion& Quaternion::operator *= ( const Quaternion &other ) {
    *this = *this * other;
    return *this;
}

inline Quaternion& Quaternion::operator *= ( float multiplier ) {
    x *= multiplier;
    y *= multiplier;
    z *= multiplier;
    w *= multiplier;
    return *this;
}

inline Quaternion& Quaternion::operator /= ( float divisor ) {
    const float multiplier = 1 / divisor;
    x *= multiplier;
    y *= multiplier;
    z *= multiplier;
    w *= multiplier;
    return *this;
}

inline Quaternion Quaternion::operator + ( const Quaternion &other ) const {
    return Quaternion(
        x + other.x, y + other.y, z + other.z, w + other.w );
}

inline Quaternion Quaternion::operator - ( const Quaternion &other ) const {
    return Quaternion(
        x - other.x, y - other.y, z - other.z, w - other.w );
}

inline Quaternion Quaternion::operator * ( const Quaternion &other ) const {
    const Vector first( x, y, z );
    const Vector second( other.x, other.y, other.z );

    const Vector result = crossProduct( first, second ) +
        second * w + first * other.w;

    return Quaternion(
        result.x,
        result.y,
        result.z,
        w * other.w - dotProduct(first, second) );
}

inline Quaternion Quaternion::operator * ( float multiplier ) const {
    return Quaternion(
        x * multiplier, y * multiplier, z * multiplier, w * multiplier );
}

inline Quaternion Quaternion::operator / ( float divisor ) const {
    const float multiplier = 1 / divisor;
    return Quaternion(
        x * multiplier, y * multiplier, z * multiplier, w * multiplier );
}

inline float Quaternion::getLength() const {
    return sqrt( x * x + y * y + z * z + w * w );
}

inline void Quaternion::normalize() {
    *this /= getLength();
}

inline Quaternion Quaternion::getNormalized() const {
    Quaternion result( *this );
    result.normalize();
    return result;
}

inline Quaternion Quaternion::getConjugate() const {
    return Quaternion( -x, -y, -z, w );
}

inline Matrix Quaternion::toRotationMatrix() const {
    const float squaredLength = x * x + y * y + z * z + w * w;
    const float scale = squaredLength ? 2 / squaredLength : 0;

    const float x_ = x * scale;
    const float y_ = y * scale;
    const float z_ = z * scale;

    const float wx = w * x_;
    const float wy = w * y_;
    const float wz = w * z_;

    const float xx = x * x_;
    const float xy = x * y_;
    const float xz = x * z_;

    const float yy = y * y_;
    const float yz = y * z_;

    const float zz = z * z_;

    return storm::Matrix(
        1 - (yy + zz), xy + wz, xz - wy, 0,
        xy - wz, 1 - (xx + zz), yz + wx, 0,
        xz + wy, yz - wx, 1 - (xx + yy), 0,
        0, 0, 0, 1
    );
}

inline Quaternion Quaternion::fromAxisAngle(
    const Vector &axis, float angle )
{
    const float sine = sin( angle / 2 );
    return Quaternion(
        axis.x * sine,
        axis.y * sine,
        axis.z * sine,
        cos(angle / 2) );
}

inline Quaternion Quaternion::fromAxes( const Vector &from, const Vector &to ) {
    const Vector crossProductValue = crossProduct( from, to );
    const float dotProductValue = dotProduct( from, to );
    return Quaternion(
        crossProductValue.x,
        crossProductValue.y,
        crossProductValue.z,
        sqrt(from.getLengthSquared() * to.getLengthSquared()) + dotProductValue
    ).getNormalized();
}

inline Quaternion Quaternion::slerp(
    const Quaternion &first, const Quaternion &second, float position )
{
    if( position <= 0 )
        return first;
    if( position >= 1 )
        return second;

    const float cosine =
        first.x * second.x +
        first.y * second.y +
        first.z * second.z +
        first.w * second.w;

    float firstScale, secondScale;
    if( 1 - fabs(cosine) > 1e-6f ) {
        const float angle = acos( cosine );
        const float sine = sin( angle );
        firstScale = sin( (1 - position) * angle ) / sine;
        secondScale = sin( position * angle ) / sine;
    } else {
        firstScale = 1 - position;
        secondScale = position;
    }

    if( cosine < 0 )
        return first * firstScale - second * secondScale;
    else
        return first * firstScale + second * secondScale;
}

inline Quaternion operator * (
    float multiplier, const Quaternion &quaternion )
{
    return quaternion * multiplier;
}

}
<commit_msg>Fixed incorrect behaviour of the 'Quaternion::fromAxes' method when input vectors are collinear<commit_after>#pragma once

#include <cmath>

namespace storm {

inline Quaternion::Quaternion( float x, float y, float z, float w ) :
    x( x ), y( y ), z( z ), w( w )
{
}

inline Quaternion& Quaternion::operator += ( const Quaternion &other ) {
    x += other.x;
    y += other.y;
    z += other.z;
    w += other.w;
    return *this;
}

inline Quaternion& Quaternion::operator -= ( const Quaternion &other ) {
    x -= other.x;
    y -= other.y;
    z -= other.z;
    w -= other.w;
    return *this;
}

inline Quaternion& Quaternion::operator *= ( const Quaternion &other ) {
    *this = *this * other;
    return *this;
}

inline Quaternion& Quaternion::operator *= ( float multiplier ) {
    x *= multiplier;
    y *= multiplier;
    z *= multiplier;
    w *= multiplier;
    return *this;
}

inline Quaternion& Quaternion::operator /= ( float divisor ) {
    const float multiplier = 1 / divisor;
    x *= multiplier;
    y *= multiplier;
    z *= multiplier;
    w *= multiplier;
    return *this;
}

inline Quaternion Quaternion::operator + ( const Quaternion &other ) const {
    return Quaternion(
        x + other.x, y + other.y, z + other.z, w + other.w );
}

inline Quaternion Quaternion::operator - ( const Quaternion &other ) const {
    return Quaternion(
        x - other.x, y - other.y, z - other.z, w - other.w );
}

inline Quaternion Quaternion::operator * ( const Quaternion &other ) const {
    const Vector first( x, y, z );
    const Vector second( other.x, other.y, other.z );

    const Vector result = crossProduct( first, second ) +
        second * w + first * other.w;

    return Quaternion(
        result.x,
        result.y,
        result.z,
        w * other.w - dotProduct(first, second) );
}

inline Quaternion Quaternion::operator * ( float multiplier ) const {
    return Quaternion(
        x * multiplier, y * multiplier, z * multiplier, w * multiplier );
}

inline Quaternion Quaternion::operator / ( float divisor ) const {
    const float multiplier = 1 / divisor;
    return Quaternion(
        x * multiplier, y * multiplier, z * multiplier, w * multiplier );
}

inline float Quaternion::getLength() const {
    return sqrt( x * x + y * y + z * z + w * w );
}

inline void Quaternion::normalize() {
    *this /= getLength();
}

inline Quaternion Quaternion::getNormalized() const {
    Quaternion result( *this );
    result.normalize();
    return result;
}

inline Quaternion Quaternion::getConjugate() const {
    return Quaternion( -x, -y, -z, w );
}

inline Matrix Quaternion::toRotationMatrix() const {
    const float squaredLength = x * x + y * y + z * z + w * w;
    const float scale = squaredLength ? 2 / squaredLength : 0;

    const float x_ = x * scale;
    const float y_ = y * scale;
    const float z_ = z * scale;

    const float wx = w * x_;
    const float wy = w * y_;
    const float wz = w * z_;

    const float xx = x * x_;
    const float xy = x * y_;
    const float xz = x * z_;

    const float yy = y * y_;
    const float yz = y * z_;

    const float zz = z * z_;

    return storm::Matrix(
        1 - (yy + zz), xy + wz, xz - wy, 0,
        xy - wz, 1 - (xx + zz), yz + wx, 0,
        xz + wy, yz - wx, 1 - (xx + yy), 0,
        0, 0, 0, 1
    );
}

inline Quaternion Quaternion::fromAxisAngle(
    const Vector &axis, float angle )
{
    const float sine = sin( angle / 2 );
    return Quaternion(
        axis.x * sine,
        axis.y * sine,
        axis.z * sine,
        cos(angle / 2) );
}

inline Quaternion Quaternion::fromAxes( const Vector &from, const Vector &to ) {
    const Vector crossProductValue = crossProduct( from, to );
    const float dotProductValue = dotProduct( from, to );

    if( dotProductValue < 0 && crossProductValue.getLengthSquared() < 1e-20 ) {
        return Quaternion( 1, 0, 0, 0 );
    }

    return Quaternion(
        crossProductValue.x,
        crossProductValue.y,
        crossProductValue.z,
        sqrt(from.getLengthSquared() * to.getLengthSquared()) + dotProductValue
    ).getNormalized();
}

inline Quaternion Quaternion::slerp(
    const Quaternion &first, const Quaternion &second, float position )
{
    if( position <= 0 )
        return first;
    if( position >= 1 )
        return second;

    const float cosine =
        first.x * second.x +
        first.y * second.y +
        first.z * second.z +
        first.w * second.w;

    float firstScale, secondScale;
    if( 1 - fabs(cosine) > 1e-6f ) {
        const float angle = acos( cosine );
        const float sine = sin( angle );
        firstScale = sin( (1 - position) * angle ) / sine;
        secondScale = sin( position * angle ) / sine;
    } else {
        firstScale = 1 - position;
        secondScale = position;
    }

    if( cosine < 0 )
        return first * firstScale - second * secondScale;
    else
        return first * firstScale + second * secondScale;
}

inline Quaternion operator * (
    float multiplier, const Quaternion &quaternion )
{
    return quaternion * multiplier;
}

}
<|endoftext|>


<commit_before>#include "twister.h"

const unsigned CYCLE = 0x100;

const unsigned C_TRANS_ = 0xff;
int block_units[][0x10] = {
	0x74, 0x63, 0x69, 0x67, 0x72, 0x68, 0x6e, 0x6c, 0x61, 0x67, 0x74, 0x6c, 0x69, 0x73, 0x61, 0x61, 0x6f, 0x6d, 0x6f, 0x72, 0x6e, 0x72, 0x69, 0x6d, 0x6e, 0x6e, 0x65, 0x74, 0x72, 0x6e, 0x6b, 0x73, 0x61, 0x6f, 0x65, 0x69, 0x73, 0x64, 0x6c, 0x65, 0x69, 0x6b, 0x68, 0x68, 0x68, 0x65, 0x72, 0x64, 0x66, 0x74, 0x61, 0x73, 0x6f, 0x69, 0x65, 0x74, 0x69, 0x68, 0x6e, 0x65, 0x62, 0x74, 0x6b, 0x65
  };
int triad_units[][0x03] = {
	0x74, 0x68, 0x65, 0x74, 0x68, 0x61, 0x65, 0x74, 0x68, 0x66, 0x6f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x65, 0x68, 0x61, 0x74, 0x68, 0x69, 0x73
};
const int transition_seq[] = { 0xce, 0xab, 0xdf, 0xcf, 0xee,
                               0xcf, 0xad, 0xdf, 0xff, 0xce,
                               0x32, 0x40, 0xd3, 0x27, 0x82,
                               0xda, 0xee, 0xff, 0xfc, 0xbf,
                               0x1c, 0x90, 0x13, 0x4a, 0xa5,
                               0xe0, 0x21, 0x9f, 0xe1, 0xc6,
                               0xe4, 0x38, 0x1f, 0x60, 0x24,
                               0x0c, 0x35, 0x51, 0x32, 0xcf,
                               0x12, 0x9a, 0x30, 0x44, 0x72,
                               0xf2, 0xca, 0xa2, 0x51, 0xc6,
                               0xcb, 0xbd, 0xba, 0xac, 0xdf,
                               0xdf, 0xde, 0xcd, 0xfd, 0xca };

unsigned char base(unsigned char a, unsigned char (*s)(unsigned char), int pos)
{
	return (*s)(pos)^a;
}

void transHomExt(vector<unsigned char>& data, unsigned char (*f)(unsigned char), unsigned char (*g)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d)^base(d, g, d);
    }
    data[i] = d;
  }
}
void transHom(vector<unsigned char>& data, unsigned char (*f)(unsigned char), unsigned char (*g)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d)^(*g)(d);
    }
    data[i] = d;
  }
}

void trans(vector<unsigned char>& data, unsigned char (*f)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d);
    }
    data[i] = d;
  }
}

vector<double> f_dist(vector<unsigned char>& in)
{
  vector<double> fdist;
  fdist.resize(256);
  for(unsigned i = 0; i<in.size(); i++)
  {
    fdist[in[i]]++;
  }

  for(unsigned i=0; i<fdist.size(); i++)
  {
    fdist[i] = (fdist[i] / in.size()) * 100;
  }

  return fdist;
}

double s_entropy(vector<double> v)
{
  double entropy = 0;
  double p;

  for(unsigned i = 0; i < v.size(); i++)
  {
    p = v[i] / 100;
    if (p == 0) continue;
    entropy += p * std::log(p) / std::log(2);
  }
  return -entropy;
}
void rms(const string& s, string& r)
{
  for(unsigned int i=0; i<s.size(); i++)
  {
    if(::isspace(s[i])) continue;
    r+= s[i];
  }
}

double sw(double weight, int i, int j, int (*inv)(int, int))
{
  return weight*(*inv)(i, j);
}
void hPerm(int s, int n, void (*p)(int), void (*inv)(int, int))
{
  if(s == 1)
  {
    (*p)(n);
    return;
  }
  for(int i=0; i< s; i++)
  {
    hPerm(s-1, n, p, inv);
    if(s%2 == 1)
      (*inv)(0, s-1);
    else
      (*inv)(i, s-1);
  }
}

double ic(const string& t)
{
  string text; rms(t, text);
  vector<double> freq(256,0);
  for(unsigned int i=0; i<text.size(); i++)
  {
    if(text[i] == ' ') continue;
    freq[text[i]] ++;
  }
  double sum=0;
  for(unsigned int i=0; i<freq.size(); i++)
  {
    if(freq[i] != 0)
    {
      double c = freq[i];
      if(c != 0)
        sum += c * (c - 1);
    }
  }
  double ic = 26 * sum / (text.size() * (text.size() - 1));
  return ic;
}
<commit_msg>xor stream test<commit_after>#include "twister.h"

const unsigned CYCLE = 0x100;

const unsigned C_TRANS_ = 0xff;
int block_units[][0x10] = {
	0x74, 0x63, 0x69, 0x67, 0x72, 0x68, 0x6e, 0x6c, 0x61, 0x67, 0x74, 0x6c, 0x69, 0x73, 0x61, 0x61, 0x6f, 0x6d, 0x6f, 0x72, 0x6e, 0x72, 0x69, 0x6d, 0x6e, 0x6e, 0x65, 0x74, 0x72, 0x6e, 0x6b, 0x73, 0x61, 0x6f, 0x65, 0x69, 0x73, 0x64, 0x6c, 0x65, 0x69, 0x6b, 0x68, 0x68, 0x68, 0x65, 0x72, 0x64, 0x66, 0x74, 0x61, 0x73, 0x6f, 0x69, 0x65, 0x74, 0x69, 0x68, 0x6e, 0x65, 0x62, 0x74, 0x6b, 0x65
  };
int triad_units[][0x03] = {
	0x74, 0x68, 0x65, 0x74, 0x68, 0x61, 0x65, 0x74, 0x68, 0x66, 0x6f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x65, 0x68, 0x61, 0x74, 0x68, 0x69, 0x73
};
const int transition_seq[] = { 0xce, 0xab, 0xdf, 0xcf, 0xee,
                               0xcf, 0xad, 0xdf, 0xff, 0xce,
                               0x32, 0x40, 0xd3, 0x27, 0x82,
                               0xda, 0xee, 0xff, 0xfc, 0xbf,
                               0x1c, 0x90, 0x13, 0x4a, 0xa5,
                               0xe0, 0x21, 0x9f, 0xe1, 0xc6,
                               0xe4, 0x38, 0x1f, 0x60, 0x24,
                               0x0c, 0x35, 0x51, 0x32, 0xcf,
                               0x12, 0x9a, 0x30, 0x44, 0x72,
                               0x04, 0x1c, 0x52, 0xca, 0xdf,
                               0xf2, 0xca, 0xa2, 0x51, 0xc6,
                               0xcb, 0xbd, 0xba, 0xac, 0xdf,
                               0xdf, 0xde, 0xcd, 0xfd, 0xca };

unsigned char base(unsigned char a, unsigned char (*s)(unsigned char), int pos)
{
	return (*s)(pos)^a;
}

void transHomExt(vector<unsigned char>& data, unsigned char (*f)(unsigned char), unsigned char (*g)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d)^base(d, g, d);
    }
    data[i] = d;
  }
}
void transHom(vector<unsigned char>& data, unsigned char (*f)(unsigned char), unsigned char (*g)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d)^(*g)(d);
    }
    data[i] = d;
  }
}

void trans(vector<unsigned char>& data, unsigned char (*f)(unsigned char))
{
  for(unsigned i = 0; i<data.size(); i++)
  {
    unsigned char d = data[i];
    for(unsigned j=0; j<CYCLE; j++)
    {
      d = (*f)(d);
    }
    data[i] = d;
  }
}

vector<double> f_dist(vector<unsigned char>& in)
{
  vector<double> fdist;
  fdist.resize(256);
  for(unsigned i = 0; i<in.size(); i++)
  {
    fdist[in[i]]++;
  }

  for(unsigned i=0; i<fdist.size(); i++)
  {
    fdist[i] = (fdist[i] / in.size()) * 100;
  }

  return fdist;
}

double s_entropy(vector<double> v)
{
  double entropy = 0;
  double p;

  for(unsigned i = 0; i < v.size(); i++)
  {
    p = v[i] / 100;
    if (p == 0) continue;
    entropy += p * std::log(p) / std::log(2);
  }
  return -entropy;
}
void rms(const string& s, string& r)
{
  for(unsigned int i=0; i<s.size(); i++)
  {
    if(::isspace(s[i])) continue;
    r+= s[i];
  }
}

double sw(double weight, int i, int j, int (*inv)(int, int))
{
  return weight*(*inv)(i, j);
}
void hPerm(int s, int n, void (*p)(int), void (*inv)(int, int))
{
  if(s == 1)
  {
    (*p)(n);
    return;
  }
  for(int i=0; i< s; i++)
  {
    hPerm(s-1, n, p, inv);
    if(s%2 == 1)
      (*inv)(0, s-1);
    else
      (*inv)(i, s-1);
  }
}

double ic(const string& t)
{
  string text; rms(t, text);
  vector<double> freq(256,0);
  for(unsigned int i=0; i<text.size(); i++)
  {
    if(text[i] == ' ') continue;
    freq[text[i]] ++;
  }
  double sum=0;
  for(unsigned int i=0; i<freq.size(); i++)
  {
    if(freq[i] != 0)
    {
      double c = freq[i];
      if(c != 0)
        sum += c * (c - 1);
    }
  }
  double ic = 26 * sum / (text.size() * (text.size() - 1));
  return ic;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <iostream>
#define  MAXSTRLEN  255                   // 用户可在255以内定义最大串长
typedef unsigned char SString[MAXSTRLEN+1];	// 0号单元存放串的长度

void get_next(SString T,int next[]){

	int i=1,j;
	next[1]=0;
	j=0;
	while(i<T[0]){

		if(j == 0 || T[i]==T[j]){
			++i;
			++j;

			if(T[i]!=T[j]){
				next[i]=j;
			}else{

				next[i]=next[j];
			}
		}

		else
			j=next[j];
	}
}
int  main(){
	int next[MAXSTRLEN]={0};
	SString S;
	int n,i,j;
	char ch;
	scanf("%d",&n);    // 指定要验证NEXT值的字符串个数
	ch=getchar();
	for(i=1;i<=n;i++)
	{
		ch=getchar();
		for(j=1;j<=MAXSTRLEN&&(ch!='\n');j++)    // 录入字符串
		{
			S[j]=ch;
			ch=getchar();
		}
		S[0]=j-1;
		S[j]=0;   // S[0]用于存储字符串中字符个数
		get_next(S,next);
		printf("NEXT J is:");
		for(j=1;j<=S[0];j++)
			printf("%d",next[j]);
		printf("\n");
	}
}

<commit_msg>update uoj8591<commit_after>#include <cstdio>
#include <cstdlib>
#include <iostream>
#define  MAXSTRLEN  255                   // 用户可在255以内定义最大串长
typedef unsigned char SString[MAXSTRLEN+1];	// 0号单元存放串的长度

void get_next(SString T,int next[]){

	int i=1,j;
	next[1]=0;
	j=0;
	while(i<T[0]){

		if(j == 0 || T[i]==T[j]){
			++i;
			++j;

			//if(T[i]!=T[j]){
				next[i]=j;
			//}else{

			//	next[i]=next[j];
			//}
		}

		else
			j=next[j];
	}
}
int  main(){
	int next[MAXSTRLEN]={0};
	SString S;
	int n,i,j;
	char ch;
	scanf("%d",&n);    // 指定要验证NEXT值的字符串个数
	ch=getchar();
	for(i=1;i<=n;i++)
	{
		ch=getchar();
		for(j=1;j<=MAXSTRLEN&&(ch!='\n');j++)    // 录入字符串
		{
			S[j]=ch;
			ch=getchar();
		}
		S[0]=j-1;
		S[j]=0;   // S[0]用于存储字符串中字符个数
		get_next(S,next);
		printf("NEXT J is:");
		for(j=1;j<=S[0];j++)
			printf("%d",next[j]);
		printf("\n");
	}
}

<|endoftext|>


<commit_before>#include "state.h"
#include "ui.h"

// Default state draw operation just draws the ui.
void State::draw() {
	uiManager.draw();
}
<commit_msg>Added empty defs for callback methods<commit_after>#include "state.h"
#include "ui.h"

// Default state draw operation just draws the ui.
void State::draw() {
	uiManager.draw();
}

// Override to provide behavior.
void State::enter() { }
void State::pause() { }
void State::exit() { }
<|endoftext|>


<commit_before>/**
 * This is the main entry point in the SparkFun Autonomous Vehicle Competition (AVC)
 * for the 2015 robot.
 */

#include "CommandSequence.h"
#include "Timon.h"
#include "UserLeds.h"

#include <BlackGPIO.h>

#include <cmath>
#include <iostream>

#include <signal.h>

using namespace avc;
using namespace std;

namespace {
  // Flag will be set when user terminates via ^C or uses kill on process
  bool hasBeenInterrupted = false;

  void interrupted(int sig) {
    hasBeenInterrupted = true;
  }
}

//
// Main entry point into the code basically waits for user
// to press button on BBB then runs the autonomous code
//
int main(int argc, const char** argv) {
  signal(SIGINT, interrupted);
  signal(SIGTERM, interrupted);
  UserLeds& leds = UserLeds::getInstance();
  int waitCnt = 0;

  // Create instance of vehicle
  Timon timon;

  // Start button connected to P9 18 (GPIO_4)
  BlackLib::BlackGPIO longButton(BlackLib::GPIO_4, BlackLib::input);
  // Extra mode start button connected to P9 24 (GPIO_15)
  BlackLib::BlackGPIO shortButton(BlackLib::GPIO_15, BlackLib::input);

  bool longWasHigh = longButton.isHigh();
  bool shortWasHigh = shortButton.isHigh();

  cout << "Entering main loop - waiting for trigger ...\n";

  while (hasBeenInterrupted == false) {

    bool shortIsHigh = shortButton.isHigh();
    bool longIsHigh = longButton.isHigh();

    // Run auton when button is pressed and then released
    if ((longWasHigh == true) && (longIsHigh == false)) {

      leds.setState(0xf);
      cout << "Starting auton for long path around track\n";
      timon.setAutonLongWay();

      Timer autonTimer;
      Command::run(timon);

      cout << "Long path auton completed in " << autonTimer.secsElapsed() << " seconds\n";
      timon.disable();

    } else if ((shortWasHigh == true) && (shortIsHigh == false)) {

      leds.setState(0xf);
      cout << "Starting auton for short path around track\n";
      timon.setAutonShortWay();

      Timer autonTimer;
      Command::run(timon);

      cout << "Short path auton completed in " << autonTimer.secsElapsed() << " seconds\n";
      timon.disable();

    } else {
      Timer::sleep(0.05);
      int ledState = waitCnt & 0xf;
      leds.setState(ledState);
      if (ledState == 0) {
	waitCnt = 1;
      } else {
	waitCnt <<= 1;
      }
    }
    // Save prior state
    longWasHigh = longIsHigh;
    shortWasHigh = shortIsHigh;
  }

  cout << "Terminated by external signal\n";

  return 0;
}

//
// Implementation of the Timon class methods
//

Timon::Timon() :
  CommandParallel("Timon", true),
#if USE_SERVOS
  _left(LEFT_PWM, -1.0, +1.0),
  _right(RIGHT_PWM, -1.0, +1.0),
#else
  _left(LEFT_PWM, LEFT_GPIO_FWD, LEFT_GPIO_REV),
  _right(RIGHT_PWM, RIGHT_GPIO_FWD, RIGHT_GPIO_REV),
#endif
  _gyro(),
  _initHeading(0),
  _heading(0),
  _wayPoint(1),
  _crashed(false),
  _done(false)
{
  if (!_gyro.reset()) {
    cerr << "**ERROR*** Failed to reset gyro\n";
    _crashed = true;
  }

}

void Timon::setAutonLongWay() {
  clear();

  CommandSequence* drive = new CommandSequence("Drive");
  // Give .25 seconds to let user move hand away
  drive->add(new DrivePowerTime(*this, 0, 0, 0.25));
  // Short drive to first corner
  drive->add(new DriveToTurn(*this, 0.3, 2.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Long drive to second corner
  drive->add(new DriveToTurn(*this, 0.2, 5.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Medium drive to third corner
  drive->add(new DriveToTurn(*this, 0.2, 4.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Long drive to fourth corner
  drive->add(new DriveToTurn(*this, 0.2, 5.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Short drive to finish line
  drive->add(new DriveToTurn(*this, 0.2, 2.0));
  // And stop (NOTE: this is optional now as the Timon class should
  // automatically disable everything after finishing an auton run)
  drive->add(DrivePowerTime::createStopCommand(*this));
  add(drive);
}

void Timon::setAutonShortWay() {
  clear();

  CommandSequence* drive = new CommandSequence("Drive");
  // Give .25 seconds to let user move hand away
  drive->add(new DrivePowerTime(*this, 0.2, 0, 1.0));

  // Uncomment to spin left side forward one second followed
  // by right side forward for a second to verify logic is right
  //drive->add(new DrivePowerTime(*this, 0.2, 0, 1.0));
  //drive->add(new DrivePowerTime(*this, 0, .2, 1.0));

  // Make a left hand turn
  drive->add(new MakeTurn(*this, -90.0));

  add(drive);
}

Timon::~Timon() {
  _left.set(0);
  _right.set(0);
  _left.disable();
  _right.disable();
}

void Timon::doInitialize() {
  _crashed = _done = false;
  _wayPoint = 1;

  if (!_gyro.getHeading(_initHeading)) {
    _crashed = true;
    cerr << "***ERROR*** Gyro not responding (unable to read heading)\n";
  }

  CommandParallel::doInitialize();
}

void Timon::readSensors() {
  float heading;
  if (_gyro.getHeading(heading)) {
    heading -= _initHeading;
    if (heading < 0) {
      heading += 360.0;
    }
    _heading = heading;
  } else {
    _crashed = true;
    cerr << "***ERROR*** Gyro not responding (unable to read heading)\n";
  }
}

float Timon::getRelativeHeading(float initHeading) const {
  float relHeading = _heading - initHeading;
  // Put in range of [0, 360]
  if (relHeading < 0) {
    relHeading += 360;
  }
  // Now adjust to range of [-180.0, +180.0]
  if (relHeading > 180) {
    relHeading -= 360;
  }
  return relHeading;
}

Command::State Timon::doExecute() {
  readSensors();
  if (hasCrashed()) {
    // Make sure motors are turned off
    coast();
    // Catastrophic failure!
    return Command::INTERRUPTED;
  }

  return CommandParallel::doExecute();
}

void Timon::doEnd(Command::State reason) {
  CommandParallel::doEnd(reason);
  disable();
}

void Timon::disable() {
  coast();
}

void Timon::nextWaypoint() {
  UserLeds& leds = UserLeds::getInstance();
  leds.setState(_wayPoint++);
}

float Timon::rangeCheckPower(float power) {
  return max(-1.0f, min(+1.0f, power));
}

ostream& Timon::print(std::ostream& out, const Command& cmd) const {
  out << cmd << "  Timon(left=" << _left.get() << ", right="
      << _right.get() << ", heading=" << _heading << ")";
  return out;
}

//
// Implementation of the DriveToTurn class methods
//

DriveToTurn::DriveToTurn(Timon& car, float power, float timeout) :
  Command("DriveToTurn", timeout),
  _car(car),
  _power(power),
  _initialHeading(0)
{
}

void DriveToTurn::doInitialize() {
  _initialHeading = _car.getHeading();
  _car.print(cout, *this) << "\n";
}

Command::State DriveToTurn::doExecute() {
  float turned = _car.getRelativeHeading(_initialHeading);
  float turnedMag = abs(turned);

  float powerCorrect = 0;
  if (turnedMag > 1.0) {
    // TODO: Figure out a power correction (basically P of PID) based
    // on how far turn is off
    powerCorrect = turnedMag / 180 + 0.005;
    powerCorrect = (turned > 0) ? powerCorrect : -powerCorrect;
    cout << "Off course: " << turned << " degrees, power correct: "
	 << powerCorrect << "\n";
  }

  float powerLeft = _power - powerCorrect;
  float powerRight = _power + powerCorrect;

  // Seek new drive power levels with power correction for steering
  powerLeft = Timon::rangeCheckPower(powerLeft);
  powerRight = Timon::rangeCheckPower(powerRight);
  _car.seekDrive(powerLeft, powerRight);

  bool foundCorner = _car.detectedCorner();
  // TODO: Remove this time out override once we can detect the corner
  foundCorner = ((getElapsedTime() / getTimeout()) >= 0.5);
  _car.print(cout, *this) << "\n";
  return (foundCorner ? Command::NORMAL_END : Command::STILL_RUNNING);
}

void DriveToTurn::doEnd(Command::State reason) {
  _car.print(cout, *this) << "\n";
  _car.nextWaypoint();
}

//
// Implementation of the MakeTurn class methods
//

MakeTurn::MakeTurn(Timon& car, float turn) :
  Command("MakeTurn", 1.0 + abs(turn) / 25),
  _car(car),
  _turn(turn),
  _initialHeading(0),
  _lastErr(0),
  _inRangeCnt(0)
{
}

MakeTurn::~MakeTurn() {
}

void MakeTurn::doInitialize() {
  _car.print(cout, *this) << "\n";
  _initialHeading = _car.getHeading();
  _lastErr = _turn;
  _inRangeCnt = 0;
}

Command::State MakeTurn::doExecute() {
  float carTurned = _car.getRelativeHeading(_initialHeading);
  float err = _turn - carTurned;
  float deltaErr = _lastErr - err;
  const float P = (0.15f * 10.0f / 360.0f);
  const float D = (0.1f * 10.0f / 360.0f);

  // TODO: Delete once we figure out how to get angle (the
  // statement below makes
  //float percentTimeElapsed = getElapsedTime() / getTimeout();
  //err = (percentTimeElapsed >= 0.5) ? 0.0 : (1.1 - percentTimeElapsed) * _turn;

  float steer = err * P + deltaErr * D;
  float steerMag = abs(steer);
  const float minMag = 0.2f;
  if (steerMag < minMag) {
    steer = (steer < 0) ? -minMag : minMag;
  }

  // Limit to .35 power level
  const float maxMag = 0.35f;
  steer = min(maxMag, max(-maxMag, steer));

  steer = Timon::rangeCheckPower(steer);
  _car.drive(steer, -steer);

  // TODO: NOTE, this implementation does not take into account a minimum
  // power to turn the car (for example, if we get within 10 degrees and
  // drop the power too low, the car may stop turning and never reach
  // the final target).

  _car.print(cout, *this) << "  turned: " << carTurned << "  err: " << err << "\n";

  _lastErr = err;

  // Done if within 3 degrees
  if (abs(err) < 3.0) {
    _inRangeCnt++;
  } else {
    _inRangeCnt = 0;
  }
  return ((_inRangeCnt >= 3) ? Command::NORMAL_END : Command::STILL_RUNNING);
}

void MakeTurn::doEnd(Command::State reason) {
  _car.print(cout, *this) << "\n";
}

//
// Implementation of the DrivePowerTime class methods
//

DrivePowerTime::DrivePowerTime(Timon& car, float powerLeft, float powerRight,
			       float howLong) :
  Command("DrivePowerTime", howLong + 1.0),
  _car(car),
  _powerLeft(powerLeft),
  _powerRight(powerRight),
  _runTime(howLong)
{
}

DrivePowerTime::~DrivePowerTime() {
}

Command::State DrivePowerTime::doExecute() {
  if (getElapsedTime() >= _runTime) {
    return Command::NORMAL_END;
  }

  _car.seekDrive(_powerLeft, _powerRight);
  return Command::STILL_RUNNING;
}

void DrivePowerTime::doEnd(Command::State reason) {
  // If command was to bring car to a stop and the
  if (reason == Command::NORMAL_END) {
    if (_powerLeft == 0 && _powerRight == 0) {
      _car.drive(0, 0);
    }
  }
}
<commit_msg>Reduced straight drive time for test run.<commit_after>/**
 * This is the main entry point in the SparkFun Autonomous Vehicle Competition (AVC)
 * for the 2015 robot.
 */

#include "CommandSequence.h"
#include "Timon.h"
#include "UserLeds.h"

#include <BlackGPIO.h>

#include <cmath>
#include <iostream>

#include <signal.h>

using namespace avc;
using namespace std;

namespace {
  // Flag will be set when user terminates via ^C or uses kill on process
  bool hasBeenInterrupted = false;

  void interrupted(int sig) {
    hasBeenInterrupted = true;
  }
}

//
// Main entry point into the code basically waits for user
// to press button on BBB then runs the autonomous code
//
int main(int argc, const char** argv) {
  signal(SIGINT, interrupted);
  signal(SIGTERM, interrupted);
  UserLeds& leds = UserLeds::getInstance();
  int waitCnt = 0;

  // Create instance of vehicle
  Timon timon;

  // Start button connected to P9 18 (GPIO_4)
  BlackLib::BlackGPIO longButton(BlackLib::GPIO_4, BlackLib::input);
  // Extra mode start button connected to P9 24 (GPIO_15)
  BlackLib::BlackGPIO shortButton(BlackLib::GPIO_15, BlackLib::input);

  bool longWasHigh = longButton.isHigh();
  bool shortWasHigh = shortButton.isHigh();

  cout << "Entering main loop - waiting for trigger ...\n";

  while (hasBeenInterrupted == false) {

    bool shortIsHigh = shortButton.isHigh();
    bool longIsHigh = longButton.isHigh();

    // Run auton when button is pressed and then released
    if ((longWasHigh == true) && (longIsHigh == false)) {

      leds.setState(0xf);
      cout << "Starting auton for long path around track\n";
      timon.setAutonLongWay();

      Timer autonTimer;
      Command::run(timon);

      cout << "Long path auton completed in " << autonTimer.secsElapsed() << " seconds\n";
      timon.disable();

    } else if ((shortWasHigh == true) && (shortIsHigh == false)) {

      leds.setState(0xf);
      cout << "Starting auton for short path around track\n";
      timon.setAutonShortWay();

      Timer autonTimer;
      Command::run(timon);

      cout << "Short path auton completed in " << autonTimer.secsElapsed() << " seconds\n";
      timon.disable();

    } else {
      Timer::sleep(0.05);
      int ledState = waitCnt & 0xf;
      leds.setState(ledState);
      if (ledState == 0) {
	waitCnt = 1;
      } else {
	waitCnt <<= 1;
      }
    }
    // Save prior state
    longWasHigh = longIsHigh;
    shortWasHigh = shortIsHigh;
  }

  cout << "Terminated by external signal\n";

  return 0;
}

//
// Implementation of the Timon class methods
//

Timon::Timon() :
  CommandParallel("Timon", true),
#if USE_SERVOS
  _left(LEFT_PWM, -1.0, +1.0),
  _right(RIGHT_PWM, -1.0, +1.0),
#else
  _left(LEFT_PWM, LEFT_GPIO_FWD, LEFT_GPIO_REV),
  _right(RIGHT_PWM, RIGHT_GPIO_FWD, RIGHT_GPIO_REV),
#endif
  _gyro(),
  _initHeading(0),
  _heading(0),
  _wayPoint(1),
  _crashed(false),
  _done(false)
{
  if (!_gyro.reset()) {
    cerr << "**ERROR*** Failed to reset gyro\n";
    _crashed = true;
  }

}

void Timon::setAutonLongWay() {
  clear();
  const float drivePow = 0.2;

  CommandSequence* drive = new CommandSequence("Drive");
  // Give .25 seconds to let user move hand away
  drive->add(new DrivePowerTime(*this, 0, 0, 0.25));
  // Short drive to first corner
  drive->add(new DriveToTurn(*this, drivePow, 1.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Long drive to second corner
  drive->add(new DriveToTurn(*this, drivePow, 3.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Medium drive to third corner
  drive->add(new DriveToTurn(*this, drivePow, 2.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Long drive to fourth corner
  drive->add(new DriveToTurn(*this, drivePow, 3.0));
  // Give 1/2 second to slow down
  drive->add(new DrivePowerTime(*this, 0, 0, 0.5));
  // Make a right hand turn
  drive->add(new MakeTurn(*this, 90.0));
  // Short drive to finish line
  drive->add(new DriveToTurn(*this, drivePow, 1.0));
  // And stop (NOTE: this is optional now as the Timon class should
  // automatically disable everything after finishing an auton run)
  drive->add(DrivePowerTime::createStopCommand(*this));
  add(drive);
}

void Timon::setAutonShortWay() {
  clear();

  CommandSequence* drive = new CommandSequence("Drive");
  // Give .25 seconds to let user move hand away
  drive->add(new DrivePowerTime(*this, 0, 0, 0.25));

  // Uncomment to spin left side forward one second followed
  // by right side forward for a second to verify logic is right
  //drive->add(new DrivePowerTime(*this, 0.2, 0, 1.0));
  //drive->add(new DrivePowerTime(*this, 0, .2, 1.0));

  // Make a left hand turn
  drive->add(new MakeTurn(*this, -90.0));

  add(drive);
}

Timon::~Timon() {
  _left.set(0);
  _right.set(0);
  _left.disable();
  _right.disable();
}

void Timon::doInitialize() {
  _crashed = _done = false;
  _wayPoint = 1;

  if (!_gyro.getHeading(_initHeading)) {
    _crashed = true;
    cerr << "***ERROR*** Gyro not responding (unable to read heading)\n";
  }

  CommandParallel::doInitialize();
}

void Timon::readSensors() {
  float heading;
  if (_gyro.getHeading(heading)) {
    heading -= _initHeading;
    if (heading < 0) {
      heading += 360.0;
    }
    _heading = heading;
  } else {
    _crashed = true;
    cerr << "***ERROR*** Gyro not responding (unable to read heading)\n";
  }
}

float Timon::getRelativeHeading(float initHeading) const {
  float relHeading = _heading - initHeading;
  // Put in range of [0, 360]
  if (relHeading < 0) {
    relHeading += 360;
  }
  // Now adjust to range of [-180.0, +180.0]
  if (relHeading > 180) {
    relHeading -= 360;
  }
  return relHeading;
}

Command::State Timon::doExecute() {
  readSensors();
  if (hasCrashed()) {
    // Make sure motors are turned off
    coast();
    // Catastrophic failure!
    return Command::INTERRUPTED;
  }

  return CommandParallel::doExecute();
}

void Timon::doEnd(Command::State reason) {
  CommandParallel::doEnd(reason);
  disable();
}

void Timon::disable() {
  coast();
}

void Timon::nextWaypoint() {
  UserLeds& leds = UserLeds::getInstance();
  leds.setState(_wayPoint++);
}

float Timon::rangeCheckPower(float power) {
  return max(-1.0f, min(+1.0f, power));
}

ostream& Timon::print(std::ostream& out, const Command& cmd) const {
  out << cmd << "  Timon(left=" << _left.get() << ", right="
      << _right.get() << ", heading=" << _heading << ")";
  return out;
}

//
// Implementation of the DriveToTurn class methods
//

DriveToTurn::DriveToTurn(Timon& car, float power, float timeout) :
  Command("DriveToTurn", timeout),
  _car(car),
  _power(power),
  _initialHeading(0)
{
}

void DriveToTurn::doInitialize() {
  _initialHeading = _car.getHeading();
  _car.print(cout, *this) << "\n";
}

Command::State DriveToTurn::doExecute() {
  float turned = _car.getRelativeHeading(_initialHeading);
  float turnedMag = abs(turned);

  float powerCorrect = 0;
  if (turnedMag > 1.0) {
    // TODO: Figure out a power correction (basically P of PID) based
    // on how far turn is off
    powerCorrect = turnedMag / 180 + 0.005;
    powerCorrect = (turned > 0) ? powerCorrect : -powerCorrect;
    cout << "Off course: " << turned << " degrees, power correct: "
	 << powerCorrect << "\n";
  }

  float powerLeft = _power - powerCorrect;
  float powerRight = _power + powerCorrect;

  // Seek new drive power levels with power correction for steering
  powerLeft = Timon::rangeCheckPower(powerLeft);
  powerRight = Timon::rangeCheckPower(powerRight);
  _car.seekDrive(powerLeft, powerRight);

  bool foundCorner = _car.detectedCorner();
  // TODO: Remove this time out override once we can detect the corner
  foundCorner = ((getElapsedTime() / getTimeout()) >= 0.5);
  _car.print(cout, *this) << "\n";
  return (foundCorner ? Command::NORMAL_END : Command::STILL_RUNNING);
}

void DriveToTurn::doEnd(Command::State reason) {
  _car.print(cout, *this) << "\n";
  _car.nextWaypoint();
}

//
// Implementation of the MakeTurn class methods
//

MakeTurn::MakeTurn(Timon& car, float turn) :
  Command("MakeTurn", 1.0 + abs(turn) / 25),
  _car(car),
  _turn(turn),
  _initialHeading(0),
  _lastErr(0),
  _inRangeCnt(0)
{
}

MakeTurn::~MakeTurn() {
}

void MakeTurn::doInitialize() {
  _car.print(cout, *this) << "\n";
  _initialHeading = _car.getHeading();
  _lastErr = _turn;
  _inRangeCnt = 0;
}

Command::State MakeTurn::doExecute() {
  float carTurned = _car.getRelativeHeading(_initialHeading);
  float err = _turn - carTurned;
  float deltaErr = _lastErr - err;
  const float P = (0.15f * 10.0f / 360.0f);
  const float D = (0.1f * 10.0f / 360.0f);

  // TODO: Delete once we figure out how to get angle (the
  // statement below makes
  //float percentTimeElapsed = getElapsedTime() / getTimeout();
  //err = (percentTimeElapsed >= 0.5) ? 0.0 : (1.1 - percentTimeElapsed) * _turn;

  float steer = err * P + deltaErr * D;
  float steerMag = abs(steer);
  const float minMag = 0.2f;
  if (steerMag < minMag) {
    steer = (steer < 0) ? -minMag : minMag;
  }

  // Limit to .35 power level
  const float maxMag = 0.35f;
  steer = min(maxMag, max(-maxMag, steer));

  steer = Timon::rangeCheckPower(steer);
  _car.drive(steer, -steer);

  // TODO: NOTE, this implementation does not take into account a minimum
  // power to turn the car (for example, if we get within 10 degrees and
  // drop the power too low, the car may stop turning and never reach
  // the final target).

  _car.print(cout, *this) << "  turned: " << carTurned << "  err: " << err << "\n";

  _lastErr = err;

  // Done if within 3 degrees
  if (abs(err) < 3.0) {
    _inRangeCnt++;
  } else {
    _inRangeCnt = 0;
  }
  return ((_inRangeCnt >= 3) ? Command::NORMAL_END : Command::STILL_RUNNING);
}

void MakeTurn::doEnd(Command::State reason) {
  _car.print(cout, *this) << "\n";
}

//
// Implementation of the DrivePowerTime class methods
//

DrivePowerTime::DrivePowerTime(Timon& car, float powerLeft, float powerRight,
			       float howLong) :
  Command("DrivePowerTime", howLong + 1.0),
  _car(car),
  _powerLeft(powerLeft),
  _powerRight(powerRight),
  _runTime(howLong)
{
}

DrivePowerTime::~DrivePowerTime() {
}

Command::State DrivePowerTime::doExecute() {
  if (getElapsedTime() >= _runTime) {
    return Command::NORMAL_END;
  }

  _car.seekDrive(_powerLeft, _powerRight);
  return Command::STILL_RUNNING;
}

void DrivePowerTime::doEnd(Command::State reason) {
  // If command was to bring car to a stop and the
  if (reason == Command::NORMAL_END) {
    if (_powerLeft == 0 && _powerRight == 0) {
      _car.drive(0, 0);
    }
  }
}
<|endoftext|>


<commit_before>#pragma once
#include <fmt/core.h>
#include <net/ethernet.h>
#include <netinet/in.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <sdeventplus/clock.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <variant>

namespace phosphor
{
namespace network
{

using namespace std::chrono_literals;

// wait for three seconds before reloading systemd-networkd
constexpr auto reloadTimeout = 3s;

// refresh the objets after four seconds as network
// configuration takes 3-4 sec to reconfigure at most.
constexpr auto refreshTimeout = 4s;

// Byte representations for common address types in network byte order
using InAddrAny = std::variant<in_addr, in6_addr>;

using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;

struct string_hash : public std::hash<std::string_view>
{
    using is_transparent = void;
};
template <typename V>
using string_umap =
    std::unordered_map<std::string, V, string_hash, std::equal_to<>>;
using string_uset =
    std::unordered_set<std::string, string_hash, std::equal_to<>>;

constexpr std::size_t hash_multi() noexcept
{
    return 0;
}

template <typename T, typename... Args>
constexpr std::size_t hash_multi(const T& v, Args... args) noexcept
{
    const std::size_t seed = hash_multi(args...);
    return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

namespace detail
{

template <typename T>
constexpr bool vcontains() noexcept
{
    return false;
}

template <typename T, typename V, typename... Vs>
constexpr bool vcontains() noexcept
{
    return vcontains<T, Vs...>() || std::is_same_v<T, V>;
}

template <typename T, typename... Types>
constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
    veq(T t, std::variant<Types...> v) noexcept
{
    return std::visit(
        [t](auto v) {
            if constexpr (std::is_same_v<T, decltype(v)>)
            {
                return v == t;
            }
            else
            {
                return false;
            }
        },
        v);
}

template <typename T>
struct AddrBufMaker
{
};

template <>
struct AddrBufMaker<ether_addr>
{
  public:
    std::string_view operator()(ether_addr val) noexcept;

  private:
    std::array<char, /*octet*/ 2 * /*octets*/ 6 + /*seps*/ 5> buf;
};

template <>
struct AddrBufMaker<in_addr>
{
  public:
    std::string_view operator()(in_addr val) noexcept;

  private:
    std::array<char, /*octet*/ 3 * /*octets*/ 4 + /*seps*/ 3> buf;
};

template <>
struct AddrBufMaker<in6_addr>
{
  public:
    std::string_view operator()(in6_addr val) noexcept;

  private:
    std::array<char, /*hextet*/ 4 * /*hextets*/ 8 + /*seps*/ 7> buf;
};

template <typename BufMaker>
struct FormatFromBuf
{
  private:
    fmt::formatter<std::string_view> formatter;

  public:
    template <typename ParseContext>
    constexpr auto parse(ParseContext& ctx)
    {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(auto v, FormatContext& ctx) const
    {
        return formatter.format(BufMaker{}(v), ctx);
    }
};
} // namespace detail
} // namespace network
} // namespace phosphor

template <typename... Ts>
struct std::hash<std::tuple<Ts...>>
{
    constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
    {
        return std::apply(phosphor::network::hash_multi<Ts...>, t);
    }
};

template <>
struct std::hash<in_addr>
{
    std::size_t operator()(in_addr addr) const noexcept;
};

template <>
struct std::hash<in6_addr>
{
    std::size_t operator()(in6_addr addr) const noexcept;
};

namespace fmt
{
template <>
struct formatter<ether_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<ether_addr>>
{
};
template <>
struct formatter<in_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<in_addr>>
{
};
template <>
struct formatter<in6_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<in6_addr>>
{
};
template <>
struct formatter<phosphor::network::InAddrAny>
{
  private:
    fmt::formatter<std::string_view> formatter;

  public:
    template <typename ParseContext>
    constexpr auto parse(ParseContext& ctx)
    {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(auto v, FormatContext& ctx) const
    {
        return std::visit(
            [&](auto v) {
                auto abm =
                    phosphor::network::detail::AddrBufMaker<decltype(v)>{};
                return formatter.format(abm(v), ctx);
            },
            v);
    }
};
} // namespace fmt

namespace std
{
string to_string(ether_addr value);
string to_string(in_addr value);
string to_string(in6_addr value);
string to_string(phosphor::network::InAddrAny value);
} // namespace std

constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
{
    return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
                      rhs.ether_addr_octet);
}

constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
{
    return lhs.s_addr == rhs.s_addr;
}

constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
{
    return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
}

template <typename T>
constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
                           bool>
    operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
{
    return phosphor::network::detail::veq(rhs, lhs);
}

auto& operator<<(auto& os, ether_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<ether_addr>{}(v);
}

auto& operator<<(auto& os, in_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<in_addr>{}(v);
}

auto& operator<<(auto& os, in6_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<in6_addr>{}(v);
}

auto& operator<<(auto& os, phosphor::network::InAddrAny v)
{
    return os << std::visit(
               [](auto v) {
                   return phosphor::network::detail::AddrBufMaker<
                       decltype(v)>{}(v);
               },
               v);
}
<commit_msg>types: hash_multi should take const refs<commit_after>#pragma once
#include <fmt/core.h>
#include <net/ethernet.h>
#include <netinet/in.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <sdeventplus/clock.hpp>
#include <sdeventplus/utility/timer.hpp>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <variant>

namespace phosphor
{
namespace network
{

using namespace std::chrono_literals;

// wait for three seconds before reloading systemd-networkd
constexpr auto reloadTimeout = 3s;

// refresh the objets after four seconds as network
// configuration takes 3-4 sec to reconfigure at most.
constexpr auto refreshTimeout = 4s;

// Byte representations for common address types in network byte order
using InAddrAny = std::variant<in_addr, in6_addr>;

using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;

struct string_hash : public std::hash<std::string_view>
{
    using is_transparent = void;
};
template <typename V>
using string_umap =
    std::unordered_map<std::string, V, string_hash, std::equal_to<>>;
using string_uset =
    std::unordered_set<std::string, string_hash, std::equal_to<>>;

constexpr std::size_t hash_multi() noexcept
{
    return 0;
}

template <typename T, typename... Args>
constexpr std::size_t hash_multi(const T& v, const Args&... args) noexcept
{
    const std::size_t seed = hash_multi(args...);
    return seed ^ (std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}

namespace detail
{

template <typename T>
constexpr bool vcontains() noexcept
{
    return false;
}

template <typename T, typename V, typename... Vs>
constexpr bool vcontains() noexcept
{
    return vcontains<T, Vs...>() || std::is_same_v<T, V>;
}

template <typename T, typename... Types>
constexpr std::enable_if_t<vcontains<T, Types...>(), bool>
    veq(T t, std::variant<Types...> v) noexcept
{
    return std::visit(
        [t](auto v) {
            if constexpr (std::is_same_v<T, decltype(v)>)
            {
                return v == t;
            }
            else
            {
                return false;
            }
        },
        v);
}

template <typename T>
struct AddrBufMaker
{
};

template <>
struct AddrBufMaker<ether_addr>
{
  public:
    std::string_view operator()(ether_addr val) noexcept;

  private:
    std::array<char, /*octet*/ 2 * /*octets*/ 6 + /*seps*/ 5> buf;
};

template <>
struct AddrBufMaker<in_addr>
{
  public:
    std::string_view operator()(in_addr val) noexcept;

  private:
    std::array<char, /*octet*/ 3 * /*octets*/ 4 + /*seps*/ 3> buf;
};

template <>
struct AddrBufMaker<in6_addr>
{
  public:
    std::string_view operator()(in6_addr val) noexcept;

  private:
    std::array<char, /*hextet*/ 4 * /*hextets*/ 8 + /*seps*/ 7> buf;
};

template <typename BufMaker>
struct FormatFromBuf
{
  private:
    fmt::formatter<std::string_view> formatter;

  public:
    template <typename ParseContext>
    constexpr auto parse(ParseContext& ctx)
    {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(auto v, FormatContext& ctx) const
    {
        return formatter.format(BufMaker{}(v), ctx);
    }
};
} // namespace detail
} // namespace network
} // namespace phosphor

template <typename... Ts>
struct std::hash<std::tuple<Ts...>>
{
    constexpr auto operator()(const std::tuple<Ts...>& t) const noexcept
    {
        return std::apply(phosphor::network::hash_multi<Ts...>, t);
    }
};

template <>
struct std::hash<in_addr>
{
    std::size_t operator()(in_addr addr) const noexcept;
};

template <>
struct std::hash<in6_addr>
{
    std::size_t operator()(in6_addr addr) const noexcept;
};

namespace fmt
{
template <>
struct formatter<ether_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<ether_addr>>
{
};
template <>
struct formatter<in_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<in_addr>>
{
};
template <>
struct formatter<in6_addr>
    : phosphor::network::detail::FormatFromBuf<
          phosphor::network::detail::AddrBufMaker<in6_addr>>
{
};
template <>
struct formatter<phosphor::network::InAddrAny>
{
  private:
    fmt::formatter<std::string_view> formatter;

  public:
    template <typename ParseContext>
    constexpr auto parse(ParseContext& ctx)
    {
        return ctx.begin();
    }

    template <typename FormatContext>
    auto format(auto v, FormatContext& ctx) const
    {
        return std::visit(
            [&](auto v) {
                auto abm =
                    phosphor::network::detail::AddrBufMaker<decltype(v)>{};
                return formatter.format(abm(v), ctx);
            },
            v);
    }
};
} // namespace fmt

namespace std
{
string to_string(ether_addr value);
string to_string(in_addr value);
string to_string(in6_addr value);
string to_string(phosphor::network::InAddrAny value);
} // namespace std

constexpr bool operator==(ether_addr lhs, ether_addr rhs) noexcept
{
    return std::equal(lhs.ether_addr_octet, lhs.ether_addr_octet + 6,
                      rhs.ether_addr_octet);
}

constexpr bool operator==(in_addr lhs, in_addr rhs) noexcept
{
    return lhs.s_addr == rhs.s_addr;
}

constexpr bool operator==(in6_addr lhs, in6_addr rhs) noexcept
{
    return std::equal(lhs.s6_addr32, lhs.s6_addr32 + 4, rhs.s6_addr32);
}

template <typename T>
constexpr std::enable_if_t<!std::is_same_v<phosphor::network::InAddrAny, T>,
                           bool>
    operator==(phosphor::network::InAddrAny lhs, T rhs) noexcept
{
    return phosphor::network::detail::veq(rhs, lhs);
}

auto& operator<<(auto& os, ether_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<ether_addr>{}(v);
}

auto& operator<<(auto& os, in_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<in_addr>{}(v);
}

auto& operator<<(auto& os, in6_addr v)
{
    return os << phosphor::network::detail::AddrBufMaker<in6_addr>{}(v);
}

auto& operator<<(auto& os, phosphor::network::InAddrAny v)
{
    return os << std::visit(
               [](auto v) {
                   return phosphor::network::detail::AddrBufMaker<
                       decltype(v)>{}(v);
               },
               v);
}
<|endoftext|>


<commit_before>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/socket.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 2);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		m_timer.cancel(ec);
		m_abort = true;

		while (!m_queue.empty())
		{
			// we don't want to call the timeout callback while we're locked
			// since that is a recepie for dead-locks
			entry e = m_queue.front();
			m_queue.pop_front();
			l.unlock();
			try { e.on_timeout(); } catch (std::exception&) {}
			l.lock();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
#ifndef BOOST_NO_EXCEPTIONS
			try {
#endif
				ent.on_connect(ent.ticket);
#ifndef BOOST_NO_EXCEPTIONS
			} catch (std::exception&) {}
#endif

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<commit_msg>fix for connection_queue::close() to maintain the correct m_num_connecting counter<commit_after>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/socket.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 2);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		m_timer.cancel(ec);
		m_abort = true;

		while (!m_queue.empty())
		{
			// we don't want to call the timeout callback while we're locked
			// since that is a recepie for dead-locks
			entry e = m_queue.front();
			m_queue.pop_front();
			if (e.connecting) --m_num_connecting;
			l.unlock();
			try { e.on_timeout(); } catch (std::exception&) {}
			l.lock();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
#ifndef BOOST_NO_EXCEPTIONS
			try {
#endif
				ent.on_connect(ent.ticket);
#ifndef BOOST_NO_EXCEPTIONS
			} catch (std::exception&) {}
#endif

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<|endoftext|>


<commit_before>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef struct {
  std::string s;
  int retry_count;
  uint32_t bitmap;
} commands;

typedef std::list<commands> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s, int count, uint32_t bitmap);
  const std::string *out(void);
  int retry_out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn).s.c_str());
    result = (*m_pIn).s.length();
    g_lockState.testControl((*m_pIn).bitmap);
    g_lockState.retryCount((*m_pIn).retry_count);
    // std::cout << (*m_pIn).s << std::endl;
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  commands command = { std::string((char *)data, length), g_lockState.retryCount() };
  m_outputs->push_back(command);
  // m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << "retries: " << g_lockState.retryCount() << "=+=+=+=" << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s, int count, uint32_t bitmap) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  commands command = { s, count, bitmap };
  m_inputs->push_back(command);
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = new std::string ((*m_pOut).s);
    m_pOut++;
  }
  return result;
}

int TestSocket::retry_out(void) {
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    return (*m_pOut).retry_count;
  }
  return -999;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

typedef struct {
  const std::string commands[100];
  int command_count;
  const std::string match;
  int test_step;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
  uint32_t bitmap;
  int orphanCount;
} test_descriptor;

bool test(TestServer &server, TestSocket *s, Namespace *utilityNamespace, const test_descriptor *descriptor) {
  bool result = true;
  const std::string *o;

  s->reset();
  for (int i=0; i<descriptor->command_count; ++i) {
    if (i == descriptor->test_step) {
      s->in(descriptor->commands[i], descriptor->initial_retry_count, descriptor->bitmap);
    }
    else {
      s->in(descriptor->commands[i], 0, 0);
    }
  }
  server.test(s);
  int retries;
  for (int i=0; i<descriptor->response_number; ++i) {
    retries = s->retry_out();
    o = s->out();
  }
  if ((NULL == o) || (*o != descriptor->match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << descriptor->match << "\"" << std::endl;
    result = false;
  }
  if (descriptor->final_retry_count != retries) {
    std:: cout << "The retry count is " << retries << " and I was expecting " << descriptor->final_retry_count << std::endl;
    result = false;
  }
  if (descriptor->orphanCount != utilityNamespace->orphanCount()) {
    std::cout << "The namespace has " << utilityNamespace->orphanCount() << " orphans in it but is expecting " << descriptor->orphanCount << std::endl;
    result = false;
  }
  NUMBER_SET nowGone;
  g_lockState.testControl(0);
  utilityNamespace->mailboxUpdateStats(&nowGone);
  return result;
}

test_descriptor descriptors[] = {
#if 0
#endif // 0
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Creation failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 1, 3, 0, -1,
   "Successful creation",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Deletion failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 1, 3, 0, -1,
   "Successful deletion",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Renaming failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 1, 3, 0, -1,
   "Successful renaming",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 1, 4, 0, -1,
   "Successful selecting",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Selecting failure (open)",
   LockState::TestOpen, 0},
  {{
      "1 login foo bar\r\n",
      "2 select foo\r\n",
      "3 select bar\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-WRITE] select Completed\r\n", 2, 6, 1000, 999,
   "Selecting failure (close)",
   LockState::TestClose, 1},
  {{
      "1 login foo bar\r\n",
      "2 select foo\r\n",
      "3 select foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-WRITE] select Completed\r\n", 2, 6, 1000, 999,
   "Selecting failure (reopen)",
   LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 1, 4, 0, -1,
   "Successful examining",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Examining failure (open)",
   LockState::TestOpen, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine foo\r\n",
      "3 examine bar\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-ONLY] examine Completed\r\n", 2, 6, 1000, 999,
   "Examining failure (close)",
   LockState::TestClose, 1},
  {{
      "1 login foo bar\r\n",
      "2 examine foo\r\n",
      "3 examine foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-ONLY] examine Completed\r\n", 2, 6, 1000, 999,
   "Examining failure (reopen)",
   LockState::TestClose, 0},
  // SYZYGY -- close doesn't fail any more.  Instead, it generates orphans
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Closing failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 2, 5, 0, -1,
   "Successful closing",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Subscribing failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 1, 3, 0, -1,
   "Successful subscribing",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 append inbox {3}\r\n",
      "foo\r\n\r\n",
      "3 logout\r\n"
    }, 5, "2 NO append Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Appending failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 append inbox {3}\r\n",
      "foo\r\n",
      "10 logout\r\n"
    }, 4, "2 OK append Completed\r\n", 1, 4, 0, -2,  // -2 not -1 because it does two actions that could conceivably lock
   "Successful appending",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 copy 1 foo\r\n",
      "4 logout\r\n"
    }, 4, "3 NO copy Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Copying failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 copy 1 foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK copy Completed\r\n", 2, 5, 0, -3,
   "Successful copying",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 NO close Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Closing failure",
   0, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 2, 5, 0, -1,
   "Successful close",
   0, 0},
#if 0
#endif // 0
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  Namespace *utilityNamespace = master.mailStore(NULL);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, utilityNamespace, &descriptors[i]);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  delete utilityNamespace;

  return 0;
}
<commit_msg>This is the appropriate test for testing locking.<commit_after>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef struct {
  std::string s;
  int retry_count;
  uint32_t bitmap;
} commands;

typedef std::list<commands> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s, int count, uint32_t bitmap);
  const std::string *out(void);
  int retry_out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn).s.c_str());
    result = (*m_pIn).s.length();
    g_lockState.testControl((*m_pIn).bitmap);
    g_lockState.retryCount((*m_pIn).retry_count);
    // std::cout << (*m_pIn).s << std::endl;
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  commands command = { std::string((char *)data, length), g_lockState.retryCount() };
  m_outputs->push_back(command);
  // m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << "retries: " << g_lockState.retryCount() << "=+=+=+=" << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s, int count, uint32_t bitmap) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  commands command = { s, count, bitmap };
  m_inputs->push_back(command);
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = new std::string ((*m_pOut).s);
    m_pOut++;
  }
  return result;
}

int TestSocket::retry_out(void) {
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    return (*m_pOut).retry_count;
  }
  return -999;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

typedef struct {
  const std::string commands[100];
  int command_count;
  const std::string match;
  int test_step;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
  uint32_t bitmap;
  int orphanCount;
} test_descriptor;

bool test(TestServer &server, TestSocket *s, Namespace *utilityNamespace, const test_descriptor *descriptor) {
  bool result = true;
  const std::string *o;

  s->reset();
  for (int i=0; i<descriptor->command_count; ++i) {
    if (i == descriptor->test_step) {
      s->in(descriptor->commands[i], descriptor->initial_retry_count, descriptor->bitmap);
    }
    else {
      s->in(descriptor->commands[i], 0, 0);
    }
  }
  server.test(s);
  int retries;
  for (int i=0; i<descriptor->response_number; ++i) {
    retries = s->retry_out();
    o = s->out();
  }
  if ((NULL == o) || (*o != descriptor->match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << descriptor->match << "\"" << std::endl;
    result = false;
  }
  if (descriptor->final_retry_count != retries) {
    std:: cout << "The retry count is " << retries << " and I was expecting " << descriptor->final_retry_count << std::endl;
    result = false;
  }
  if (descriptor->orphanCount != utilityNamespace->orphanCount()) {
    std::cout << "The namespace has " << utilityNamespace->orphanCount() << " orphans in it but is expecting " << descriptor->orphanCount << std::endl;
    result = false;
  }
  NUMBER_SET nowGone;
  g_lockState.testControl(0);
  utilityNamespace->mailboxUpdateStats(&nowGone);
  return result;
}

test_descriptor descriptors[] = {
#if 0
#endif // 0
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Creation failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 1, 3, 0, -1,
   "Successful creation",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Deletion failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 1, 3, 0, -1,
   "Successful deletion",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Renaming failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 1, 3, 0, -1,
   "Successful renaming",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 1, 4, 0, -1,
   "Successful selecting",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Selecting failure (open)",
   LockState::TestOpen, 0},
  {{
      "1 login foo bar\r\n",
      "2 select foo\r\n",
      "3 select bar\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-WRITE] select Completed\r\n", 2, 6, 1000, 999,
   "Selecting failure (close)",
   LockState::TestClose, 1},
  {{
      "1 login foo bar\r\n",
      "2 select foo\r\n",
      "3 select foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-WRITE] select Completed\r\n", 2, 6, 1000, 999,
   "Selecting failure (reopen)",
   LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 1, 4, 0, -1,
   "Successful examining",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Examining failure (open)",
   LockState::TestOpen, 0},
  {{
      "1 login foo bar\r\n",
      "2 examine foo\r\n",
      "3 examine bar\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-ONLY] examine Completed\r\n", 2, 6, 1000, 999,
   "Examining failure (close)",
   LockState::TestClose, 1},
  {{
      "1 login foo bar\r\n",
      "2 examine foo\r\n",
      "3 examine foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK [READ-ONLY] examine Completed\r\n", 2, 6, 1000, 999,
   "Examining failure (reopen)",
   LockState::TestClose, 0},
  // SYZYGY -- close doesn't fail any more.  Instead, it generates orphans
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Closing failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 2, 5, 0, -1,
   "Successful closing",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Subscribing failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 1, 3, 0, -1,
   "Successful subscribing",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 append inbox {3}\r\n",
      "foo\r\n\r\n",
      "3 logout\r\n"
    }, 5, "2 NO append Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Appending failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 append inbox {3}\r\n",
      "foo\r\n",
      "10 logout\r\n"
    }, 4, "+ Ready for the Message Data\r\n", 1, 3, 0, -1,
   "Successful appending",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 copy 1 foo\r\n",
      "4 logout\r\n"
    }, 4, "3 NO copy Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Copying failure",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 copy 1 foo\r\n",
      "4 logout\r\n"
    }, 4, "3 OK copy Completed\r\n", 2, 5, 0, -3,
   "Successful copying",
   LockState::TestOpen | LockState::TestClose, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 NO close Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Closing failure",
   0, 0},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 2, 5, 0, -1,
   "Successful close",
   0, 0},
#if 0
#endif // 0
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  Namespace *utilityNamespace = master.mailStore(NULL);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, utilityNamespace, &descriptors[i]);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  delete utilityNamespace;

  return 0;
}
<|endoftext|>