<commit_before>// Copyright (c) 2018 alex v
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "ntpclient.h"
#include "util.h"

using namespace boost;
using namespace boost::asio;

int64_t CNtpClient::getTimestamp()
{
    time_t timeRecv = -1;

    io_service io_service;

    LogPrint("ntp", "CNtpClient: Opening socket to NTP server %s.\n", sHostName);
    try
    {

        ip::udp::resolver resolver(io_service);
        ip::udp::resolver::query query(boost::asio::ip::udp::v4(), sHostName, "ntp");

        ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);

        ip::udp::socket socket(io_service);
        socket.open(ip::udp::v4());

        boost::array<unsigned char, 48> sendBuf = {10,0,0,0,0,0,0,0,0};

        socket.send_to(boost::asio::buffer(sendBuf), receiver_endpoint);

        boost::array<unsigned long, 1024> recvBuf;
        ip::udp::endpoint sender_endpoint;

        try
        {

            fd_set fileDescriptorSet;
            struct timeval timeStruct;

            // set the timeout to 5 seconds
            timeStruct.tv_sec = GetArg("-ntptimeout", 5);
            timeStruct.tv_usec = 0;
            FD_ZERO(&fileDescriptorSet);

            int nativeSocket = socket.native();

            FD_SET(nativeSocket,&fileDescriptorSet);

            select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);

            if(!FD_ISSET(nativeSocket,&fileDescriptorSet))
            {

                LogPrint("ntp", "CNtpClient: Could not read socket from NTP server %s (Read timeout)\n", sHostName);

            }
            else
            {

                socket.receive_from(boost::asio::buffer(recvBuf), sender_endpoint);
                timeRecv = ntohl((time_t)recvBuf[4]);
                timeRecv-= 2208988800U;  // Substract 01/01/1970 == 2208988800U

                LogPrint("ntp", "CNtpClient: Received timestamp: %ll", (long)timeRecv);

            }

        }
        catch (std::exception& e)
        {

             LogPrintf("CNtpClient: Could not read clock from NTP server %s (%s)\n", sHostName, e.what());

        }

    }
    catch (std::exception& e)
    {

        LogPrintf("CNtpClient: Could not open socket to NTP server %s (%s)\n", sHostName, e.what());

    }

    return (int64_t)timeRecv;
  }
<commit_msg>fix definition<commit_after>// Copyright (c) 2018 alex v
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "ntpclient.h"
#include "util.h"

using namespace boost;
using namespace boost::asio;

int64_t CNtpClient::getTimestamp()
{
    time_t timeRecv = -1;

    io_service io_service;

    LogPrint("ntp", "CNtpClient: Opening socket to NTP server %s.\n", sHostName);
    try
    {

        ip::udp::resolver resolver(io_service);
        ip::udp::resolver::query query(boost::asio::ip::udp::v4(), sHostName, "ntp");

        ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);

        ip::udp::socket socket(io_service);
        socket.open(ip::udp::v4());

        boost::array<unsigned char, 48> sendBuf = {{10,0,0,0,0,0,0,0,0}};

        socket.send_to(boost::asio::buffer(sendBuf), receiver_endpoint);

        boost::array<unsigned long, 1024> recvBuf;
        ip::udp::endpoint sender_endpoint;

        try
        {

            fd_set fileDescriptorSet;
            struct timeval timeStruct;

            // set the timeout to 5 seconds
            timeStruct.tv_sec = GetArg("-ntptimeout", 5);
            timeStruct.tv_usec = 0;
            FD_ZERO(&fileDescriptorSet);

            int nativeSocket = socket.native();

            FD_SET(nativeSocket,&fileDescriptorSet);

            select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);

            if(!FD_ISSET(nativeSocket,&fileDescriptorSet))
            {

                LogPrint("ntp", "CNtpClient: Could not read socket from NTP server %s (Read timeout)\n", sHostName);

            }
            else
            {

                socket.receive_from(boost::asio::buffer(recvBuf), sender_endpoint);
                timeRecv = ntohl((time_t)recvBuf[4]);
                timeRecv-= 2208988800U;  // Substract 01/01/1970 == 2208988800U

                LogPrint("ntp", "CNtpClient: Received timestamp: %ll", (long)timeRecv);

            }

        }
        catch (std::exception& e)
        {

             LogPrintf("CNtpClient: Could not read clock from NTP server %s (%s)\n", sHostName, e.what());

        }

    }
    catch (std::exception& e)
    {

        LogPrintf("CNtpClient: Could not open socket to NTP server %s (%s)\n", sHostName, e.what());

    }

    return (int64_t)timeRecv;
  }
<|endoftext|>


<commit_before>/**
 ** \file object/fwd.hh
 ** \brief Forward declarations of all node-classes of OBJECT
 ** (needed by the visitors)
 */
#ifndef OBJECT_FWD_HH
# define OBJECT_FWD_HH

# include <vector>

# include <libport/fwd.hh>
# include <libport/shared-ptr.hh>

namespace runner
{
  class Runner;
}

namespace object
{
  // state.hh
  struct State;

  // rObject & objects_type.
  class Object;
  // We don't know yet that Object inherits RefCounted, so we have to force
  // the second template argument.
  typedef libport::shared_ptr<Object, true> rObject;
  typedef std::vector<rObject> objects_type;

  /// \a Macro should be a binary macro whose first arg, \p What, is
  /// the lower case C++ name, and the second argument, \p Name, the
  /// capitalized URBI name.  This is used in many different contexts,
  /// such as defining enums, so we do not use terminators here (;
  /// etc.): Macro must do it.
# define APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)	\
  Macro(alien,      Alien)				\
  Macro(code,       Code)				\
  Macro(delegate,   Delegate)				\
  Macro(dictionary, Dictionary)                         \
  Macro(float,      Float)				\
  Macro(integer,    Integer)				\
  Macro(list,       List)				\
  Macro(lobby,      Lobby)				\
  Macro(primitive,  Primitive)				\
  Macro(string,     String)

# define APPLY_ON_ALL_PRIMITIVES(Macro)			\
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)		\
  Macro(object,    Object)

# define APPLY_ON_ALL_ROOT_CLASSES_BUT_OBJECT(Macro)	\
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)		\
  Macro(global, Global)					\
  Macro(scope, Scope)					\
  Macro(tag, Tag)					\
  Macro(task, Task)

# define APPLY_ON_ALL_ROOT_CLASSES(Macro)	\
  APPLY_ON_ALL_ROOT_CLASSES_BUT_OBJECT(Macro)	\
  Macro(object, Object)

  /*
    Help the generation of precompiled symbols.

    SYMBOL(Alien)
    SYMBOL(Call)
    SYMBOL(Code)
    SYMBOL(Delegate)
    SYMBOL(Float)
    SYMBOL(Integer)
    SYMBOL(List)
    SYMBOL(Lobby)
    SYMBOL(Object)
    SYMBOL(Primitive)
    SYMBOL(String)
    SYMBOL(Task)

  */

  // All the atoms.
  template <typename Traits>
  class Atom;

  /// Define a primitive as an Atom parametrized with a traits.
# define DEFINE(What, Name)				\
  struct What ## _traits;				\
  typedef Atom< What ## _traits > Name;			\
  typedef libport::shared_ptr < Name, true > r ## Name;

  /* You have to understand that the primitives are defined here.  For
   * example, a Code is manipulated through a rCode (r = ref counted) and in
   * fact Code is just a typedef for Atom<code_traits>.  If you get compilation
   * errors about non existent members, it's most likely because you did
   * obj.get_value () instead of obj->get_value ().  This is a side effect
   * of the operator-> used for the ref-counting.  Keep that in mind. */
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(DEFINE)
# undef DEFINE

  // urbi-exception.hh
  class IDelegate;
  class UrbiException;
  class LookupError;
  class RedefinitionError;
  class PrimitiveError;
  class WrongArgumentType;
  class WrongArgumentCount;

  extern rObject nil_class;
  extern rObject task_class;
  extern rObject void_class;
} // namespace object

#endif // !OBJECT_FWD_HH
<commit_msg>Aesthetics day: indentation fix again.<commit_after>/**
 ** \file object/fwd.hh
 ** \brief Forward declarations of all node-classes of OBJECT
 ** (needed by the visitors)
 */
#ifndef OBJECT_FWD_HH
# define OBJECT_FWD_HH

# include <vector>

# include <libport/fwd.hh>
# include <libport/shared-ptr.hh>

namespace runner
{
  class Runner;
}

namespace object
{
  // state.hh
  struct State;

  // rObject & objects_type.
  class Object;
  // We don't know yet that Object inherits RefCounted, so we have to force
  // the second template argument.
  typedef libport::shared_ptr<Object, true> rObject;
  typedef std::vector<rObject> objects_type;

  /// \a Macro should be a binary macro whose first arg, \p What, is
  /// the lower case C++ name, and the second argument, \p Name, the
  /// capitalized URBI name.  This is used in many different contexts,
  /// such as defining enums, so we do not use terminators here (;
  /// etc.): Macro must do it.
# define APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)	\
  Macro(alien,      Alien)				\
  Macro(code,       Code)				\
  Macro(delegate,   Delegate)				\
  Macro(dictionary, Dictionary)                         \
  Macro(float,      Float)				\
  Macro(integer,    Integer)				\
  Macro(list,       List)				\
  Macro(lobby,      Lobby)				\
  Macro(primitive,  Primitive)				\
  Macro(string,     String)

# define APPLY_ON_ALL_PRIMITIVES(Macro)			\
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)		\
  Macro(object,     Object)

# define APPLY_ON_ALL_ROOT_CLASSES_BUT_OBJECT(Macro)	\
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(Macro)		\
  Macro(global,     Global)					\
  Macro(scope,      Scope)					\
  Macro(tag,        Tag)					\
  Macro(task,       Task)

# define APPLY_ON_ALL_ROOT_CLASSES(Macro)	\
  APPLY_ON_ALL_ROOT_CLASSES_BUT_OBJECT(Macro)	\
  Macro(object, Object)

  /*
    Help the generation of precompiled symbols.

    SYMBOL(Alien)
    SYMBOL(Call)
    SYMBOL(Code)
    SYMBOL(Delegate)
    SYMBOL(Float)
    SYMBOL(Integer)
    SYMBOL(List)
    SYMBOL(Lobby)
    SYMBOL(Object)
    SYMBOL(Primitive)
    SYMBOL(String)
    SYMBOL(Task)

  */

  // All the atoms.
  template <typename Traits>
  class Atom;

  /// Define a primitive as an Atom parametrized with a traits.
# define DEFINE(What, Name)				\
  struct What ## _traits;				\
  typedef Atom< What ## _traits > Name;			\
  typedef libport::shared_ptr < Name, true > r ## Name;

  /* You have to understand that the primitives are defined here.  For
   * example, a Code is manipulated through a rCode (r = ref counted) and in
   * fact Code is just a typedef for Atom<code_traits>.  If you get compilation
   * errors about non existent members, it's most likely because you did
   * obj.get_value () instead of obj->get_value ().  This is a side effect
   * of the operator-> used for the ref-counting.  Keep that in mind. */
  APPLY_ON_ALL_PRIMITIVES_BUT_OBJECT(DEFINE)
# undef DEFINE

  // urbi-exception.hh
  class IDelegate;
  class UrbiException;
  class LookupError;
  class RedefinitionError;
  class PrimitiveError;
  class WrongArgumentType;
  class WrongArgumentCount;

  extern rObject nil_class;
  extern rObject task_class;
  extern rObject void_class;
} // namespace object

#endif // !OBJECT_FWD_HH
<|endoftext|>


<commit_before>#include "ofxLSTube.h"

ofxLSTube::ofxLSTube(){

}

void ofxLSTube::generate(ofMesh& mesh, const ofxLSBranch branch, const float length){
    bool cap = true;
    const int radius = branch.capSizes.first;
    const int scaledRadius = branch.capSizes.second;

    // these variables are used to do not stretch the texture
    float circumferenceBottom = radius * 3.1415926f;
    float ratio = circumferenceBottom/length;
    float ratioCap = (scaledRadius*2)/length;
    float xWrapLimit = circumferenceBottom/(length/textureRepeat);
    float wrapLimitCap = ratioCap * textureRepeat;

    ofMatrix4x4 beginMatrix = branch.begin.getGlobalTransformMatrix();
    ofMatrix4x4 endMatrix = branch.end.getGlobalTransformMatrix();

    // Cylinder body
    int first = mesh.getNumVertices();
    for (int i = 0; i <= resolution; i++) {
        // if it is the last face, close it where the first face
        // was started
        if (i == resolution) {
            mesh.addIndex(first+(i*2));
            mesh.addIndex(first);
            mesh.addIndex(first+1);

            mesh.addIndex(first+1);
            mesh.addIndex(first+(i*2)+1);
            mesh.addIndex(first+(i*2));
        } else {
            mesh.addIndex(first+(i*2));
            mesh.addIndex(first+(i*2)+2);
            mesh.addIndex(first+(i*2)+3);

            mesh.addIndex(first+(i*2)+3);
            mesh.addIndex(first+(i*2)+1);
            mesh.addIndex(first+(i*2));
        }
    }

    for (int i = 0; i <= resolution; i++) {
        //calculate x and y component
        float theta = 2.0f * 3.1415926f * float(i) / float(resolution);
        float x = radius * cosf(theta);
        float z = radius * sinf(theta);
        ofVec3f circleBottom = ofVec3f(x, 0.0, z);
        ofVec3f direction = (ofVec3f() + circleBottom).getNormalized();

        float xTop = scaledRadius * cosf(theta);
        float zTop = scaledRadius * sinf(theta);
        ofVec3f circleTop = ofVec3f(xTop, 0.0, zTop);
        ofVec2f tcoord;
        tcoord.x = ofMap(i, 0.f, resolution, 0.f, xWrapLimit);

        // bottom
        tcoord.y = 0;
        mesh.addVertex(circleBottom * beginMatrix);
        mesh.addNormal(direction * beginMatrix.getRotate());
        mesh.addTexCoord(tcoord);

        //top
        tcoord.y = textureRepeat;
        mesh.addVertex(circleTop * endMatrix);
        mesh.addNormal(direction * endMatrix.getRotate());
        mesh.addTexCoord(tcoord);
    }

    // Cylinder cap
    if (cap) {
        int topMiddlePoint = mesh.getNumVertices();
        ofVec3f topDir = branch.end.getPosition().getNormalized();
        mesh.addVertex(branch.end.getGlobalPosition());
        mesh.addNormal(topDir * endMatrix.getRotate());
        mesh.addTexCoord(ofVec2f(wrapLimitCap/2,wrapLimitCap/2));

        for (int i = 0; i <= resolution; i++) {
            if (i == resolution) {
                //closing triangle
                mesh.addIndex(topMiddlePoint);
                mesh.addIndex(topMiddlePoint+ i + 1);
                mesh.addIndex(topMiddlePoint+1);
            } else {
                //indices
                mesh.addIndex(topMiddlePoint);
                mesh.addIndex(topMiddlePoint+ i + 1);
                mesh.addIndex(topMiddlePoint+ i + 2);
            }
            //add vertex
            float theta = 2.0f * 3.1415926f * float(i) / float(resolution);
            float x = scaledRadius * cosf(theta);
            float z = scaledRadius * sinf(theta);
            ofVec3f circleTemp = ofVec3f(x, 0.0, z);

            ofVec2f capTcoord;
            capTcoord.x = ofMap(x, -scaledRadius, scaledRadius, 0.f, wrapLimitCap);
            capTcoord.y = ofMap(z, -scaledRadius, scaledRadius, 0.f, wrapLimitCap);
            mesh.addVertex(circleTemp * branch.end.getGlobalTransformMatrix());
            mesh.addNormal(topDir * endMatrix.getRotate());
            mesh.addTexCoord(capTcoord);
        }
    }
}
<commit_msg>fix texture on cap<commit_after>#include "ofxLSTube.h"

ofxLSTube::ofxLSTube(){

}

void ofxLSTube::generate(ofMesh& mesh, const ofxLSBranch branch, const float length){
    bool cap = true;
    const int radius = branch.capSizes.first;
    const int scaledRadius = branch.capSizes.second;

    // these variables are used to do not stretch the texture
    float circumferenceBottom = radius * 3.1415926f;
    float ratio = circumferenceBottom/length;
    float ratioCap = scaledRadius/length;
    float xWrapLimit = circumferenceBottom/(length/textureRepeat);
    float wrapLimitCap = ratioCap * textureRepeat;

    ofMatrix4x4 beginMatrix = branch.begin.getGlobalTransformMatrix();
    ofMatrix4x4 endMatrix = branch.end.getGlobalTransformMatrix();

    // Cylinder body
    int first = mesh.getNumVertices();
    for (int i = 0; i <= resolution; i++) {
        // if it is the last face, close it where the first face
        // was started
        if (i == resolution) {
            mesh.addIndex(first+(i*2));
            mesh.addIndex(first);
            mesh.addIndex(first+1);

            mesh.addIndex(first+1);
            mesh.addIndex(first+(i*2)+1);
            mesh.addIndex(first+(i*2));
        } else {
            mesh.addIndex(first+(i*2));
            mesh.addIndex(first+(i*2)+2);
            mesh.addIndex(first+(i*2)+3);

            mesh.addIndex(first+(i*2)+3);
            mesh.addIndex(first+(i*2)+1);
            mesh.addIndex(first+(i*2));
        }
    }

    for (int i = 0; i <= resolution; i++) {
        //calculate x and y component
        float theta = 2.0f * 3.1415926f * float(i) / float(resolution);
        float x = radius * cosf(theta);
        float z = radius * sinf(theta);
        ofVec3f circleBottom = ofVec3f(x, 0.0, z);
        ofVec3f direction = (ofVec3f() + circleBottom).getNormalized();

        float xTop = scaledRadius * cosf(theta);
        float zTop = scaledRadius * sinf(theta);
        ofVec3f circleTop = ofVec3f(xTop, 0.0, zTop);
        ofVec2f tcoord;
        tcoord.x = ofMap(i, 0.f, resolution, 0.f, xWrapLimit);

        // bottom
        tcoord.y = 0;
        mesh.addVertex(circleBottom * beginMatrix);
        mesh.addNormal(direction * beginMatrix.getRotate());
        mesh.addTexCoord(tcoord);

        //top
        tcoord.y = textureRepeat;
        mesh.addVertex(circleTop * endMatrix);
        mesh.addNormal(direction * endMatrix.getRotate());
        mesh.addTexCoord(tcoord);
    }

    // Cylinder cap
    if (cap) {
        int topMiddlePoint = mesh.getNumVertices();
        ofVec3f topDir = branch.end.getPosition().getNormalized();
        mesh.addVertex(branch.end.getGlobalPosition());
        mesh.addNormal(topDir * endMatrix.getRotate());
        mesh.addTexCoord(ofVec2f(wrapLimitCap/2,wrapLimitCap/2));

        for (int i = 0; i <= resolution; i++) {
            if (i == resolution) {
                //closing triangle
                mesh.addIndex(topMiddlePoint);
                mesh.addIndex(topMiddlePoint+ i + 1);
                mesh.addIndex(topMiddlePoint+1);
            } else {
                //indices
                mesh.addIndex(topMiddlePoint);
                mesh.addIndex(topMiddlePoint+ i + 1);
                mesh.addIndex(topMiddlePoint+ i + 2);
            }
            //add vertex
            float theta = 2.0f * 3.1415926f * float(i) / float(resolution);
            float x = scaledRadius * cosf(theta);
            float z = scaledRadius * sinf(theta);
            ofVec3f circleTemp = ofVec3f(x, 0.0, z);

            ofVec2f capTcoord;
            capTcoord.x = ofMap(x, -scaledRadius, scaledRadius, 0.f, wrapLimitCap);
            capTcoord.y = ofMap(z, -scaledRadius, scaledRadius, 0.f, wrapLimitCap);
            mesh.addVertex(circleTemp * branch.end.getGlobalTransformMatrix());
            mesh.addNormal(topDir * endMatrix.getRotate());
            mesh.addTexCoord(capTcoord);
        }
    }
}
<|endoftext|>


<commit_before>// Compares the number of operations with items in gheap-based algorithms
// to the number of operations with items in the corresponding STL algorithms.
//
// Pass -DNDEBUG for eliminating operations related to debugging checks.

#include "galgorithm.hpp"
#include "gheap.hpp"

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <list>
#include <stdint.h>  // for uintptr_t (<cstdint> is missing in C++03).
#include <vector>

using namespace std;

// Simulates a LRU list of pages, which can contain up to _max_lru_size entries.
// Each page has size PAGE_MASK + 1.
struct lru
{
  typedef list<uintptr_t> lru_t;

  static const uintptr_t PAGE_MASK = (((uintptr_t)1) << 12) - 1;

  // Maximum number of pages in LRU list.
  static const size_t MAX_LRU_SIZE = 16;

  // LRU list of pages. Front of the list contains least recently used pages.
  static lru_t lru_pages;

  // The number of simulated pagefaults since the last lru::init() call.
  static int pagefaults;

  // Resets the model to initial state.
  static void reset()
  {
    lru_pages.clear();
    pagefaults = 0;
  }

  // Simulates access to a memory pointed by ptr.
  // Brings the accessed page to the back of LRU list.
  // If the page is absent in LRU list, then increments pagefaults counter.
  static void access_ptr(const void *const ptr)
  {
    assert(lru_pages.size() <= MAX_LRU_SIZE);

    uintptr_t page_num = ((uintptr_t)ptr) & ~PAGE_MASK;
    lru_t::iterator it = find(lru_pages.begin(), lru_pages.end(),
        page_num);
    if (it == lru_pages.end()) {
      ++pagefaults;
      lru_pages.push_front(page_num);
      if (lru_pages.size() > MAX_LRU_SIZE) {
        lru_pages.pop_back();
      }
      assert(lru_pages.size() <= MAX_LRU_SIZE);
    }
    else {
      lru_pages.splice(lru_pages.begin(), lru_pages, it);
    }
  }
};

lru::lru_t lru::lru_pages;
int lru::pagefaults = 0;

struct A
{
  static int default_ctors;
  static int copy_ctors;
  static int copy_assignments;
  static int swaps;
  static int cheap_dtors;
  static int expensive_dtors;
  static int move_ctors;
  static int cheap_move_assignments;
  static int expensive_move_assignments;
  static int comparisons;

  static void reset()
  {
    default_ctors = 0;
    copy_ctors = 0;
    copy_assignments = 0;
    swaps = 0;
    cheap_dtors = 0;
    expensive_dtors = 0;
    move_ctors = 0;
    cheap_move_assignments = 0;
    expensive_move_assignments = 0;
    comparisons = 0;
    lru::reset();
  }

  static void print()
  {
    cout << "default_ctors=" << default_ctors << ", copy_ctors=" <<
        copy_ctors << ", copy_assignments=" << copy_assignments <<
        ", swaps=" << swaps << ", cheap_dtors=" << cheap_dtors <<
        ", expensive_dtors=" << expensive_dtors << ", move_ctors=" <<
        move_ctors << ", cheap_move_assignments=" << cheap_move_assignments <<
        ", expensive_move_assignments=" << expensive_move_assignments <<
        ", comparisons=" << comparisons << ", pagefaults=" << lru::pagefaults <<
            endl;
  }

  int value;

  bool has_value() const
  {
    return (value >= 0);
  }

  int get_value() const
  {
    assert(has_value());
    lru::access_ptr(this);
    return value;
  }

  void set_value(const int v)
  {
    assert(v >= 0);
    value = v;
    lru::access_ptr(this);
  }

  void set_value(const A &a)
  {
    int v = a.get_value();
    set_value(v);
  }

  void clear_value()
  {
    value = -1;
    lru::access_ptr(this);
  }

  A()
  {
    ++default_ctors;
    clear_value();
  }

  A(const int v)
  {
    set_value(v);
  }

  A(const A &a)
  {
    ++copy_ctors;
    set_value(a);
  }

  void operator = (const A &a)
  {
    if (this == &a) {
      return;
    }

    assert(has_value());
    ++copy_assignments;
    set_value(a);
  }

  ~A()
  {
    if (has_value()) {
      ++expensive_dtors;
    }
    else {
      ++cheap_dtors;
    }
    clear_value();
  }

#ifdef GHEAP_CPP11

  A(A &&a)
  {
    ++move_ctors;
    set_value(a);
    a.clear_value();
  }

  void operator = (A &&a)
  {
    if (this == &a) {
      return;
    }

    if (has_value()) {
      ++expensive_move_assignments;
    }
    else {
      ++cheap_move_assignments;
    }

    set_value(a);
    a.clear_value();
  }

#endif
};

int A::default_ctors;
int A::copy_ctors;
int A::copy_assignments;
int A::swaps;
int A::cheap_dtors;
int A::expensive_dtors;
int A::move_ctors;
int A::cheap_move_assignments;
int A::expensive_move_assignments;
int A::comparisons;

namespace std
{
  template <>
  void swap(A &a, A &b)
  {
    ++A::swaps;

    int tmp = a.get_value();
    a.set_value(b);
    b.set_value(tmp);
  }
}

bool operator < (const A &a, const A &b)
{
  ++A::comparisons;
  return (a.get_value() < b.get_value());
}

struct stl
{
  static const char *name()
  {
    return "stl";
  }

  template <class RandomAccessIterator>
  static void push_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::push_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void pop_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::pop_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void make_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::make_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void sort_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::sort_heap(first, last);
  }
};

struct gtl
{
  typedef gheap<> heap;

  static const char *name()
  {
    return "gheap<>";
  }

  template <class RandomAccessIterator>
  static void push_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::push_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void pop_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::pop_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void make_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::make_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void sort_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::sort_heap(first, last);
  }
};

namespace {

void init_array(vector<A> &a, const size_t n)
{
  a.clear();
  srand(0);
  generate_n(back_inserter(a), n, rand);
}

template <class Heap>
void test_push_heap(vector<A> &a, const size_t n)
{
  cout << "  test_push_heap(" << Heap::name() << "): ";

  init_array(a, n);
  A::reset();
  for (size_t i = 2; i <= n; ++i) {
    Heap::push_heap(a.begin(), a.begin() + i);
  }
  A::print();
}

template <class Heap>
void test_pop_heap(vector<A> &a, const size_t n)
{
  cout << "  test_pop_heap(" << Heap::name() << "): ";

  init_array(a, n);
  Heap::make_heap(a.begin(), a.end());

  A::reset();
  for (size_t i = 0; i < n - 1; ++i) {
    Heap::pop_heap(a.begin(), a.end() - i);
  }
  A::print();
}

template <class Heap>
void test_make_heap(vector<A> &a, const size_t n)
{
  cout << "  test_make_heap(" << Heap::name() << "): ";

  init_array(a, n);
  A::reset();
  Heap::make_heap(a.begin(), a.end());
  A::print();
}

template <class Heap>
void test_sort_heap(vector<A> &a, const size_t n)
{
  cout << "  test_sort_heap(" << Heap::name() << "): ";

  init_array(a, n);
  Heap::make_heap(a.begin(), a.end());

  A::reset();
  Heap::sort_heap(a.begin(), a.end());
  A::print();
}

void test_nway_mergesort_avg(vector<A> &a, const size_t n)
{
  cout << "  test_nway_mergesort_avg(" << gtl::name() << "): ";

  typedef galgorithm<gtl::heap> algorithm;

  init_array(a, n);
  A::reset();
  algorithm::nway_mergesort(a.begin(), a.end());
  A::print();
}

void test_nway_mergesort_worst(vector<A> &a, const size_t n)
{
  cout << "  test_nway_mergesort_worst(" << gtl::name() << "): ";

  typedef galgorithm<gtl::heap> algorithm;

  // Simulate worst case for SGI STL sort implementation (aka introsort) -
  // see http://en.wikipedia.org/wiki/Introsort .
  // Actually n-way mergesort must be free of bad cases.
  for (size_t i = 0; i < n; ++i) {
    a[i] = n - i;
  }

  init_array(a, n);
  A::reset();
  algorithm::nway_mergesort(a.begin(), a.end());
  A::print();
}

void test_sort_avg(vector<A> &a, const size_t n)
{
  cout << "  test_sort_avg(" << stl::name() << "): ";

  init_array(a, n);
  A::reset();
  sort(a.begin(), a.end());
  A::print();
}

void test_sort_worst(vector<A> &a, const size_t n)
{
  cout << "  test_sort_worst(" << stl::name() << "): ";

  // Simulate worst case for SGI STL sort implementation (aka introsort) -
  // see http://en.wikipedia.org/wiki/Introsort .
  for (size_t i = 0; i < n; ++i) {
    a[i] = n - i;
  }

  A::reset();
  sort(a.begin(), a.end());
  A::print();
}

}  // end of anonymous namespace

int main()
{
  const size_t N = 1000000;

  cout << "N=" << N << endl;

  vector<A> a;
  a.reserve(N);

  test_push_heap<stl>(a, N);
  test_push_heap<gtl>(a, N);

  test_pop_heap<stl>(a, N);
  test_pop_heap<gtl>(a, N);

  test_make_heap<stl>(a, N);
  test_make_heap<gtl>(a, N);

  test_sort_heap<stl>(a, N);
  test_sort_heap<gtl>(a, N);

  test_nway_mergesort_avg(a, N);
  test_nway_mergesort_worst(a, N);
  test_sort_avg(a, N);
  test_sort_worst(a, N);
}
<commit_msg>Don't count pagefaults if the previous page is in LRU list<commit_after>// Compares the number of operations with items in gheap-based algorithms
// to the number of operations with items in the corresponding STL algorithms.
//
// Pass -DNDEBUG for eliminating operations related to debugging checks.

#include "galgorithm.hpp"
#include "gheap.hpp"

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <list>
#include <stdint.h>  // for uintptr_t (<cstdint> is missing in C++03).
#include <vector>

using namespace std;

// Simulates a LRU list of pages, which can contain up to _max_lru_size entries.
// Each page's size is PAGE_MASK + 1 bytes.
struct lru
{
  typedef list<uintptr_t> lru_t;

  static const uintptr_t PAGE_MASK = (((uintptr_t)1) << 12) - 1;

  // Maximum number of pages in LRU list.
  static const size_t MAX_LRU_SIZE = 20;

  // LRU list of pages. Front of the list contains least recently used pages.
  static lru_t lru_pages;

  // The number of simulated pagefaults since the last lru::init() call.
  static int pagefaults;

  // Resets the model to initial state.
  static void reset()
  {
    lru_pages.clear();
    pagefaults = 0;
  }

  // Simulates access to a memory pointed by ptr.
  // Brings the accessed page to the back of LRU list.
  // If the page is absent in LRU list, then increments pagefaults counter.
  static void access_ptr(const void *const ptr)
  {
    assert(lru_pages.size() <= MAX_LRU_SIZE);

    const uintptr_t page_num = ((uintptr_t)ptr) & ~PAGE_MASK;
    lru_t::iterator it = find(lru_pages.begin(), lru_pages.end(),
        page_num);
    if (it == lru_pages.end()) {
      const uintptr_t prev_page_num = page_num - PAGE_MASK - 1;
      if (count(lru_pages.begin(), lru_pages.end(), prev_page_num) == 0) {
        // Count pagefault only if the previous page is not in the LRU list.
        // If the previous page is in the LRU list, then assume that the current
        // page is already pre-fetched, so no hard pagefault.
        ++pagefaults;
      }

      lru_pages.push_front(page_num);
      if (lru_pages.size() > MAX_LRU_SIZE) {
        lru_pages.pop_back();
      }
      assert(lru_pages.size() <= MAX_LRU_SIZE);
    }
    else {
      lru_pages.splice(lru_pages.begin(), lru_pages, it);
    }
  }
};

lru::lru_t lru::lru_pages;
int lru::pagefaults = 0;

struct A
{
  static int default_ctors;
  static int copy_ctors;
  static int copy_assignments;
  static int swaps;
  static int cheap_dtors;
  static int expensive_dtors;
  static int move_ctors;
  static int cheap_move_assignments;
  static int expensive_move_assignments;
  static int comparisons;

  static void reset()
  {
    default_ctors = 0;
    copy_ctors = 0;
    copy_assignments = 0;
    swaps = 0;
    cheap_dtors = 0;
    expensive_dtors = 0;
    move_ctors = 0;
    cheap_move_assignments = 0;
    expensive_move_assignments = 0;
    comparisons = 0;
    lru::reset();
  }

  static void print()
  {
    cout << "default_ctors=" << default_ctors << ", copy_ctors=" <<
        copy_ctors << ", copy_assignments=" << copy_assignments <<
        ", swaps=" << swaps << ", cheap_dtors=" << cheap_dtors <<
        ", expensive_dtors=" << expensive_dtors << ", move_ctors=" <<
        move_ctors << ", cheap_move_assignments=" << cheap_move_assignments <<
        ", expensive_move_assignments=" << expensive_move_assignments <<
        ", comparisons=" << comparisons << ", pagefaults=" << lru::pagefaults <<
            endl;
  }

  int value;

  bool has_value() const
  {
    return (value >= 0);
  }

  int get_value() const
  {
    assert(has_value());
    lru::access_ptr(this);
    return value;
  }

  void set_value(const int v)
  {
    assert(v >= 0);
    value = v;
    lru::access_ptr(this);
  }

  void set_value(const A &a)
  {
    int v = a.get_value();
    set_value(v);
  }

  void clear_value()
  {
    value = -1;
    lru::access_ptr(this);
  }

  A()
  {
    ++default_ctors;
    clear_value();
  }

  A(const int v)
  {
    set_value(v);
  }

  A(const A &a)
  {
    ++copy_ctors;
    set_value(a);
  }

  void operator = (const A &a)
  {
    if (this == &a) {
      return;
    }

    assert(has_value());
    ++copy_assignments;
    set_value(a);
  }

  ~A()
  {
    if (has_value()) {
      ++expensive_dtors;
    }
    else {
      ++cheap_dtors;
    }
    clear_value();
  }

#ifdef GHEAP_CPP11

  A(A &&a)
  {
    ++move_ctors;
    set_value(a);
    a.clear_value();
  }

  void operator = (A &&a)
  {
    if (this == &a) {
      return;
    }

    if (has_value()) {
      ++expensive_move_assignments;
    }
    else {
      ++cheap_move_assignments;
    }

    set_value(a);
    a.clear_value();
  }

#endif
};

int A::default_ctors;
int A::copy_ctors;
int A::copy_assignments;
int A::swaps;
int A::cheap_dtors;
int A::expensive_dtors;
int A::move_ctors;
int A::cheap_move_assignments;
int A::expensive_move_assignments;
int A::comparisons;

namespace std
{
  template <>
  void swap(A &a, A &b)
  {
    ++A::swaps;

    int tmp = a.get_value();
    a.set_value(b);
    b.set_value(tmp);
  }
}

bool operator < (const A &a, const A &b)
{
  ++A::comparisons;
  return (a.get_value() < b.get_value());
}

struct stl
{
  static const char *name()
  {
    return "stl";
  }

  template <class RandomAccessIterator>
  static void push_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::push_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void pop_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::pop_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void make_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::make_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void sort_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    ::std::sort_heap(first, last);
  }
};

struct gtl
{
  typedef gheap<> heap;

  static const char *name()
  {
    return "gheap<>";
  }

  template <class RandomAccessIterator>
  static void push_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::push_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void pop_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::pop_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void make_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::make_heap(first, last);
  }

  template <class RandomAccessIterator>
  static void sort_heap(const RandomAccessIterator &first,
      const RandomAccessIterator &last)
  {
    heap::sort_heap(first, last);
  }
};

namespace {

void init_array(vector<A> &a, const size_t n)
{
  a.clear();
  srand(0);
  generate_n(back_inserter(a), n, rand);
}

template <class Heap>
void test_push_heap(vector<A> &a, const size_t n)
{
  cout << "  test_push_heap(" << Heap::name() << "): ";

  init_array(a, n);
  A::reset();
  for (size_t i = 2; i <= n; ++i) {
    Heap::push_heap(a.begin(), a.begin() + i);
  }
  A::print();
}

template <class Heap>
void test_pop_heap(vector<A> &a, const size_t n)
{
  cout << "  test_pop_heap(" << Heap::name() << "): ";

  init_array(a, n);
  Heap::make_heap(a.begin(), a.end());

  A::reset();
  for (size_t i = 0; i < n - 1; ++i) {
    Heap::pop_heap(a.begin(), a.end() - i);
  }
  A::print();
}

template <class Heap>
void test_make_heap(vector<A> &a, const size_t n)
{
  cout << "  test_make_heap(" << Heap::name() << "): ";

  init_array(a, n);
  A::reset();
  Heap::make_heap(a.begin(), a.end());
  A::print();
}

template <class Heap>
void test_sort_heap(vector<A> &a, const size_t n)
{
  cout << "  test_sort_heap(" << Heap::name() << "): ";

  init_array(a, n);
  Heap::make_heap(a.begin(), a.end());

  A::reset();
  Heap::sort_heap(a.begin(), a.end());
  A::print();
}

void test_nway_mergesort_avg(vector<A> &a, const size_t n)
{
  cout << "  test_nway_mergesort_avg(" << gtl::name() << "): ";

  typedef galgorithm<gtl::heap> algorithm;

  init_array(a, n);
  A::reset();
  algorithm::nway_mergesort(a.begin(), a.end());
  A::print();
}

void test_nway_mergesort_worst(vector<A> &a, const size_t n)
{
  cout << "  test_nway_mergesort_worst(" << gtl::name() << "): ";

  typedef galgorithm<gtl::heap> algorithm;

  // Simulate worst case for SGI STL sort implementation (aka introsort) -
  // see http://en.wikipedia.org/wiki/Introsort .
  // Actually n-way mergesort must be free of bad cases.
  for (size_t i = 0; i < n; ++i) {
    a[i] = n - i;
  }

  init_array(a, n);
  A::reset();
  algorithm::nway_mergesort(a.begin(), a.end());
  A::print();
}

void test_sort_avg(vector<A> &a, const size_t n)
{
  cout << "  test_sort_avg(" << stl::name() << "): ";

  init_array(a, n);
  A::reset();
  sort(a.begin(), a.end());
  A::print();
}

void test_sort_worst(vector<A> &a, const size_t n)
{
  cout << "  test_sort_worst(" << stl::name() << "): ";

  // Simulate worst case for SGI STL sort implementation (aka introsort) -
  // see http://en.wikipedia.org/wiki/Introsort .
  for (size_t i = 0; i < n; ++i) {
    a[i] = n - i;
  }

  A::reset();
  sort(a.begin(), a.end());
  A::print();
}

}  // end of anonymous namespace

int main()
{
  const size_t N = 1000000;

  cout << "N=" << N << endl;

  vector<A> a;
  a.reserve(N);

  test_push_heap<stl>(a, N);
  test_push_heap<gtl>(a, N);

  test_pop_heap<stl>(a, N);
  test_pop_heap<gtl>(a, N);

  test_make_heap<stl>(a, N);
  test_make_heap<gtl>(a, N);

  test_sort_heap<stl>(a, N);
  test_sort_heap<gtl>(a, N);

  test_nway_mergesort_avg(a, N);
  test_nway_mergesort_worst(a, N);
  test_sort_avg(a, N);
  test_sort_worst(a, N);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, 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 "libtorrent/pch.hpp"

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/bind.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/invariant_check.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/logging.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/hasher.hpp>

#include <fstream>

using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::microsec_clock;
using boost::posix_time::seconds;
using boost::posix_time::milliseconds;
using boost::shared_ptr;
using boost::bind;

namespace libtorrent { namespace dht
{

namespace io = libtorrent::detail;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(rpc)
#endif

node_id generate_id();

rpc_manager::rpc_manager(fun const& f, node_id const& our_id
	, routing_table& table, send_fun const& sf)
	: m_next_transaction_id(rand() % max_transactions)
	, m_oldest_transaction_id(m_next_transaction_id)
	, m_incoming(f)
	, m_send(sf)
	, m_our_id(our_id)
	, m_table(table)
	, m_timer(boost::posix_time::microsec_clock::universal_time())
	, m_random_number(generate_id())
	, m_destructing(false)
{
	std::srand(time(0));
}

rpc_manager::~rpc_manager()
{
	m_destructing = true;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(rpc) << "Destructing";
#endif
	std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
		, bind(&observer::abort, _1));

	for (transactions_t::iterator i = m_transactions.begin()
		, end(m_transactions.end()); i != end; ++i)
	{
		if (*i) (*i)->abort();
	}
}

#ifndef NDEBUG
void rpc_manager::check_invariant() const
{
	assert(m_oldest_transaction_id >= 0);
	assert(m_oldest_transaction_id < max_transactions);
	assert(m_next_transaction_id >= 0);
	assert(m_next_transaction_id < max_transactions);
	assert(!m_transactions[m_next_transaction_id]);

	for (int i = (m_next_transaction_id + 1) % max_transactions;
		i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
	{
		assert(!m_transactions[i]);
	}
}
#endif

bool rpc_manager::incoming(msg const& m)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	if (m.reply)
	{
		// if we don't have the transaction id in our
		// request list, ignore the packet

		if (m.transaction_id.size() != 2)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
				<< m.transaction_id.size() << " from " << m.addr;
#endif
			return false;
		}

		std::string::const_iterator i = m.transaction_id.begin();
		int tid = io::read_uint16(i);

		if (tid >= (int)m_transactions.size()
			|| tid < 0)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		boost::shared_ptr<observer> o = m_transactions[tid];

		if (!o)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		if (m.addr != o->target_addr)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
		reply_stats << m.addr << "\t" << (microsec_clock::universal_time()
			- o->sent).total_milliseconds() << std::endl;
#endif
		o->reply(m);
		m_transactions[tid].reset();

		if (m.piggy_backed_ping)
		{
			// there is a ping request piggy
			// backed in this reply
			msg ph;
			ph.message_id = messages::ping;
			ph.transaction_id = m.ping_transaction_id;
			ph.id = m_our_id;
			ph.addr = m.addr;

			msg empty;

			reply(empty, ph);
		}
		return m_table.node_seen(m.id, m.addr);
	}
	else
	{
		// this is an incoming request
		m_incoming(m);
	}
	return false;
}

time_duration rpc_manager::tick()
{
	INVARIANT_CHECK;

	using boost::posix_time::microsec_clock;

	const int timeout_ms = 10 * 1000;

	//	look for observers that has timed out

	if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms);

	std::vector<shared_ptr<observer> > timeouts;

	for (;m_next_transaction_id != m_oldest_transaction_id;
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
	{
		assert(m_oldest_transaction_id >= 0);
		assert(m_oldest_transaction_id < max_transactions);

		boost::shared_ptr<observer> o = m_transactions[m_oldest_transaction_id];
		if (!o) continue;

		time_duration diff = o->sent + milliseconds(timeout_ms)
			- microsec_clock::universal_time();
		if (diff > seconds(0))
		{
			if (diff < seconds(1)) return seconds(1);
			return diff;
		}

		try
		{
			m_transactions[m_oldest_transaction_id].reset();
			timeouts.push_back(o);
		} catch (std::exception) {}
	}

	std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
	timeouts.clear();

	// clear the aborted transactions, will likely
	// generate new requests. We need to swap, since the
	// destrutors may add more observers to the m_aborted_transactions
	std::vector<shared_ptr<observer> >().swap(m_aborted_transactions);
	return milliseconds(timeout_ms);
}

unsigned int rpc_manager::new_transaction_id(shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	unsigned int tid = m_next_transaction_id;
	m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
	if (m_transactions[m_next_transaction_id])
	{
		// moving the observer into the set of aborted transactions
		// it will prevent it from spawning new requests right now,
		// since that would break the invariant
		m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]);
		m_transactions[m_next_transaction_id].reset();
		assert(m_oldest_transaction_id == m_next_transaction_id);
	}
	assert(!m_transactions[tid]);
	m_transactions[tid] = o;
	if (m_oldest_transaction_id == m_next_transaction_id)
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
			" messages! limit: " << (int)max_transactions;
#endif
		update_oldest_transaction_id();
	}

	return tid;
}

void rpc_manager::update_oldest_transaction_id()
{
	INVARIANT_CHECK;

	assert(m_oldest_transaction_id != m_next_transaction_id);
	while (!m_transactions[m_oldest_transaction_id])
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1)
			% max_transactions;
		if (m_oldest_transaction_id == m_next_transaction_id)
			break;
	}
}

void rpc_manager::invoke(int message_id, udp::endpoint target_addr
	, shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	if (m_destructing)
	{
		o->abort();
		return;
	}

	msg m;
	m.message_id = message_id;
	m.reply = false;
	m.id = m_our_id;
	m.addr = target_addr;
	assert(!m_transactions[m_next_transaction_id]);
	try
	{
		m.transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		o->send(m);

		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = target_addr;

	#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id]
			<< " -> " << target_addr;
	#endif
		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		// m_send may fail with "no route to host"
	}
}

void rpc_manager::reply(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = false;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	m_send(m);
}

namespace
{
	struct dummy_observer : observer
	{
		virtual void reply(msg const&) {}
		virtual void timeout() {}
		virtual void send(msg&) {}
		void abort() {}
	};
}

void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = true;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	try
	{
		m.ping_transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.ping_transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		boost::shared_ptr<observer> o(new dummy_observer);
		assert(!m_transactions[m_next_transaction_id]);
		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = m.addr;

		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		// m_send may fail with "no route to host"
	}
}

} } // namespace libtorrent::dht

<commit_msg>fixed assert caused when network went down<commit_after>/*

Copyright (c) 2006, 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 "libtorrent/pch.hpp"

#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/bind.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/invariant_check.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/logging.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/hasher.hpp>

#include <fstream>

using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::microsec_clock;
using boost::posix_time::seconds;
using boost::posix_time::milliseconds;
using boost::shared_ptr;
using boost::bind;

namespace libtorrent { namespace dht
{

namespace io = libtorrent::detail;

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(rpc)
#endif

node_id generate_id();

rpc_manager::rpc_manager(fun const& f, node_id const& our_id
	, routing_table& table, send_fun const& sf)
	: m_next_transaction_id(rand() % max_transactions)
	, m_oldest_transaction_id(m_next_transaction_id)
	, m_incoming(f)
	, m_send(sf)
	, m_our_id(our_id)
	, m_table(table)
	, m_timer(boost::posix_time::microsec_clock::universal_time())
	, m_random_number(generate_id())
	, m_destructing(false)
{
	std::srand(time(0));
}

rpc_manager::~rpc_manager()
{
	m_destructing = true;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_LOG(rpc) << "Destructing";
#endif
	std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end()
		, bind(&observer::abort, _1));

	for (transactions_t::iterator i = m_transactions.begin()
		, end(m_transactions.end()); i != end; ++i)
	{
		if (*i) (*i)->abort();
	}
}

#ifndef NDEBUG
void rpc_manager::check_invariant() const
{
	assert(m_oldest_transaction_id >= 0);
	assert(m_oldest_transaction_id < max_transactions);
	assert(m_next_transaction_id >= 0);
	assert(m_next_transaction_id < max_transactions);
	assert(!m_transactions[m_next_transaction_id]);

	for (int i = (m_next_transaction_id + 1) % max_transactions;
		i != m_oldest_transaction_id; i = (i + 1) % max_transactions)
	{
		assert(!m_transactions[i]);
	}
}
#endif

bool rpc_manager::incoming(msg const& m)
{
	INVARIANT_CHECK;

	if (m_destructing) return false;

	if (m.reply)
	{
		// if we don't have the transaction id in our
		// request list, ignore the packet

		if (m.transaction_id.size() != 2)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with invalid transaction id size: "
				<< m.transaction_id.size() << " from " << m.addr;
#endif
			return false;
		}

		std::string::const_iterator i = m.transaction_id.begin();
		int tid = io::read_uint16(i);

		if (tid >= (int)m_transactions.size()
			|| tid < 0)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		boost::shared_ptr<observer> o = m_transactions[tid];

		if (!o)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with unknown transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

		if (m.addr != o->target_addr)
		{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			TORRENT_LOG(rpc) << "Reply with incorrect address and valid transaction id: "
				<< tid << " from " << m.addr;
#endif
			return false;
		}

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
		reply_stats << m.addr << "\t" << (microsec_clock::universal_time()
			- o->sent).total_milliseconds() << std::endl;
#endif
		o->reply(m);
		m_transactions[tid].reset();

		if (m.piggy_backed_ping)
		{
			// there is a ping request piggy
			// backed in this reply
			msg ph;
			ph.message_id = messages::ping;
			ph.transaction_id = m.ping_transaction_id;
			ph.id = m_our_id;
			ph.addr = m.addr;

			msg empty;

			reply(empty, ph);
		}
		return m_table.node_seen(m.id, m.addr);
	}
	else
	{
		// this is an incoming request
		m_incoming(m);
	}
	return false;
}

time_duration rpc_manager::tick()
{
	INVARIANT_CHECK;

	using boost::posix_time::microsec_clock;

	const int timeout_ms = 10 * 1000;

	//	look for observers that has timed out

	if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms);

	std::vector<shared_ptr<observer> > timeouts;

	for (;m_next_transaction_id != m_oldest_transaction_id;
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions)
	{
		assert(m_oldest_transaction_id >= 0);
		assert(m_oldest_transaction_id < max_transactions);

		boost::shared_ptr<observer> o = m_transactions[m_oldest_transaction_id];
		if (!o) continue;

		time_duration diff = o->sent + milliseconds(timeout_ms)
			- microsec_clock::universal_time();
		if (diff > seconds(0))
		{
			if (diff < seconds(1)) return seconds(1);
			return diff;
		}

		try
		{
			m_transactions[m_oldest_transaction_id].reset();
			timeouts.push_back(o);
		} catch (std::exception) {}
	}

	std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1));
	timeouts.clear();

	// clear the aborted transactions, will likely
	// generate new requests. We need to swap, since the
	// destrutors may add more observers to the m_aborted_transactions
	std::vector<shared_ptr<observer> >().swap(m_aborted_transactions);
	return milliseconds(timeout_ms);
}

unsigned int rpc_manager::new_transaction_id(shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	unsigned int tid = m_next_transaction_id;
	m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions;
	if (m_transactions[m_next_transaction_id])
	{
		// moving the observer into the set of aborted transactions
		// it will prevent it from spawning new requests right now,
		// since that would break the invariant
		m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]);
		m_transactions[m_next_transaction_id].reset();
		assert(m_oldest_transaction_id == m_next_transaction_id);
	}
	assert(!m_transactions[tid]);
	m_transactions[tid] = o;
	if (m_oldest_transaction_id == m_next_transaction_id)
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "WARNING: transaction limit reached! Too many concurrent"
			" messages! limit: " << (int)max_transactions;
#endif
		update_oldest_transaction_id();
	}

	return tid;
}

void rpc_manager::update_oldest_transaction_id()
{
	INVARIANT_CHECK;

	assert(m_oldest_transaction_id != m_next_transaction_id);
	while (!m_transactions[m_oldest_transaction_id])
	{
		m_oldest_transaction_id = (m_oldest_transaction_id + 1)
			% max_transactions;
		if (m_oldest_transaction_id == m_next_transaction_id)
			break;
	}
}

void rpc_manager::invoke(int message_id, udp::endpoint target_addr
	, shared_ptr<observer> o)
{
	INVARIANT_CHECK;

	if (m_destructing)
	{
		o->abort();
		return;
	}

	msg m;
	m.message_id = message_id;
	m.reply = false;
	m.id = m_our_id;
	m.addr = target_addr;
	assert(!m_transactions[m_next_transaction_id]);
#ifndef NDEBUG
	int potential_new_id = m_next_transaction_id;
#endif
	try
	{
		m.transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		o->send(m);

		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = target_addr;

	#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id]
			<< " -> " << target_addr;
	#endif
		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		// m_send may fail with "no route to host"
		assert(potential_new_id == m_next_transaction_id);
		o->abort();
	}
}

void rpc_manager::reply(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = false;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	m_send(m);
}

namespace
{
	struct dummy_observer : observer
	{
		virtual void reply(msg const&) {}
		virtual void timeout() {}
		virtual void send(msg&) {}
		void abort() {}
	};
}

void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)
{
	INVARIANT_CHECK;

	if (m_destructing) return;

	if (m.message_id != messages::error)
		m.message_id = reply_to.message_id;
	m.addr = reply_to.addr;
	m.reply = true;
	m.piggy_backed_ping = true;
	m.id = m_our_id;
	m.transaction_id = reply_to.transaction_id;

	try
	{
		m.ping_transaction_id.clear();
		std::back_insert_iterator<std::string> out(m.ping_transaction_id);
		io::write_uint16(m_next_transaction_id, out);

		boost::shared_ptr<observer> o(new dummy_observer);
		assert(!m_transactions[m_next_transaction_id]);
		o->sent = boost::posix_time::microsec_clock::universal_time();
		o->target_addr = m.addr;

		m_send(m);
		new_transaction_id(o);
	}
	catch (std::exception& e)
	{
		// m_send may fail with "no route to host"
	}
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_FNV_HPP
#define OUZEL_MATH_FNV_HPP

#include <cstdint>

namespace ouzel
{
    namespace fnv
    {
        template <typename T> T prime;
        template <typename T> T offsetBasis;

        template <> constexpr uint32_t prime<uint32_t> = 16777619u;
        template <> constexpr uint32_t offsetBasis<uint32_t> = 2166136261u;
        template <> constexpr uint64_t prime<uint64_t> = 1099511628211u;
        template <> constexpr uint64_t offsetBasis<uint64_t> = 14695981039346656037u;

        // Fowler / Noll / Vo (FNV) hash
        template <typename Result, typename Value> inline auto hash(const Value value) noexcept
        {
            Result result = offsetBasis<Result>;
            for (size_t i = 0; i < sizeof(Value); ++i)
                result = (result ^ static_cast<uint8_t>(value >> (i * 8))) * prime<Result>;
            return result;
        }
    } // namespace fnv
} // namespace ouzel

#endif // OUZEL_MATH_FNV_HPP
<commit_msg>Make fnv hash constexpr<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_FNV_HPP
#define OUZEL_MATH_FNV_HPP

#include <cstdint>

namespace ouzel
{
    namespace fnv
    {
        template <typename T> T prime;
        template <typename T> T offsetBasis;

        template <> constexpr uint32_t prime<uint32_t> = 16777619u;
        template <> constexpr uint32_t offsetBasis<uint32_t> = 2166136261u;
        template <> constexpr uint64_t prime<uint64_t> = 1099511628211u;
        template <> constexpr uint64_t offsetBasis<uint64_t> = 14695981039346656037u;

        // Fowler / Noll / Vo (FNV) hash
        template <typename Result, typename Value>
        constexpr Result hash(const Value value, size_t i = 0, Result result = offsetBasis<Result>) noexcept
        {
            return (i < sizeof(Value)) ? hash<Result>(value, i + 1, (result * prime<Result>) ^ ((value >> (i * 8)) & 0xFF)) : result;
        }
    } // namespace fnv
} // namespace ouzel

#endif // OUZEL_MATH_FNV_HPP
<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <typeinfo>
#include "../Scene/Scene.hpp"
#include <json/json.h>
#include "../Component/SuperComponent.hpp"

/// %Entity containing various components.
class Entity {
    public:
        /// Create new entity.
        /**
         * @param scene The scene in which the entity is contained.
         */
        Entity(Scene* scene, const std::string& name = "");

        /// Destructor.
        ~Entity();

        /// Adds component with type T.
        /**
         * @return The created component.
         */
        template<typename T> T* AddComponent();

        /// Gets component with type T.
        /**
         * @return The requested component (or nullptr).
         */
        template<typename T> T* GetComponent();

        /// Kill component of type T.
        template <typename T> void KillComponent();

        /// Kill the entity, will be removed at the end of the frame.
        void Kill();

        /// Get whether entity has been killed.
        /**
         * @return Whether the entity has been killed.
         */
        bool IsKilled() const;

        /// Save the entity.
        /**
         * @return JSON value to be stored on disk.
         */
        Json::Value Save() const;

        /// Load entity from JSON node.
        /**
         * @param node JSON node to load from.
         */
        void Load(const Json::Value& node);

        /// Name of the entity.
        std::string name;

    private:
        template<typename T> void Save(Json::Value& node, const std::string& name) const;
        template<typename T> void Load(const Json::Value& node, const std::string& name);

        Scene* scene;

        std::map<const std::type_info*, Component::SuperComponent*> components;

        bool killed = false;
};

template<typename T> T* Entity::AddComponent() {
    const std::type_info* componentType = &typeid(T*);
    if (components.find(componentType) != components.end())
        return nullptr;
    T* component = new T(this);
    components[componentType] = component;
    scene->AddComponent(component, componentType);
    return component;
}

template<typename T> T* Entity::GetComponent() {
    if (components.count(&typeid(T*)) != 0) {
        return static_cast<T*>(components[&typeid(T*)]);
    } else {
        return nullptr;
    }
}

template <typename T> void Entity::KillComponent() {
    const std::type_info* componentType = &typeid(T*);
    if (components.find(componentType) != components.end()) {
        components[componentType]->Kill();
        components.erase(componentType);
    }
}

template<typename T> void Entity::Save(Json::Value& node, const std::string& name) const {
    auto it = components.find(&typeid(T*));
    if (it != components.end())
        node[name] = it->second->Save();
}

template<typename T> void Entity::Load(const Json::Value& node, const std::string& name) {
    Json::Value componentNode = node[name];
    if (!componentNode.isNull()) {
        T* component = AddComponent<T>();
        component->Load(componentNode);
    }
}
<commit_msg>Fix Entity documentation.<commit_after>#pragma once

#include <map>
#include <typeinfo>
#include "../Scene/Scene.hpp"
#include <json/json.h>
#include "../Component/SuperComponent.hpp"

/// %Entity containing various components.
class Entity {
    public:
        /// Create new entity.
        /**
         * @param scene The scene in which the entity is contained.
         * @param name Name of the entity.
         */
        Entity(Scene* scene, const std::string& name = "");

        /// Destructor.
        ~Entity();

        /// Adds component with type T.
        /**
         * @return The created component.
         */
        template<typename T> T* AddComponent();

        /// Gets component with type T.
        /**
         * @return The requested component (or nullptr).
         */
        template<typename T> T* GetComponent();

        /// Kill component of type T.
        template <typename T> void KillComponent();

        /// Kill the entity, will be removed at the end of the frame.
        void Kill();

        /// Get whether entity has been killed.
        /**
         * @return Whether the entity has been killed.
         */
        bool IsKilled() const;

        /// Save the entity.
        /**
         * @return JSON value to be stored on disk.
         */
        Json::Value Save() const;

        /// Load entity from JSON node.
        /**
         * @param node JSON node to load from.
         */
        void Load(const Json::Value& node);

        /// Name of the entity.
        std::string name;

    private:
        template<typename T> void Save(Json::Value& node, const std::string& name) const;
        template<typename T> void Load(const Json::Value& node, const std::string& name);

        Scene* scene;

        std::map<const std::type_info*, Component::SuperComponent*> components;

        bool killed = false;
};

template<typename T> T* Entity::AddComponent() {
    const std::type_info* componentType = &typeid(T*);
    if (components.find(componentType) != components.end())
        return nullptr;
    T* component = new T(this);
    components[componentType] = component;
    scene->AddComponent(component, componentType);
    return component;
}

template<typename T> T* Entity::GetComponent() {
    if (components.count(&typeid(T*)) != 0) {
        return static_cast<T*>(components[&typeid(T*)]);
    } else {
        return nullptr;
    }
}

template <typename T> void Entity::KillComponent() {
    const std::type_info* componentType = &typeid(T*);
    if (components.find(componentType) != components.end()) {
        components[componentType]->Kill();
        components.erase(componentType);
    }
}

template<typename T> void Entity::Save(Json::Value& node, const std::string& name) const {
    auto it = components.find(&typeid(T*));
    if (it != components.end())
        node[name] = it->second->Save();
}

template<typename T> void Entity::Load(const Json::Value& node, const std::string& name) {
    Json::Value componentNode = node[name];
    if (!componentNode.isNull()) {
        T* component = AddComponent<T>();
        component->Load(componentNode);
    }
}
<|endoftext|>


<commit_before>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
// fdostringstream.cc
//

#include "fdostream.h"
#include "ustring.h"
#include "uexception.h"
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>

#ifndef WITHOUT_CIN_COUT_CERR
namespace ustl {

//----------------------------------------------------------------------

fdistringstream cin  (STDIN_FILENO);
fdostringstream cout (STDOUT_FILENO);
fdostringstream cerr (STDERR_FILENO);

//----------------------------------------------------------------------

/// Constructs a stream for writing to \p fd.
fdostringstream::fdostringstream (int fd)
: ostringstream (),
  m_Buffer (255),
  m_Fd (fd),
  m_bEOF (false)
{
    link (m_Buffer);
}

/// Default destructor.
fdostringstream::~fdostringstream (void)
{
    try { flush(); } catch (...) {}
}

/// Flushes the buffer to the file.
void fdostringstream::flush (void)
{
    while (pos() && overflow());
}

/// Called when more buffer space (\p n bytes) is needed.
fdostringstream::size_type fdostringstream::overflow (size_type n)
{
    if (m_bEOF)
	return (ostringstream::overflow (n));
    size_type bw = 0;
    while (!bw) {
	errno = 0;
	ssize_t bwn = ::write (m_Fd, cdata() + bw, pos() - bw);
	if (bwn < 0) {
	    if (errno != EAGAIN && errno != EINTR)
		throw libc_exception ("write");
	} else if (bwn == 0) {
	    m_bEOF = true;
	    break;
	} else
	    bw += bwn;
    }
    erase (begin(), bw);
    if (remaining() < n)
	ostringstream::overflow (n);
    return (remaining());
}

//----------------------------------------------------------------------

/// Constructs a stream to read from \p fd.
fdistringstream::fdistringstream (int fd)
: istringstream (),
  m_Buffer (255),
  m_Fd (fd),
  m_bEOF (false)
{
    link (m_Buffer.data(), 0U);
}

fdistringstream::size_type fdistringstream::underflow (size_type n)
{
    if (m_bEOF)
	return (istringstream::underflow (n));

    const ssize_t freeSpace = m_Buffer.size() - pos();
    const ssize_t neededFreeSpace = max (n, m_Buffer.size() / 2);
    const size_t oughtToErase = Align (max (0, neededFreeSpace - freeSpace));
    const size_t nToErase = min (pos(), oughtToErase);
    m_Buffer.memlink::erase (m_Buffer.begin(), nToErase);
    const uoff_t oldPos (pos() - nToErase);

    size_type br = oldPos;
    if (m_Buffer.size() - br < n) {
	m_Buffer.resize (br + neededFreeSpace);
	link (m_Buffer.data(), 0U);
    }
    while (br - oldPos < n) {
	errno = 0;
	ssize_t brn = ::read (m_Fd, m_Buffer.begin() + br, m_Buffer.size() - br);
	if (brn < 0) {
	    if (errno != EAGAIN && errno != EINTR)
		throw libc_exception ("read");
	} else if (brn == 0) {
	    m_bEOF = true;
	    break;
	} else
	    br += brn;
    }
    m_Buffer[br] = string::c_Terminator;
    link (m_Buffer.data(), br);
    seek (oldPos);
    return (remaining());
}

//----------------------------------------------------------------------

} // namespace ustl
#endif // WITHOUT_CIN_COUT_CERR

<commit_msg>Fixed erroneous eof when flushing an empty stream<commit_after>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
// fdostringstream.cc
//

#include "fdostream.h"
#include "ustring.h"
#include "uexception.h"
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>

#ifndef WITHOUT_CIN_COUT_CERR
namespace ustl {

//----------------------------------------------------------------------

fdistringstream cin  (STDIN_FILENO);
fdostringstream cout (STDOUT_FILENO);
fdostringstream cerr (STDERR_FILENO);

//----------------------------------------------------------------------

/// Constructs a stream for writing to \p fd.
fdostringstream::fdostringstream (int fd)
: ostringstream (),
  m_Buffer (255),
  m_Fd (fd),
  m_bEOF (false)
{
    link (m_Buffer);
}

/// Default destructor.
fdostringstream::~fdostringstream (void)
{
    try { flush(); } catch (...) {}
}

/// Flushes the buffer to the file.
void fdostringstream::flush (void)
{
    while (pos() && overflow (remaining()));
}

/// Called when more buffer space (\p n bytes) is needed.
fdostringstream::size_type fdostringstream::overflow (size_type n)
{
    if (m_bEOF)
	return (ostringstream::overflow (n));
    size_type bw = 0;
    while (!bw) {
	errno = 0;
	ssize_t bwn = ::write (m_Fd, cdata() + bw, pos() - bw);
	if (bwn < 0) {
	    if (errno != EAGAIN && errno != EINTR)
		throw libc_exception ("write");
	} else if (bwn == 0) {
	    if (pos() > bw)
		m_bEOF = true;
	    break;
	} else
	    bw += bwn;
    }
    erase (begin(), bw);
    if (remaining() < n)
	ostringstream::overflow (n);
    return (remaining());
}

//----------------------------------------------------------------------

/// Constructs a stream to read from \p fd.
fdistringstream::fdistringstream (int fd)
: istringstream (),
  m_Buffer (255),
  m_Fd (fd),
  m_bEOF (false)
{
    link (m_Buffer.data(), 0U);
}

fdistringstream::size_type fdistringstream::underflow (size_type n)
{
    if (m_bEOF)
	return (istringstream::underflow (n));

    const ssize_t freeSpace = m_Buffer.size() - pos();
    const ssize_t neededFreeSpace = max (n, m_Buffer.size() / 2);
    const size_t oughtToErase = Align (max (0, neededFreeSpace - freeSpace));
    const size_t nToErase = min (pos(), oughtToErase);
    m_Buffer.memlink::erase (m_Buffer.begin(), nToErase);
    const uoff_t oldPos (pos() - nToErase);

    size_type br = oldPos;
    if (m_Buffer.size() - br < n) {
	m_Buffer.resize (br + neededFreeSpace);
	link (m_Buffer.data(), 0U);
    }
    while (br - oldPos < n) {
	errno = 0;
	ssize_t brn = ::read (m_Fd, m_Buffer.begin() + br, m_Buffer.size() - br);
	if (brn < 0) {
	    if (errno != EAGAIN && errno != EINTR)
		throw libc_exception ("read");
	} else if (brn == 0) {
	    m_bEOF = true;
	    break;
	} else
	    br += brn;
    }
    m_Buffer[br] = string::c_Terminator;
    link (m_Buffer.data(), br);
    seek (oldPos);
    return (remaining());
}

//----------------------------------------------------------------------

} // namespace ustl
#endif // WITHOUT_CIN_COUT_CERR

<|endoftext|>


<commit_before>// Time:  O(nlogf),     n is most recently number of tweets,
//                      f is the number of followings.
// Space: O(u + t + r), u is the number of users,
//                      t is the total number of tweets,
//                      r is the number of followings.

class Twitter {
public:
    /** Initialize your data structure here. */
    Twitter() : time_(0) {

    }

    /** Compose a new tweet. */
    void postTweet(int userId, int tweetId) {
        messages_[userId].emplace_back(make_pair(++time_, tweetId));
    }

    /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
    vector<int> getNewsFeed(int userId) {
        using RIT = deque<pair<size_t, int>>::reverse_iterator;
        priority_queue<tuple<size_t, RIT, RIT>> heap;

        if (messages_[userId].size()) {
            heap.emplace(make_tuple(messages_[userId].rbegin()->first,
                                    messages_[userId].rbegin(),
                                    messages_[userId].rend()));
        }
        for (const auto& id : followings_[userId]) {
            if (messages_[id].size()) {
                heap.emplace(make_tuple(messages_[id].rbegin()->first,
                                        messages_[id].rbegin(),
                                        messages_[id].rend()));
            }
        }
        vector<int> res;
        while (!heap.empty() && res.size() < number_of_most_recent_tweets_) {
            const auto& top = heap.top();
            size_t t;
            RIT begin, end;
            tie(t, begin, end) = top;
            heap.pop();

            auto next = begin + 1;
            if (next != end) {
                heap.emplace(make_tuple(next->first, next, end));
            }

            res.emplace_back(begin->second);
        }
        return res;
    }

    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    void follow(int followerId, int followeeId) {
        if (followerId != followeeId && !followings_[followerId].count(followeeId)) {
            followings_[followerId].emplace(followeeId);
        }
    }

    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
    void unfollow(int followerId, int followeeId) {
        if (followings_[followerId].count(followeeId)) {
            followings_[followerId].erase(followeeId);
        }
    }

private:
    const size_t number_of_most_recent_tweets_ = 10;
    unordered_map<int, unordered_set<int>> followings_;
    unordered_map<int, deque<pair<size_t, int>>> messages_;
    size_t time_;
};

/**
 * Your Twitter object will be instantiated and called as such:
 * Twitter obj = new Twitter();
 * obj.postTweet(userId,tweetId);
 * vector<int> param_2 = obj.getNewsFeed(userId);
 * obj.follow(followerId,followeeId);
 * obj.unfollow(followerId,followeeId);
 */

<commit_msg>Update design-twitter.cpp<commit_after>// Time:  O(nlogf),     n is most recently number of tweets,
//                      f is the number of user's following.
// Space: O(u + t + r), u is the number of users,
//                      t is the total number of tweets,
//                      r is the total number of followings.

class Twitter {
public:
    /** Initialize your data structure here. */
    Twitter() : time_(0) {

    }

    /** Compose a new tweet. */
    void postTweet(int userId, int tweetId) {
        messages_[userId].emplace_back(make_pair(++time_, tweetId));
    }

    /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
    vector<int> getNewsFeed(int userId) {
        using RIT = deque<pair<size_t, int>>::reverse_iterator;
        priority_queue<tuple<size_t, RIT, RIT>> heap;

        if (messages_[userId].size()) {
            heap.emplace(make_tuple(messages_[userId].rbegin()->first,
                                    messages_[userId].rbegin(),
                                    messages_[userId].rend()));
        }
        for (const auto& id : followings_[userId]) {
            if (messages_[id].size()) {
                heap.emplace(make_tuple(messages_[id].rbegin()->first,
                                        messages_[id].rbegin(),
                                        messages_[id].rend()));
            }
        }
        vector<int> res;
        while (!heap.empty() && res.size() < number_of_most_recent_tweets_) {
            const auto& top = heap.top();
            size_t t;
            RIT begin, end;
            tie(t, begin, end) = top;
            heap.pop();

            auto next = begin + 1;
            if (next != end) {
                heap.emplace(make_tuple(next->first, next, end));
            }

            res.emplace_back(begin->second);
        }
        return res;
    }

    /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
    void follow(int followerId, int followeeId) {
        if (followerId != followeeId && !followings_[followerId].count(followeeId)) {
            followings_[followerId].emplace(followeeId);
        }
    }

    /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
    void unfollow(int followerId, int followeeId) {
        if (followings_[followerId].count(followeeId)) {
            followings_[followerId].erase(followeeId);
        }
    }

private:
    const size_t number_of_most_recent_tweets_ = 10;
    unordered_map<int, unordered_set<int>> followings_;
    unordered_map<int, deque<pair<size_t, int>>> messages_;
    size_t time_;
};

/**
 * Your Twitter object will be instantiated and called as such:
 * Twitter obj = new Twitter();
 * obj.postTweet(userId,tweetId);
 * vector<int> param_2 = obj.getNewsFeed(userId);
 * obj.follow(followerId,followeeId);
 * obj.unfollow(followerId,followeeId);
 */

<|endoftext|>


<commit_before>// Time:  O(nlogk)
// Space: O(k)

class Solution {
public:
    vector<int> smallestRange(vector<vector<int>>& nums) {
        using VIT = vector<int>::iterator;

        const auto comp = [](const pair<VIT, VIT>& p1, const pair<VIT, VIT>& p2) {
                              return *p1.first > *p2.first;
                          };

        int left = numeric_limits<int>::max(), right = numeric_limits<int>::min();
        priority_queue<pair<VIT, VIT>, vector<pair<VIT, VIT>>, decltype(comp)> min_heap(comp);
        for (auto &row : nums) {
            left = min(left, row[0]);
            right = max(right, row[0]);
            min_heap.emplace(row.begin(), row.end());
        }

        vector<int> result = {left, right};
        while (!min_heap.empty()) {
            auto p = min_heap.top();
            min_heap.pop();
            ++p.first;
            if (p.first == p.second) {
                break;
            }
            min_heap.emplace(p);

            left = *min_heap.top().first;
            right = max(right, *p.first);
            if (right - left < result[1] - result[0]) {
                result = {left, right};
            }
        }
        return result;
    }
};

<commit_msg>update<commit_after>// Time:  O(nlogk)
// Space: O(k)

class Solution {
public:
    vector<int> smallestRange(vector<vector<int>>& nums) {
        using VIT = vector<int>::iterator;

        const auto comp = [](const pair<VIT, VIT>& p1, const pair<VIT, VIT>& p2) {
                              return *p1.first > *p2.first;
                          };

        int left = numeric_limits<int>::max(), right = numeric_limits<int>::min();
        priority_queue<pair<VIT, VIT>, vector<pair<VIT, VIT>>, decltype(comp)> min_heap(comp);
        for (const auto &row : nums) {
            left = min(left, row[0]);
            right = max(right, row[0]);
            min_heap.emplace(row.begin(), row.end());
        }

        vector<int> result = {left, right};
        while (!min_heap.empty()) {
            auto p = min_heap.top();
            min_heap.pop();
            ++p.first;
            if (p.first == p.second) {
                break;
            }
            min_heap.emplace(p);

            left = *min_heap.top().first;
            right = max(right, *p.first);
            if (right - left < result[1] - result[0]) {
                result = {left, right};
            }
        }
        return result;
    }
};

<|endoftext|>


<commit_before>// Time:  O(m * n * h), h is height of trie
// Space: O(26^h)

class Solution {
private:
    struct TrieNode {
        bool isString = false;
        unordered_map<char, TrieNode *> leaves;

        bool Insert(const string& s) {
            auto* p = this;
            for (const auto& c : s) {
                if (p->leaves.find(c) == p->leaves.cend()) {
                    p->leaves[c] = new TrieNode;
                }
                p = p->leaves[c];
            }

            // s already existed in this trie.
            if (p->isString) {
                return false;
            } else {
                p->isString = true;
                return true;
            }
        }

        ~TrieNode() {
            for (auto& kv : leaves) {
                if (kv.second) {
                    kv.second->~TrieNode();
                }
            }
        }
    };

public:
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
        unordered_set<string> ret;
        vector<vector<bool>> visited(board.size(), vector<bool>(board[0].size(), false));
        string curr;
        TrieNode trie;
        for (const auto& word : words) {
            trie.Insert(word);
        }

        for (int i = 0; i < board.size(); ++i) {
            for (int j = 0; j < board[0].size(); ++j) {
                wordSearchDFS(board, visited, &trie, i, j, curr,  ret);
            }
        }

        return vector<string>(ret.begin(), ret.end());
    }

    void wordSearchDFS(vector<vector<char>> &grid,
             vector<vector<bool>> &visited,
             TrieNode *trie,
             int i,
             int j,
             string curr,
             unordered_set<string> &ret) {
        // Invalid state.
        if (!trie || i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) {
            return;
        }

        // Not in trie or visited.
        if (!trie->leaves[grid[i][j] ] || visited[i][j]) {
            return;
        }

        // Get next trie nodes.
        TrieNode *nextNode = trie->leaves[grid[i][j]];

        // Update current string.
        curr.emplace_back(grid[i][j]);

        // Find the string, add to the answers.
        if (nextNode->isString) {
            ret.insert(curr);
        }

        // Marked as visited.
        visited[i][j] = true;

        // Try each direction.
        vector<pair<int, int>> direction{{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
        for (int k = 0; k < 4; ++k) {
            wordSearchDFS(grid, visited, nextNode,
                          i + direction[k].first, j + direction[k].second, curr, ret);
        }

        visited[i][j] = false;
    }
};
<commit_msg>Update word-search-ii.cpp<commit_after>// Time:  O(m * n * h), h is height of trie
// Space: O(26^h)

class Solution {
private:
    struct TrieNode {
        bool isString = false;
        unordered_map<char, TrieNode *> leaves;

        bool Insert(const string& s) {
            auto* p = this;
            for (const auto& c : s) {
                if (p->leaves.find(c) == p->leaves.cend()) {
                    p->leaves[c] = new TrieNode;
                }
                p = p->leaves[c];
            }

            // s already existed in this trie.
            if (p->isString) {
                return false;
            } else {
                p->isString = true;
                return true;
            }
        }

        ~TrieNode() {
            for (auto& kv : leaves) {
                if (kv.second) {
                    kv.second->~TrieNode();
                }
            }
        }
    };

public:
    /**
     * @param board: A list of lists of character
     * @param words: A list of string
     * @return: A list of string
     */
    vector<string> wordSearchII(vector<vector<char> > &board, vector<string> &words) {
        unordered_set<string> ret;
        vector<vector<bool>> visited(board.size(), vector<bool>(board[0].size(), false));
        string curr;
        TrieNode trie;
        for (const auto& word : words) {
            trie.Insert(word);
        }

        for (int i = 0; i < board.size(); ++i) {
            for (int j = 0; j < board[0].size(); ++j) {
                wordSearchDFS(board, visited, &trie, i, j, curr,  ret);
            }
        }

        return vector<string>(ret.begin(), ret.end());
    }

    void wordSearchDFS(vector<vector<char>> &grid,
             vector<vector<bool>> &visited,
             TrieNode *trie,
             int i,
             int j,
             string curr,
             unordered_set<string> &ret) {
        // Invalid state.
        if (!trie || i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) {
            return;
        }

        // Not in trie or visited.
        if (!trie->leaves[grid[i][j] ] || visited[i][j]) {
            return;
        }

        // Get next trie nodes.
        TrieNode *nextNode = trie->leaves[grid[i][j]];

        // Update current string.
        curr.push_back(grid[i][j]);

        // Find the string, add to the answers.
        if (nextNode->isString) {
            ret.insert(curr);
        }

        // Marked as visited.
        visited[i][j] = true;

        // Try each direction.
        vector<pair<int, int>> direction{{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
        for (int k = 0; k < 4; ++k) {
            wordSearchDFS(grid, visited, nextNode,
                          i + direction[k].first, j + direction[k].second, curr, ret);
        }

        visited[i][j] = false;
    }
};
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <limits>

#include "acmacs-base/size-scale.hh"
#include "acmacs-base/color.hh"
#include "acmacs-chart/layout.hh"

// ----------------------------------------------------------------------

class Surface;

#include "acmacs-base/global-constructors-push.hh"

const Aspect AspectRegular{1.0};
const Aspect AspectEgg{0.75};
const Aspect AspectNoChange{std::numeric_limits<double>::quiet_NaN()};

const Rotation RotationRegular{0.0};
const Rotation RotationReassortant{0.5};
const Rotation RotationNoChange{std::numeric_limits<double>::quiet_NaN()};

#include "acmacs-base/diagnostics-pop.hh"

// ----------------------------------------------------------------------

class PointStyle
{
 public:
    enum class Shown { Hidden, Shown, NoChange };
    enum class Shape { NoChange, Circle, Box, Triangle };
    enum Empty { Empty };

    inline PointStyle()
        : mShown(Shown::Shown), mShape(Shape::Circle), mFill("green"), mOutline("black"),
          mSize(5), mOutlineWidth(1), mAspect(AspectRegular), mRotation(RotationRegular) {}
    inline PointStyle(enum Empty)
        : mShown(Shown::NoChange), mShape(Shape::NoChange), mFill(ColorNoChange), mOutline(ColorNoChange),
          mSize(Pixels::make_empty()), mOutlineWidth(Pixels::make_empty()), mAspect(AspectNoChange), mRotation(RotationNoChange) {}
    inline PointStyle(const PointStyle& aPS) = default;

    inline PointStyle& operator = (const PointStyle& aPS)
        {
            if (aPS.mShown != Shown::NoChange)
                mShown = aPS.mShown;
            if (aPS.mShape != Shape::NoChange)
                mShape = aPS.mShape;
            if (!aPS.mFill.empty())
                mFill = aPS.mFill;
            if (!aPS.mOutline.empty())
                mOutline = aPS.mOutline;
            if (!aPS.mSize.empty())
                mSize = aPS.mSize;
            if (!aPS.mOutlineWidth.empty())
                mOutlineWidth = aPS.mOutlineWidth;
            if (!aPS.mAspect.empty())
                mAspect = aPS.mAspect;
            if (!aPS.mRotation.empty())
                mRotation = aPS.mRotation;
            return *this;
        }

    void draw(Surface& aSurface, const Coordinates& aCoord);

    inline PointStyle& show(Shown aShown = Shown::Shown) { mShown = aShown; return *this; }
    inline PointStyle& hide() { mShown = Shown::Hidden; return *this; }
    inline PointStyle& shape(Shape aShape) { mShape = aShape; return *this; }
    inline PointStyle& fill(Color c) { mFill = c; return *this; }
    inline PointStyle& outline(Color c) { mOutline = c; return *this; }
    inline PointStyle& size(Pixels aSize) { mSize = aSize; return *this; }
    inline PointStyle& outline_width(Pixels aOutlineWidth) { mOutlineWidth = aOutlineWidth; return *this; }
    inline PointStyle& aspect(Aspect aAspect) { mAspect = aAspect; return *this; }
    inline PointStyle& aspect(double aAspect) { mAspect = aAspect; return *this; }
    inline PointStyle& rotation(Rotation aRotation) { mRotation = aRotation; return *this; }
    inline PointStyle& rotation(double aRotation) { mRotation = aRotation; return *this; }

    inline PointStyle& scale(double aScale) { mSize *= aScale; return *this; }
    inline PointStyle& scale_outline(double aScale) { mOutlineWidth *= aScale; return *this; }

    inline bool shown() const { return mShown == Shown::Shown; }
    inline Shape shape() const { return mShape; }
    inline Pixels size() const { return mSize; }
    inline std::string fill() const { return mFill.to_string(); }
    inline std::string outline() const { return mOutline.to_string(); }
    inline std::string fill_hex() const { return mFill.to_hex_string(); }
    inline std::string outline_hex() const { return mOutline.to_hex_string(); }
    inline Pixels outline_width() const { return mOutlineWidth; }
    inline Aspect aspect() const { return mAspect; }
    inline Rotation rotation() const { return mRotation; }

    inline Shown shown_raw() const { return mShown; }
    inline Color fill_raw() const { return mFill; }
    inline Color outline_raw() const { return mOutline; }

 private:
    Shown mShown;
    Shape mShape;
    Color mFill;
    Color mOutline;
    Pixels mSize;
    Pixels mOutlineWidth;
    Aspect mAspect;
    Rotation mRotation;

}; // class PointStyle

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>point style improvement<commit_after>#pragma once

#include <string>
#include <limits>

#include "acmacs-base/size-scale.hh"
#include "acmacs-base/color.hh"
#include "acmacs-chart/layout.hh"

// ----------------------------------------------------------------------

class Surface;

#include "acmacs-base/global-constructors-push.hh"

const Aspect AspectRegular{1.0};
const Aspect AspectEgg{0.75};
const Aspect AspectNoChange{std::numeric_limits<double>::quiet_NaN()};

const Rotation RotationRegular{0.0};
const Rotation RotationReassortant{0.5};
const Rotation RotationNoChange{std::numeric_limits<double>::quiet_NaN()};

#include "acmacs-base/diagnostics-pop.hh"

// ----------------------------------------------------------------------

class PointStyle
{
 public:
    enum class Shown { Hidden, Shown, NoChange };
    enum class Shape { NoChange, Circle, Box, Triangle };
    enum Empty { Empty };

    inline PointStyle()
        : mShown(Shown::Shown), mShape(Shape::Circle), mFill("green"), mOutline("black"),
          mSize(5), mOutlineWidth(1), mAspect(AspectRegular), mRotation(RotationRegular) {}
    inline PointStyle(enum Empty)
        : mShown(Shown::NoChange), mShape(Shape::NoChange), mFill(ColorNoChange), mOutline(ColorNoChange),
          mSize(Pixels::make_empty()), mOutlineWidth(Pixels::make_empty()), mAspect(AspectNoChange), mRotation(RotationNoChange) {}
    inline PointStyle(const PointStyle& aPS) = default;

    inline PointStyle& operator = (const PointStyle& aPS)
        {
            if (aPS.mShown != Shown::NoChange)
                mShown = aPS.mShown;
            if (aPS.mShape != Shape::NoChange)
                mShape = aPS.mShape;
            if (!aPS.mFill.empty())
                mFill = aPS.mFill;
            if (!aPS.mOutline.empty())
                mOutline = aPS.mOutline;
            if (!aPS.mSize.empty())
                mSize = aPS.mSize;
            if (!aPS.mOutlineWidth.empty())
                mOutlineWidth = aPS.mOutlineWidth;
            if (!aPS.mAspect.empty())
                mAspect = aPS.mAspect;
            if (!aPS.mRotation.empty())
                mRotation = aPS.mRotation;
            return *this;
        }

    void draw(Surface& aSurface, const Coordinates& aCoord);

    inline PointStyle& show(Shown aShown = Shown::Shown) { mShown = aShown; return *this; }
    inline PointStyle& hide() { mShown = Shown::Hidden; return *this; }
    inline PointStyle& shape(Shape aShape) { mShape = aShape; return *this; }
    inline PointStyle& shape(std::string aShape) { if (aShape == "circle") shape(Shape::Circle); else if (aShape == "box") shape(Shape::Box); else if (aShape == "triangle") shape(Shape::Triangle); else throw std::runtime_error("Unrecognized point style shape: " + aShape); return *this; }
    inline PointStyle& fill(Color c) { mFill = c; return *this; }
    inline PointStyle& outline(Color c) { mOutline = c; return *this; }
    inline PointStyle& size(Pixels aSize) { mSize = aSize; return *this; }
    inline PointStyle& outline_width(Pixels aOutlineWidth) { mOutlineWidth = aOutlineWidth; return *this; }
    inline PointStyle& aspect(Aspect aAspect) { mAspect = aAspect; return *this; }
    inline PointStyle& aspect(double aAspect) { mAspect = aAspect; return *this; }
    inline PointStyle& rotation(Rotation aRotation) { mRotation = aRotation; return *this; }
    inline PointStyle& rotation(double aRotation) { mRotation = aRotation; return *this; }

    inline PointStyle& scale(double aScale) { mSize *= aScale; return *this; }
    inline PointStyle& scale_outline(double aScale) { mOutlineWidth *= aScale; return *this; }

    inline bool shown() const { return mShown == Shown::Shown; }
    inline Shape shape() const { return mShape; }
    inline Pixels size() const { return mSize; }
    inline std::string fill() const { return mFill.to_string(); }
    inline std::string outline() const { return mOutline.to_string(); }
    inline std::string fill_hex() const { return mFill.to_hex_string(); }
    inline std::string outline_hex() const { return mOutline.to_hex_string(); }
    inline Pixels outline_width() const { return mOutlineWidth; }
    inline Aspect aspect() const { return mAspect; }
    inline Rotation rotation() const { return mRotation; }

    inline Shown shown_raw() const { return mShown; }
    inline Color fill_raw() const { return mFill; }
    inline Color outline_raw() const { return mOutline; }

 private:
    Shown mShown;
    Shape mShape;
    Color mFill;
    Color mOutline;
    Pixels mSize;
    Pixels mOutlineWidth;
    Aspect mAspect;
    Rotation mRotation;

}; // class PointStyle

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>