text:
/**
 * Copyright (c) 2009 Carnegie Mellon University.
 *     All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS
 *  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied.  See the License for the specific language
 *  governing permissions and limitations under the License.
 *
 * For more about this software visit:
 *
 *      http://www.graphlab.ml.cmu.edu
 *
 */

#include <graphlab/rpc/dc.hpp>

#ifndef GRAPHLAB_DC_DIST_OBJECT_HPP
#define GRAPHLAB_DC_DIST_OBJECT_HPP
#include <vector>
#include <string>
#include <set>
#include <graphlab/parallel/atomic.hpp>
#include <graphlab/rpc/dc_internal_types.hpp>
#include <graphlab/rpc/dc_dist_object_base.hpp>
#include <graphlab/rpc/object_request_issue.hpp>
#include <graphlab/rpc/object_call_issue.hpp>
#include <graphlab/rpc/function_ret_type.hpp>
#include <graphlab/rpc/mem_function_arg_types_def.hpp>
#include <graphlab/util/charstream.hpp>
#include <boost/preprocessor.hpp>
#include <graphlab/macros_def.hpp>

#define BARRIER_BRANCH_FACTOR 128

namespace graphlab {

/**
\ingroup rpc
Provides capabilities for distributed objects Your class should either
inherit this, or instantiate it before any distributed object call.
The requirement for using the distributed object is that all machines
must construct the distributed objects in the same order. And, no
distributed object calls should be make until it is guaranteed that
all machines have constructed their respective distributed objects.

This class also acts as a single "context" spanning multiple machines.
For instance, the barrier implemented here is fully localized to within
a particular instance of this object. That is, multiple instances of the object
can issue multiple independent barriers.
The dc_services() object is a thin wrapper around the dc_dist_object.

This class implements several MPI-like primitive ops such as
barrier, gather, broadcast, etc. These operations are not particular optimized
and can be quite inefficient.
*/
template <typename T>
class dc_dist_object : public dc_impl::dc_dist_object_base{
 private:
  distributed_control &dc_;
  size_t obj_id;
  size_t control_obj_id;  // object id of this object
  T* owner;
  bool calltracking;
  std::vector<atomic<size_t> > callsreceived;
  std::vector<atomic<size_t> > callssent;
  std::vector<atomic<size_t> > bytessent;
  // make operator= private
  dc_dist_object<T>& operator=(const dc_dist_object<T> &d) {return *this;}
  friend class distributed_control;

 public:
  /// Should not be used by the user
  void inc_calls_received(procid_t p) {
    if (!full_barrier_in_effect) {
        callsreceived[p].inc();
        if (full_barrier_in_effect) {
          if (callsreceived[p].inc() == calls_to_receive[p]) {
            // if it was me who set the bit
            if (procs_complete.set_bit(p) == false) {
              // then decrement the incomplete count.
              // if it was me to decreased it to 0
              // lock and signal
              full_barrier_lock.lock();
              if (num_proc_recvs_incomplete.dec() == 0) {
                full_barrier_cond.signal();
              }
              full_barrier_lock.unlock();
            }
          }
        }
    }
    else {
      //check the proc I just incremented.
      // If I just exceeded the required size, I need
      // to decrement the full barrier counter
      if (callsreceived[p].inc() == calls_to_receive[p]) {
        // if it was me who set the bit
        if (procs_complete.set_bit(p) == false) {
          // then decrement the incomplete count.
          // if it was me to decreased it to 0
          // lock and signal
          full_barrier_lock.lock();
          if (num_proc_recvs_incomplete.dec() == 0) {
            full_barrier_cond.signal();
          }
          full_barrier_lock.unlock();
        }
      }
    }
  }

  /// Should not be used by the user
  void inc_calls_sent(procid_t p) {
    callssent[p].inc();
  }

  /// Should not be used by the user
  void inc_bytes_sent(procid_t p, size_t bytes) {
    bytessent[p].inc(bytes);
  }

 public:
  dc_dist_object(distributed_control &dc_, T* owner, bool calltracking = false):
    dc_(dc_),owner(owner),calltracking(calltracking) {
    callssent.resize(dc_.numprocs());
    callsreceived.resize(dc_.numprocs());
    bytessent.resize(dc_.numprocs());
    //------ Initialize the matched send/recv ------
    recv_froms.resize(dc_.numprocs());

    //------ Initialize the gatherer ------
    gather_receive.resize(dc_.numprocs());

    //------- Initialize the Barrier ----------
    child_barrier_counter.value = 0;
    barrier_sense = 1;
    barrier_release = -1;

    // compute my children
    childbase = size_t(dc_.procid()) * BARRIER_BRANCH_FACTOR + 1;
    if (childbase >= dc_.numprocs()) {
      numchild = 0;
    }
    else {
      size_t maxchild = std::min<size_t>(dc_.numprocs(),
                                         childbase + BARRIER_BRANCH_FACTOR);
      numchild = (procid_t)(maxchild - childbase);
    }

    parent =  (procid_t)((dc_.procid() - 1) / BARRIER_BRANCH_FACTOR)   ;

    //-------- Initialize all gather --------------
    ab_child_barrier_counter.value = 0;
    ab_barrier_sense = 1;
    ab_barrier_release = -1;

    //-------- Initialize the full barrier ---------

    full_barrier_in_effect = false;
    procs_complete.resize(dc_.numprocs());

    // register
    obj_id = dc_.register_object(owner, this);
    control_obj_id = dc_.register_object(this, this);
  }

  /// The number of function calls received by this object
  size_t calls_received() const {
    size_t ctr = 0;
    for (size_t i = 0;i < numprocs(); ++i) {
      ctr += callsreceived[i].value;
    }
    return ctr;
  }

  /// The number of function calls send from this object
  size_t calls_sent() const {
    size_t ctr = 0;
    for (size_t i = 0;i < numprocs(); ++i) {
      ctr += callssent[i].value;
    }
    return ctr;
  }

  size_t bytes_sent() const {
    size_t ctr = 0;
    for (size_t i = 0;i < numprocs(); ++i) {
      ctr += bytessent[i].value;
    }
    return ctr;
  }

  /// A reference to the underlying dc
  distributed_control& dc() {
    return dc_;
  }

  /// A reference to the underlying dc
  const distributed_control& dc() const {
    return dc_;
  }

  /// The current process ID
  inline procid_t procid() const {
    return dc_.procid();
  }

  /// The number of processes in the distributed program.
  inline procid_t numprocs() const {
    return dc_.numprocs();
  }

  /**
   This comm barrier is not a true "barrier" but is
   essentially a sequentialization point. It guarantees that
   all calls from this machine to the target machine performed
   before the comm_barrier() call are completed before any call
   sent after the comm barrier() call.

    \note This affects the global context
  */
  inline void comm_barrier(procid_t targetmachine) {
    return dc_.comm_barrier(targetmachine);
  }
  /**
    This is a convenience function which broadcasts a comm_barrier()
    \note having all machines call the comm barrier does not guarantee
    that all calls have been processed. Basically 'p' local barriers
    do not result in a global barrier.

    \note This affects the global context
  */
  inline void comm_barrier() {
    return dc_.comm_barrier();
  }

  /**
    This returns the set of services for the parent DC.
    This is deprecated. Use dc() to get access to the global context
  */
   __attribute__((__deprecated__)) inline dc_services& services() {
    return dc_.services();
  }

    /*
  This generates the interface functions for the standard calls, basic calls, and fast calls
  The function looks like this:
  \code
  template<typename F , typename T0> void remote_call (procid_t target, F remote_function , T0 i0 )
  {
      ASSERT_LT(target, dc_.senders.size());
      if ((STANDARD_CALL & CONTROL_PACKET) == 0) inc_calls_sent(target);
      dc_impl::object_call_issue1 <T, F , T0> ::exec(dc_.senders[target],
                                                      STANDARD_CALL,
                                                      target,obj_id,
                                                      remote_function ,
                                                      i0 );
  }

  The argument to the RPC_INTERFACE_GENERATOR are:
    - the name of the rpc call ("remote_call" in the first one)
    - the name of the issueing processor ("object_call_issue")
    - The flags to set on the call ("STANDARD_CALL")

    The call can be issued with
    rmi.remote_call(target,
                    &object_type::function_name,
                    arg1,
                    arg2...)
  \endcode
  */
  #define GENARGS(Z,N,_)  BOOST_PP_CAT(T, N) BOOST_PP_CAT(i, N)
  #define GENI(Z,N,_) BOOST_PP_CAT(i, N)
  #define GENT(Z,N,_) BOOST_PP_CAT(T, N)
  #define GENARC(Z,N,_) arc << BOOST_PP_CAT(i, N);

  #define RPC_INTERFACE_GENERATOR(Z,N,FNAME_AND_CALL) \
  template<typename F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
  void  BOOST_PP_TUPLE_ELEM(3,0,FNAME_AND_CALL) (procid_t target, F remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_) ) {  \
    ASSERT_LT(target, dc_.senders.size()); \
    if ((BOOST_PP_TUPLE_ELEM(3,2,FNAME_AND_CALL) & CONTROL_PACKET) == 0) inc_calls_sent(target); \
    BOOST_PP_CAT( BOOST_PP_TUPLE_ELEM(3,1,FNAME_AND_CALL),N) \
        <T, F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, T)> \
          ::exec(this, dc_.senders[target],  BOOST_PP_TUPLE_ELEM(3,2,FNAME_AND_CALL), target,obj_id, remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENI ,_) ); \
  }   \

  /*
  Generates the interface functions. 3rd argument is a tuple (interface name, issue name, flags)
  */
  BOOST_PP_REPEAT(7, RPC_INTERFACE_GENERATOR, (remote_call, dc_impl::object_call_issue, STANDARD_CALL) )
  BOOST_PP_REPEAT(7, RPC_INTERFACE_GENERATOR, (fast_remote_call,dc_impl::object_call_issue, FAST_CALL) )
  BOOST_PP_REPEAT(7, RPC_INTERFACE_GENERATOR, (control_call,dc_impl::object_call_issue, (FAST_CALL | CONTROL_PACKET)) )

  /*
  The generation procedure for requests are the same. The only
  difference is that the function name has to be changed a little to
  be identify the return type of the function, (typename
  dc_impl::function_ret_type<__GLRPC_FRESULT>) and the issuing
  processor is object_request_issue.

    The call can be issued with
    \code
    ret = rmi.remote_request(target,
                              &object_type::function_name,
                              arg1,
                              arg2...)
    \endcode
  */
  #define REQUEST_INTERFACE_GENERATOR(Z,N,ARGS) \
  template<typename F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
    BOOST_PP_TUPLE_ELEM(3,0,ARGS) (procid_t target, F remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_) ) {  \
    ASSERT_LT(target, dc_.senders.size()); \
    if ((BOOST_PP_TUPLE_ELEM(3,2,ARGS) & CONTROL_PACKET) == 0) inc_calls_sent(target); \
    return BOOST_PP_CAT( BOOST_PP_TUPLE_ELEM(3,1,ARGS),N) \
        <T, F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, T)> \
          ::exec(this, dc_.senders[target],  BOOST_PP_TUPLE_ELEM(3,2,ARGS), target,obj_id, remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENI ,_) ); \
  }   \

  /**
  Generates the interface functions. 3rd argument is a tuple
  (interface name, issue name, flags)
  */
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type remote_request, dc_impl::object_request_issue, STANDARD_CALL) )
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type fast_remote_request, dc_impl::object_request_issue, FAST_CALL) )
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type control_request, dc_impl::object_request_issue, (FAST_CALL | CONTROL_PACKET)) )

  #undef RPC_INTERFACE_GENERATOR
  #undef REQUEST_INTERFACE_GENERATOR

  /* Now generate the interface functions which allow me to call this
  dc_dist_object directly The internal calls are similar to the ones
  above. The only difference is that is that instead of 'obj_id', the
  parameter passed to the issue processor is "control_obj_id" which
  identifies the current RMI class.
  */
  #define RPC_INTERFACE_GENERATOR(Z,N,FNAME_AND_CALL) \
  template<typename F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
  void  BOOST_PP_TUPLE_ELEM(3,0,FNAME_AND_CALL) (procid_t target, F remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_) ) {  \
    ASSERT_LT(target, dc_.senders.size()); \
    if ((BOOST_PP_TUPLE_ELEM(3,2,FNAME_AND_CALL) & CONTROL_PACKET) == 0) inc_calls_sent(target); \
    BOOST_PP_CAT( BOOST_PP_TUPLE_ELEM(3,1,FNAME_AND_CALL),N) \
        <dc_dist_object<T>, F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, T)> \
          ::exec(this, dc_.senders[target],  BOOST_PP_TUPLE_ELEM(3,2,FNAME_AND_CALL), target,control_obj_id, remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENI ,_) ); \
  }   \

  BOOST_PP_REPEAT(6, RPC_INTERFACE_GENERATOR, (internal_call,dc_impl::object_call_issue, STANDARD_CALL) )
  BOOST_PP_REPEAT(6, RPC_INTERFACE_GENERATOR, (internal_fast_call,dc_impl::object_call_issue, FAST_CALL) )
  BOOST_PP_REPEAT(6, RPC_INTERFACE_GENERATOR, (internal_control_call,dc_impl::object_call_issue, (FAST_CALL | CONTROL_PACKET)) )

  #define REQUEST_INTERFACE_GENERATOR(Z,N,ARGS) \
  template<typename F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
    BOOST_PP_TUPLE_ELEM(3,0,ARGS) (procid_t target, F remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_) ) {  \
    ASSERT_LT(target, dc_.senders.size()); \
    if ((BOOST_PP_TUPLE_ELEM(3,2,ARGS) & CONTROL_PACKET) == 0) inc_calls_sent(target); \
    return BOOST_PP_CAT( BOOST_PP_TUPLE_ELEM(3,1,ARGS),N) \
        <dc_dist_object<T>, F BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, T)> \
          ::exec(this, dc_.senders[target],  BOOST_PP_TUPLE_ELEM(3,2,ARGS), target,control_obj_id, remote_function BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENI ,_) ); \
  }   \

  /*
  Generates the interface functions. 3rd argument is a tuple (interface name, issue name, flags)
  */
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type internal_request, dc_impl::object_request_issue, STANDARD_CALL) )
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type internal_fast_request, dc_impl::object_request_issue, FAST_CALL) )
  BOOST_PP_REPEAT(6, REQUEST_INTERFACE_GENERATOR, (typename dc_impl::function_ret_type<__GLRPC_FRESULT>::type internal_control_request, dc_impl::object_request_issue, (FAST_CALL | CONTROL_PACKET)) )

  #undef RPC_INTERFACE_GENERATOR
  #undef REQUEST_INTERFACE_GENERATOR
  #undef GENARC
  #undef GENT
  #undef GENI
  #undef GENARGS

/*****************************************************************************
                      Implementation of matched send_to / recv_from
 *****************************************************************************/

 private:
  std::vector<dc_impl::recv_from_struct> recv_froms;

  void block_and_wait_for_recv(size_t src,
                             std::string& str,
                             size_t tag) {
    recv_froms[src].lock.lock();
    recv_froms[src].data = str;
    recv_froms[src].tag = tag;
    recv_froms[src].hasdata = true;
    recv_froms[src].cond.signal();
    recv_froms[src].lock.unlock();
  }

 public:

  /**
  This is a blocking send_to. It send an object T to the target
  machine, but waits for the target machine to call recv_from
  before returning. Functionally similar to MPI's matched sending/receiving
  */
  template <typename U>
  void send_to(procid_t target, U& t, bool control = false) {
    std::stringstream strm;
    oarchive oarc(strm);
    oarc << t;
    strm.flush();
    dc_impl::reply_ret_type rt(REQUEST_WAIT_METHOD);
    // I shouldn't use a request to block here since
    // that will take up a thread on the remote side
    // so I simulate a request here.
    size_t rtptr = reinterpret_cast<size_t>(&rt);
    if (control == false) {
      internal_call(target, &dc_dist_object<T>::block_and_wait_for_recv,
                     procid(), strm.str(), rtptr);
    }
    else {
      internal_control_call(target, &dc_dist_object<T>::block_and_wait_for_recv,
                  procid(), strm.str(), rtptr);
    }
    // wait for reply
    rt.wait();

    if (control == false) inc_calls_received(target);
  }

  /**
  A blocking recv_from. Must be matched with a send_to call from the
  target before both source and target resumes.
  */
  template <typename U>
  void recv_from(procid_t source, U& t, bool control = false) {
    // wait on the condition variable until I have data
    dc_impl::recv_from_struct &recvstruct = recv_froms[source];
    recvstruct.lock.lock();
    while (recvstruct.hasdata == false) {
      recvstruct.cond.wait(recvstruct.lock);
    }

    // got the data. deserialize it
    std::stringstream strm(recvstruct.data);
    iarchive iarc(strm);
    iarc >> t;
    // clear the data
    std::string("").swap(recvstruct.data);
    // remember the tag so we can unlock it before the remote call
    size_t tag = recvstruct.tag;
    // clear the has data flag
    recvstruct.hasdata = false;
    // unlock
    recvstruct.lock.unlock();
    if (control == false) {
      // remote call to release the sender. Use an empty blob
      dc_.fast_remote_call(source, reply_increment_counter, tag, dc_impl::blob());
      // I have to increment the calls sent manually here
      // since the matched send/recv calls do not go through the
      // typical object calls. It goes through the DC, but I also want to charge
      // it to this object
      inc_calls_sent(source);
    }
    else {
      dc_.control_call(source, reply_increment_counter, tag, dc_impl::blob());
    }
  }

/*****************************************************************************
                      Implementation of Broadcast
 *****************************************************************************/

private:

  std::string broadcast_receive;

  void set_broadcast_receive(const std::string &s) {
    broadcast_receive = s;
  }

 public:

  /**
     This function allows one machine to broadcasts a variable to all machines.

     The originator calls broadcast with data provided in
     in 'data' and originator set to true.
     All other callers call with originator set to false.

     The originator will then return 'data'. All other machines
     will receive the originator's transmission in the "data" parameter.

     This call is guaranteed to have barrier-like behavior. That is to say,
     this call will block until all machines enter the broadcast function.

     \note Behavior is undefined if more than one machine calls broadcast
     with originator set to true.

     \note Behavior is undefined if multiple threads on the same machine
     call broadcast simultaneously. If multiple-thread broadcast is necessary,
     each thread should use its own instance of the services class.
  */
  template <typename U>
  void broadcast(U& data, bool originator, bool control = false) {
    if (originator) {
      // construct the data stream
      std::stringstream strm;
      oarchive oarc(strm);
      oarc << data;
      strm.flush();
      broadcast_receive = strm.str();
      if (control == false) {
        for (size_t i = 0;i < numprocs(); ++i) {
          if (i != procid()) {
            internal_request(i,
                            &dc_dist_object<T>::set_broadcast_receive,
                            broadcast_receive);
          }
        }
      }
      else {
        for (size_t i = 0;i < numprocs(); ++i) {
          if (i != procid()) {
            internal_control_request(i,
                                    &dc_dist_object<T>::set_broadcast_receive,
                                    broadcast_receive);
          }
        }
      }
    }

    // by the time originator gets here, all machines
    // will have received the data due to the broadcast_receive
    // set a barrier here.
    barrier();

    // all machines will now deserialize the data
    if (!originator) {
      std::stringstream strm(broadcast_receive);
      iarchive iarc(strm);
      iarc >> data;
    }
  }

/*****************************************************************************
      Implementation of Gather, all_gather and gather_partition
 *****************************************************************************/

 private:
  std::vector<std::string> gather_receive;
  atomic<size_t> gatherid;

  void set_gather_receive(procid_t source, const std::string &s, size_t gid) {
    while(gatherid.value != gid) sched_yield();
    gather_receive[source] = s;
  }
 public:
  /**
   * Collects information contributed by each machine onto
   * one machine.
   * data must be of length data[numprocs].
   * My data is stored in data[dc.procid()].
   * when function returns, machine sendto will have the complete vector
   * where data[i] is the data contributed by machine i.
   * All machines must have the same parameter for "sendto"
   */
  template <typename U>
  void gather(std::vector<U>& data, procid_t sendto, bool control = false) {
    // if not root
    if (sendto != procid()) {
      std::stringstream strm( std::ios::out | std::ios::binary );
      oarchive oarc(strm);
      oarc << data[procid()];
      strm.flush();
      if (control == false) {
        internal_request(sendto,
                        &dc_dist_object<T>::set_gather_receive,
                        procid(),
                        strm.str(),
                        gatherid.value);
      }
      else {
        internal_control_request(sendto,
                                  &dc_dist_object<T>::set_gather_receive,
                                  procid(),
                                  strm.str(),
                                  gatherid.value);
      }
    }
    barrier();
    if (sendto == procid()) {
      // if I am the receiver
      for (procid_t i = 0; i < numprocs(); ++i) {
        if (i != procid()) {
          // receiving only from others
          std::stringstream strm(gather_receive[i],
                                 std::ios::in | std::ios::binary);
          assert(strm.good());
          iarchive iarc(strm);
          iarc >> data[i];
        }
      }
    }
    gatherid.inc();

  }

/********************************************************************
             Implementation of all gather
*********************************************************************/

 private:
  // ------- Sense reversing barrier data ----------
  /// The next value of the barrier. either +1 or -1
  int ab_barrier_sense;
  /// When this flag == the current barrier value. The barrier is complete
  int ab_barrier_release;
  /** when barrier sense is 1, barrier clears when
   * child_barrier_counter == numchild. When barrier sense is -1, barrier
   * clears when child_barrier_counter == 0;
   */
  atomic<int> ab_child_barrier_counter;
  /// condition variable and mutex protecting the barrier variables
  conditional ab_barrier_cond;
  mutex ab_barrier_mut;
  std::string ab_children_data[BARRIER_BRANCH_FACTOR];
  std::string ab_alldata;

  /**
    The child calls this function in the parent once the child enters the barrier
  */
  void __ab_child_to_parent_barrier_trigger(procid_t source, std::string collect) {
    ab_barrier_mut.lock();
    // assert childbase <= source <= childbase + BARRIER_BRANCH_FACTOR
    ASSERT_GE(source, childbase);
    ASSERT_LT(source, childbase + BARRIER_BRANCH_FACTOR);
    ab_children_data[source - childbase] = collect;
    ab_child_barrier_counter.inc(ab_barrier_sense);
    ab_barrier_cond.signal();
    ab_barrier_mut.unlock();
  }

  /**
    This is on the downward pass of the barrier. The parent calls this function
    to release all the children's barriers
  */
  void __ab_parent_to_child_barrier_release(int releaseval,
                                            std::string allstrings,
                                            int use_control_calls) {
    // send the release downwards
    // get my largest child
    ab_alldata = allstrings;
    for (procid_t i = 0;i < numchild; ++i) {
      if (use_control_calls) {
        internal_control_call((procid_t)(childbase + i),
                              &dc_dist_object<T>::__ab_parent_to_child_barrier_release,
                              releaseval,
                              ab_alldata,
                              use_control_calls);
      }
      else {
        internal_call((procid_t)(childbase + i),
                      &dc_dist_object<T>::__ab_parent_to_child_barrier_release,
                      releaseval,
                      ab_alldata,
                      use_control_calls);
      }
    }
    ab_barrier_mut.lock();
    ab_barrier_release = releaseval;
    ab_barrier_cond.signal();
    ab_barrier_mut.unlock();
  }

 public:

  /**
   * Each machine creates a vector 'data' with size equivalent to the number of machines.
   * Each machine then fills the entry data[procid()] with information that it
   * wishes to communicate.
   * After calling all_gather(), all machines will return with identical
   * vectors 'data', where data[i] contains the information machine i stored.
   */
  template <typename U>
  void all_gather(std::vector<U>& data, bool control = false) {
    if (numprocs() == 1) return;
    // get the string representation of the data
    charstream strm(128);
    oarchive oarc(strm);
    oarc << data[procid()];
    strm.flush();
    // upward message
    int ab_barrier_val = ab_barrier_sense;
    ab_barrier_mut.lock();
    // wait for all children to be done
    while(1) {
      if ((ab_barrier_sense == -1 && ab_child_barrier_counter.value == 0) ||
          (ab_barrier_sense == 1 && ab_child_barrier_counter.value == (int)(numchild))) {
        // flip the barrier sense
        ab_barrier_sense = -ab_barrier_sense;
        // call child to parent in parent
        ab_barrier_mut.unlock();
        if (procid() != 0) {
          // collect all my children data
          charstream strstrm(128);
          oarchive oarc2(strstrm);
          oarc2 << std::string(strm->c_str(), strm->size());
          for (procid_t i = 0;i < numchild; ++i) {
            strstrm.write(ab_children_data[i].c_str(), ab_children_data[i].length());
          }
          strstrm.flush();
          if (control) {
            internal_control_call(parent,
                            &dc_dist_object<T>::__ab_child_to_parent_barrier_trigger,
                            procid(),
                            std::string(strstrm->c_str(), strstrm->size()));
          }
          else {
            internal_call(parent,
                          &dc_dist_object<T>::__ab_child_to_parent_barrier_trigger,
                          procid(),
                          std::string(strstrm->c_str(), strstrm->size()));
          }
        }
        break;
      }
      ab_barrier_cond.wait(ab_barrier_mut);
    }

    //logger(LOG_DEBUG, "barrier phase 1 complete");
    // I am root. send the barrier release downwards
    if (procid() == 0) {
      ab_barrier_release = ab_barrier_val;
      // build the downward data
      charstream strstrm(128);
      oarchive oarc2(strstrm);
      oarc2 << std::string(strm->c_str(), strm->size());
      for (procid_t i = 0;i < numchild; ++i) {
        strstrm.write(ab_children_data[i].c_str(), ab_children_data[i].length());
      }
      strstrm.flush();
      ab_alldata = std::string(strstrm->c_str(), strstrm->size());
      for (procid_t i = 0;i < numchild; ++i) {
        internal_control_call((procid_t)(childbase + i),
                             &dc_dist_object<T>::__ab_parent_to_child_barrier_release,
                             ab_barrier_val,
                             ab_alldata,
                             (int)control);

      }
    }
    // wait for the downward message releasing the barrier
    ab_barrier_mut.lock();
    while(1) {
      if (ab_barrier_release == ab_barrier_val) break;
      ab_barrier_cond.wait(ab_barrier_mut);
    }
    // read the collected data and release the lock
    std::string local_ab_alldata = ab_alldata;
    ab_barrier_mut.unlock();

    //logger(LOG_DEBUG, "barrier phase 2 complete");
    // now the data is a DFS search of a heap
    // I need to unpack it
    size_t heappos = 0;
    std::stringstream istrm(local_ab_alldata);
    iarchive iarc(istrm);

    for (size_t i = 0;i < numprocs(); ++i) {
      std::string s;
      iarc >> s;

      std::stringstream strm2(s);
      iarchive iarc2(strm2);
      iarc2 >> data[heappos];

      if (i + 1 == numprocs()) break;
      // advance heappos
      // leftbranch
      bool lefttraverseblock = false;
      while (1) {
        // can we continue going deaper down the left?
        size_t leftbranch = heappos * BARRIER_BRANCH_FACTOR + 1;
        if (lefttraverseblock == false && leftbranch < numprocs()) {
          heappos = leftbranch;
          break;
        }
        // ok. can't go down the left
        bool this_is_a_right_branch = (((heappos - 1) % BARRIER_BRANCH_FACTOR) == BARRIER_BRANCH_FACTOR - 1);
        // if we are a left branch, go to sibling
        if (this_is_a_right_branch == false) {
          size_t sibling = heappos + 1;
          if (sibling < numprocs()) {
            heappos = sibling;
            break;
          }
        }

        // we have finished this subtree, go back up to parent
        // and block the depth traversal on the next round
        // unless heappos is 0

        heappos = (heappos - 1) / BARRIER_BRANCH_FACTOR;
        lefttraverseblock = true;
        continue;
        // go to sibling
      }

    }
  }

////////////////////////////////////////////////////////////////////////////

  /**
   * This function is takes a vector of local elements T which must
   * be comparable and constructs a vector of length numprocs where
   * each element is a subset of the local contribution from that
   * machine and the union of all elements in the union of all local
   * contributions and all entries are unique:
   *
   * Usage: Each process reads the files that are stored locally and
   * wants to know which subset of local files to read even when
   * multiple processes see the same files.
   */
  template <typename U>
  void gather_partition(const std::vector<U>& local_contribution,
                        std::vector< std::vector<U> >& ret_partition,
                        bool control = false) {
    typedef std::set<U> set_type;

    // Compute the elements on each machine
    std::vector< std::set<U> > cpu2elems(numprocs());
    cpu2elems[procid()].insert(local_contribution.begin(),
                                   local_contribution.end());

    gather(cpu2elems, 0);
    // Construct the "balanced" partitioning
    if(procid() == 0) {
      ret_partition.clear();
      ret_partition.resize(numprocs());
      // Construct the union
      std::set<U> unassigned_elems;
      foreach(const set_type& set, cpu2elems)
        unassigned_elems.insert(set.begin(), set.end());
      // Assign elements to each of the machines
      for(procid_t cpuid = 0; !unassigned_elems.empty();
          cpuid = (cpuid + 1) % cpu2elems.size()) {
        // while there are things left to be assigned to this cpu
        while( !cpu2elems[cpuid].empty() ) {
          // Get the next element and remove it
          U elem = *(cpu2elems[cpuid].begin());
          cpu2elems[cpuid].erase(cpu2elems[cpuid].begin());
          // if the next element on this cpu is not yet assigned then
          // assign it to this cpu
          if(unassigned_elems.count(elem) != 0) {
            unassigned_elems.erase(elem);
            ret_partition[cpuid].push_back(elem);
            break;
          }

        } // end of while loop
      } // end of loop over cpus
      assert(unassigned_elems.empty());
    }
    // Scatter the result
    broadcast(ret_partition, procid() == 0, control);
  } // end of gather_partition

/*****************************************************************************
                      Implementation of Barrier
 *****************************************************************************/

 private:
  // ------- Sense reversing barrier data ----------
  /// The next value of the barrier. either +1 or -1
  int barrier_sense;
  /// When this flag == the current barrier value. The barrier is complete
  int barrier_release;
  /** when barrier sense is 1, barrier clears when
   * child_barrier_counter == numchild. When barrier sense is -1, barrier
   * clears when child_barrier_counter == 0;
   */
  atomic<int> child_barrier_counter;
  /// condition variable and mutex protecting the barrier variables
  conditional barrier_cond;
  mutex barrier_mut;
  procid_t parent;  /// parent node
  size_t childbase; /// id of my first child
  procid_t numchild;  /// number of children

  /**
    The child calls this function in the parent once the child enters the barrier
  */
  void __child_to_parent_barrier_trigger(procid_t source) {
    barrier_mut.lock();
    // assert childbase <= source <= childbase + BARRIER_BRANCH_FACTOR
    ASSERT_GE(source, childbase);
    ASSERT_LT(source, childbase + BARRIER_BRANCH_FACTOR);
    child_barrier_counter.inc(barrier_sense);
    barrier_cond.signal();
    barrier_mut.unlock();
  }

  /**
    This is on the downward pass of the barrier. The parent calls this function
    to release all the children's barriers
  */
  void __parent_to_child_barrier_release(int releaseval) {
    // send the release downwards
    // get my largest child
    for (procid_t i = 0;i < numchild; ++i) {
      internal_control_call((procid_t)(childbase + i),
                            &dc_dist_object<T>::__parent_to_child_barrier_release,
                            releaseval);

    }
    barrier_mut.lock();
    barrier_release = releaseval;
    barrier_cond.signal();
    barrier_mut.unlock();
  }

 public:
  /**
    A regular barrier equivalent to MPI_Barrier.
    A machine entering this barrier will wait until every machine
    reaches this barrier before continuing. Only one thread from each machine
    should call the barrier.

    \see full_barrier
    */
  void barrier() {
    // upward message
    int barrier_val = barrier_sense;
    barrier_mut.lock();
    // wait for all children to be done
    while(1) {
      if ((barrier_sense == -1 && child_barrier_counter.value == 0) ||
          (barrier_sense == 1 && child_barrier_counter.value == (int)(numchild))) {
        // flip the barrier sense
        barrier_sense = -barrier_sense;
        // call child to parent in parent
        barrier_mut.unlock();
        if (procid() != 0) {
          internal_control_call(parent,
                           &dc_dist_object<T>::__child_to_parent_barrier_trigger,
                           procid());
        }
        break;
      }
      barrier_cond.wait(barrier_mut);
    }

    //logger(LOG_DEBUG, "barrier phase 1 complete");
    // I am root. send the barrier release downwards
    if (procid() == 0) {
      barrier_release = barrier_val;

      for (procid_t i = 0;i < numchild; ++i) {
        internal_control_call((procid_t)(childbase + i),
                             &dc_dist_object<T>::__parent_to_child_barrier_release,
                             barrier_val);

      }
    }
    // wait for the downward message releasing the barrier
    barrier_mut.lock();
    while(1) {
      if (barrier_release == barrier_val) break;
      barrier_cond.wait(barrier_mut);
    }
    barrier_mut.unlock();

    //logger(LOG_DEBUG, "barrier phase 2 complete");
  }

 /*****************************************************************************
                      Implementation of Full Barrier
*****************************************************************************/
 private:
  mutex full_barrier_lock;
  conditional full_barrier_cond;
  std::vector<size_t> calls_to_receive;
  // used to inform the counter that the full barrier
  // is in effect and all modifications to the calls_recv
  // counter will need to lock and signal
  bool full_barrier_in_effect;

  /** number of 'source' processor counts which have
  not achieved the right recv count */
  atomic<size_t> num_proc_recvs_incomplete;

  /// Marked as 1 if the proc is complete
  dense_bitset procs_complete;

 public:
  /**
  Similar to the barrier(), but provides additional guarantees that
  all RMI calls issued prior to this barrier are completed before
  returning.

  \note This function could return prematurely if
  other threads are still issuing function calls since we
  cannot differentiate between calls issued before the barrier
  and calls issued while the barrier is being evaluated.
  Therefore, when used in a multithreaded scenario, the user must ensure
  that all other threads which may perform operations using this object
  are stopped before the full barrier is initated.

  \see barrier
  */
  void full_barrier() {
    // gather a sum of all the calls issued to machine 0
    std::vector<size_t> calls_sent_to_target(numprocs(), 0);
    for (size_t i = 0;i < numprocs(); ++i) {
      calls_sent_to_target[i] = callssent[i].value;
    }

    // tell node 0 how many calls there are
    std::vector<std::vector<size_t> > all_calls_sent(numprocs());
    all_calls_sent[procid()] = calls_sent_to_target;
    all_gather(all_calls_sent, true);

    // get the number of calls I am supposed to receive from each machine
    calls_to_receive.clear(); calls_to_receive.resize(numprocs(), 0);
    for (size_t i = 0;i < numprocs(); ++i) {
      calls_to_receive[i] += all_calls_sent[i][procid()];
//      std::cout << "Expecting " << calls_to_receive[i] << " calls from " << i << std::endl;
    }
    // clear the counters
    num_proc_recvs_incomplete.value = numprocs();
    procs_complete.clear();
    // activate the full barrier
    full_barrier_in_effect = true;
    __asm("mfence");
    // begin one pass to set all which are already completed
    for (size_t i = 0;i < numprocs(); ++i) {
      if (callsreceived[i].value >= calls_to_receive[i]) {
        if (procs_complete.set_bit((uint32_t)i) == false) {
          num_proc_recvs_incomplete.dec();
        }
      }
    }

    full_barrier_lock.lock();
    while (num_proc_recvs_incomplete.value > 0) full_barrier_cond.wait(full_barrier_lock);
    full_barrier_lock.unlock();
    full_barrier_in_effect = false;
//     for (size_t i = 0; i < numprocs(); ++i) {
//       std::cout << "Received " << global_calls_received[i].value << " from " << i << std::endl;
//     }
    barrier();
  }

 /* --------------------  Implementation of Gather Statistics -----------------*/
 private:
  struct collected_statistics {
    size_t callssent;
    size_t bytessent;
    collected_statistics(): callssent(0), bytessent(0) { }
    void save(oarchive &oarc) const {
      oarc << callssent << bytessent;
    }
    void load(iarchive &iarc) {
      iarc >> callssent >> bytessent;
    }
  };
 public:
  /** Gather RPC statistics. All machines must call
   this function at the same time. However, only proc 0 will
   return values */
  std::map<std::string, size_t> gather_statistics() {
    std::map<std::string, size_t> ret;

    std::vector<collected_statistics> stats(numprocs());
    stats[procid()].callssent = calls_sent();
    stats[procid()].bytessent = bytes_sent();
    logstream(LOG_INFO) << procid() << ": calls_sent: ";
    for (size_t i = 0;i < numprocs(); ++i) {
      logstream(LOG_INFO) << callssent[i].value << ", ";
    }
    logstream(LOG_INFO) << std::endl;
    logstream(LOG_INFO) << procid() << ": calls_recv: ";
    for (size_t i = 0;i < numprocs(); ++i) {
      logstream(LOG_INFO) << callsreceived[i].value << ", ";
    }
    logstream(LOG_INFO) << std::endl;

    gather(stats, 0, true);
    if (procid() == 0) {
      collected_statistics cs;
      for (size_t i = 0;i < numprocs(); ++i) {
        cs.callssent += stats[i].callssent;
        cs.bytessent += stats[i].bytessent;
      }
      ret["total_calls_sent"] = cs.callssent;
      ret["total_bytes_sent"] = cs.bytessent;
    }
    return ret;
  }
};

#include <graphlab/macros_undef.hpp>
#include <graphlab/rpc/mem_function_arg_types_undef.hpp>
#undef BARRIER_BRANCH_FACTOR
}// namespace graphlab
#endif

ext: hpp

max_stars_repo_name: iivek/graphlab-cmu-mirror

max_issues_repo_name: iivek/graphlab-cmu-mirror

max_forks_repo_name: iivek/graphlab-cmu-mirror


text:
/*
 * TreeManager.cpp
 *
 *  Created on: 5 Feb 2015
 *      Author: ejclemen
 */

#include "../../interface/TreeHelpers/TreeManager.h"
#include "../../interface/Readers/NTupleEventReader.h"
#include "../../interface/GlobalVariables.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>

using namespace boost;
using namespace std;
namespace BAT {

TreeManager::TreeManager() : //
		seenDataTypes_(), //
		treeFiles_(), //
		currentDataType_(DataType::ElectronHad), //
		currentFolder_(""), //
		collection_() {
}

TreeManager::~TreeManager() {
}

void TreeManager::addBranch(std::string branchLabel, std::string varType, std::string treeName, bool isSingleValuePerEvent) {

	// Check if folder exists
	// And check if tree of the same name in this folder exists
	if (collection_.find(currentFolder_) == collection_.end() ) {
		addFolder(currentFolder_);
	}

	for (unsigned short type = DataType::ElectronHad; type < DataType::NUMBER_OF_DATA_TYPES; ++type) {
		if (seenDataTypes_.at(type)) {
			if (  collection_[currentFolder_][type]->treeMap_.find(treeName) == collection_[currentFolder_][type]->treeMap_.end() ) {
				addTreeToFolder(treeName, currentFolder_, type);
			}

			// Add branch to tree
			treeFiles_.at(type)->Cd(currentFolder_.c_str());
			collection_[currentFolder_][type]->addBranchToTree(branchLabel, varType, collection_[currentFolder_].at(type)->treeMap_[treeName], isSingleValuePerEvent);
		}
	}

}

void TreeManager::Fill(std::string branchLabel, float fillValue) {
	collection_[currentFolder_][currentDataType_]->setBranchVariable( branchLabel, fillValue );
}

void TreeManager::FillTrees() {
	// Loop over all known trees, and call "Fill"
	for ( boost::unordered_map<std::string, TBranchArray>::const_iterator dirIter = collection_.begin(); dirIter != collection_.end(); ++dirIter ) {
		for (unsigned short type = DataType::ElectronHad; type < DataType::NUMBER_OF_DATA_TYPES; ++type) {
			if (seenDataTypes_.at(type)) {

				for ( boost::unordered_map<std::string, boost::shared_ptr<TTree>>::const_iterator iter = dirIter->second[type]->treeMap_.begin(); iter != dirIter->second[type]->treeMap_.end(); ++iter) {
					iter->second->Fill();
				}

			// Reset all variables
			dirIter->second[type]->resetBranchVariables();

			}
		}
	}
}

void TreeManager::setCurrentDataType(DataType::value type) {
	currentDataType_ = type;
}

void TreeManager::prepareForSeenDataTypes( const boost::array<bool, DataType::NUMBER_OF_DATA_TYPES>& seenDataTypes_ ) {
	this->seenDataTypes_ = seenDataTypes_;

	for (unsigned type = 0; type < DataType::NUMBER_OF_DATA_TYPES; ++type) {
		if (seenDataTypes_.at(type)) {
			const std::string filename = "tree_" + assembleFilename((DataType::value) type);
			boost::shared_ptr<TFile> file(new TFile(filename.c_str(), "RECREATE"));
			file->SetCompressionLevel(7);

			treeFiles_.at(type) = file;
			// collection_[""].at(type) = TBranchCollectionRef(new TBranchCollection());
		}
	}
}

const std::string TreeManager::assembleFilename(DataType::value type) const {
	const std::string name = DataType::names[type];
	std::stringstream str;
	std::string electronAlgo = ElectronAlgorithm::names[Globals::electronAlgorithm];
	std::string jetAlgo = JetAlgorithm::names[Globals::jetAlgorithm];
	std::string metAlgo = METAlgorithm::names[Globals::metAlgorithm];
	std::string muonAlgo = MuonAlgorithm::names[Globals::muonAlgorithm];
	std::string electronSyst = (Globals::ElectronScaleFactorSystematic > 0) ? "_plusElectron" : "_minusElectron";
	std::string muonSyst = (Globals::MuonScaleFactorSystematic > 0) ? "_plusMuon" : "_minusMuon";
	std::string jesSyst = (Globals::JESsystematic > 0) ? "_plusJES" : "_minusJES";
	std::string jetSmearingSyst = (Globals::JetSmearingSystematic > 0) ? "_plusJER" : "_minusJER";
	std::string bjetSyst = (Globals::BJetSystematic > 0) ? "_plusBjet" : "_minusBJet";
	std::string lightJetSyst = (Globals::LightJetSystematic > 0) ? "_plusLightJet" : "_minusLightJet";
	std::string suffix = Globals::custom_file_suffix;
	std::string pdfWeight =
			(Globals::pdfWeightNumber != 0) ? "_PDF_" + boost::lexical_cast<std::string>(Globals::pdfWeightNumber) : "";
	if (Globals::ElectronScaleFactorSystematic == 0)
		electronSyst = "";
	if (Globals::MuonScaleFactorSystematic == 0)
		muonSyst = "";
	if (Globals::JESsystematic == 0)
		jesSyst = "";
	if (Globals::JetSmearingSystematic == 0)
		jetSmearingSyst = "";
	if (Globals::BJetSystematic == 0)
		bjetSyst = "";
	if (Globals::LightJetSystematic == 0)
		lightJetSyst = "";
	if (suffix != "")
		suffix = "_" + suffix;

	str << name << "_" << Globals::luminosity << "pb";
	str << "_" << electronAlgo << "_" << muonAlgo << "_" << jetAlgo << "_" << metAlgo;
	str << electronSyst << muonSyst << jesSyst << jetSmearingSyst << pdfWeight << bjetSyst << lightJetSyst << suffix << ".root";
	return str.str();

}

void TreeManager::writeToDisk() {
	for (unsigned type = 0; type < DataType::NUMBER_OF_DATA_TYPES; ++type) {
		if (seenDataTypes_.at(type)) {
			treeFiles_.at(type)->Write();
			// treeFiles_.at(type)->Close();
		}

	}
}

void TreeManager::addFolder(string folder)
{
	for (unsigned type = 0; type < DataType::NUMBER_OF_DATA_TYPES; ++type) {
		if (seenDataTypes_.at(type)) {
			treeFiles_.at(type)->Cd(folder.c_str());
			collection_[folder].at(type) = TBranchCollectionRef(new TBranchCollection(folder));
			collection_[folder].at(type)->writeDirectory( folder, treeFiles_.at(type) );
		}

	}
}

void TreeManager::addTreeToFolder(string treeName, string folder, unsigned int dataType) {
	collection_[folder].at(dataType)->treeMap_[treeName] = boost::shared_ptr<TTree>(
			new TTree(treeName.c_str(), treeName.c_str()));
	collection_[folder].at(dataType)->treeMap_[treeName]->SetDirectory(
			treeFiles_.at(dataType)->GetDirectory(folder.c_str()));

	// Add branch for event weight only if it doesn't already exist
	// e.g. if there are two trees in this directory, there might already be an EventWeight branch
	// Bad if the two trees in the same directory correspond to different events
	if (!collection_[folder].at(dataType)->contains("EventWeight")) {
		collection_[folder].at(dataType)->addBranchToTree("EventWeight", "F",
				collection_[folder].at(dataType)->treeMap_[treeName]);
	}
	if (!collection_[folder].at(dataType)->contains("PUWeight")) {
		collection_[folder].at(dataType)->addBranchToTree("PUWeight", "F",
				collection_[folder].at(dataType)->treeMap_[treeName]);
	}
}

void TreeManager::setCurrentFolder(std::string collection) {
	currentFolder_ = collection;
}

} //end namespace BAT

ext: cpp

max_stars_repo_name: kreczko/AnalysisSoftware

max_issues_repo_name: kreczko/AnalysisSoftware

max_forks_repo_name: kreczko/AnalysisSoftware


text:
#include <Eigen/Core>

#include <numpy_eigen/boost_python_headers.hpp>
Eigen::Matrix<boost::uint8_t, 6, 5> test_uchar_6_5(const Eigen::Matrix<boost::uint8_t, 6, 5> & M)
{
	return M;
}
void export_uchar_6_5()
{
	boost::python::def("test_uchar_6_5",test_uchar_6_5);
}

max_stars_repo_name: PushyamiKaveti/kalibr

max_issues_repo_name: PushyamiKaveti/kalibr

max_forks_repo_name: PushyamiKaveti/kalibr


text:
/**
 * Copyright Soramitsu Co., Ltd. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef KAGOME_OFFCHAIN_TYPES
#define KAGOME_OFFCHAIN_TYPES

#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include <libp2p/multi/multiaddress.hpp>
#include <libp2p/peer/peer_id.hpp>

#include "common/blob.hpp"
#include "common/buffer.hpp"
#include "scale/scale.hpp"

namespace kagome::offchain {

  /// Timestamp is milliseconds since UNIX Epoch
  using Timestamp = uint64_t;

  using RandomSeed = common::Blob<32>;

  enum class StorageType : int32_t { Undefined = 0, Persistent = 1, Local = 2 };

  enum class HttpMethod { Undefined = 0, Get = 1, Post = 2 };

  using RequestId = int16_t;

  enum class HttpError : int32_t {
    Timeout = 0,   //!< The deadline was reached
    IoError = 1,   //!< There was an IO error while processing the request
    InvalidId = 2  //!< The ID of the request is invalid
  };

  /**
   * @brief HTTP status codes that can get returned by certain Offchain funcs.
   * 0:  the specified request identifier is invalid.
   * 10: the deadline for the started request was reached.
   * 20: an error has occurred during the request, e.g. a timeout or the remote
   *     server has closed the connection. On returning this error code, the
   *     request is considered destroyed and must be reconstructed again.
   * 100-999: the request has finished with the given HTTP status code.
   */
  using HttpStatus = uint16_t;
  constexpr HttpStatus InvalidIdentifier(0);
  constexpr HttpStatus DeadlineHasReached(10);
  constexpr HttpStatus ErrorHasOccurred(20);

  struct NoPayload {};

  template <class Stream,
            typename = std::enable_if_t<Stream::is_encoder_stream>>
  Stream &operator<<(Stream &s, const NoPayload &) {
    return s;
  }

  template <class Stream,
            typename = std::enable_if_t<Stream::is_decoder_stream>>
  Stream &operator>>(Stream &s, NoPayload &) {
    return s;
  }

  struct Success : public NoPayload {};
  struct Failure : public NoPayload {};

  template <typename S, typename F>
  struct Result final : boost::variant<S, F> {
    using boost::variant<S, F>::variant;
    bool isSuccess() const {
      return boost::variant<S, F>::which() == 0;
    }
    bool isFailure() const {
      return boost::variant<S, F>::which() == 1;
    }
    S &value() {
      return boost::relaxed_get<S>(*this);
    }
    F &error() {
      return boost::relaxed_get<F>(*this);
    }
  };

  struct OpaqueNetworkState {
    libp2p::peer::PeerId peer_id;
    std::list<libp2p::multi::Multiaddress> address;
  };

  template <class Stream,
            typename = std::enable_if_t<Stream::is_encoder_stream>>
  Stream &operator<<(Stream &s, const OpaqueNetworkState &v) {
    s << v.peer_id.toVector();

    s << scale::CompactInteger(v.address.size());

    for (auto &address : v.address) {
      s << address.getBytesAddress();
    }

    return s;
  }

  template <class Stream,
            typename = std::enable_if_t<Stream::is_decoder_stream>>
  Stream &operator>>(Stream &s, OpaqueNetworkState &v) {
    common::Buffer buff;

    s >> buff;
    auto peer_id_res = libp2p::peer::PeerId::fromBytes(buff);
    if (peer_id_res.has_error()) {
      std::runtime_error(peer_id_res.error().message());
    }
    v.peer_id = std::move(peer_id_res.value());

    scale::CompactInteger size;
    s >> size;
    v.address.resize(size.convert_to<uint64_t>());

    for (auto &address : v.address) {
      s >> buff;
      auto ma_res = libp2p::multi::Multiaddress::create(buff);
      if (ma_res.has_error()) {
        std::runtime_error(ma_res.error().message());
        address = std::move(ma_res.value());
      }
    }

    return s;
  }

}  // namespace kagome::offchain

#endif  // KAGOME_OFFCHAIN_TYPES

max_stars_repo_name: soramitsu/kagome

max_issues_repo_name: soramitsu/kagome

max_forks_repo_name: soramitsu/kagome


text:
    /**
  *********************************************************************
*************************************************************************
***
*** \file  CPUUsage.cpp
*** \brief CPUUsage class body
***
*****************************************
  *****************************************
    **/

/*

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

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

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

*/

#include "CPUUsage.hpp"
#include "../libH/Debug.hpp"
#include "../libH/Exception.hpp"
#include "../libH/UtilTime.hpp"
#include <fstream>
#include <iostream>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/thread/thread.hpp>

using namespace std;
using namespace boost;
using namespace boost::filesystem;
using namespace H;
using namespace Gizmod;

////////////////////////////////////////////////////////////////////////////
// Typedef's / defines
///////////////////////////////////////

/**
 * \def    PROC_STAT_PATH
 * \brief  Path to /proc/stat
**/
#define PROC_STAT_PATH		"/proc/stat"

/**
 * \def    DEFAULT_UPDATE_DELAY
 * \brief  The default amount of seconds between process tree rebuilds
**/
#define DEFAULT_UPDATE_DELAY	0.1f

////////////////////////////////////////////////////////////////////////////
// Statics
///////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////

/**
 * \brief CPUUsage Default Constructor
**/
CPUUsage::CPUUsage() : mThreadProc(this) {
	mSecsBetweenUpdates = DEFAULT_UPDATE_DELAY;
	mWatching = false;
	mThreading = false;
	getNumCPUs();
}

/**
 * \brief CPUUsageInfo Default Constructor
**/
CPUUsageInfo::CPUUsageInfo() {
	memset(Field, 0, sizeof(double) * CPUUSAGE_MAX);
	memset(Stat, 0, sizeof(double) * CPUUSAGE_MAX);
	Usage = 0.0;
	Average = 0.0;
}

/**
 * \brief CPUUsage Destructor
**/
CPUUsage::~CPUUsage() {
	shutdown();
}

/**
 * \brief CPUUsageInfo Destructor
**/
CPUUsageInfo::~CPUUsageInfo() {
}

////////////////////////////////////////////////////////////////////////////
// Class Body
///////////////////////////////////////

/**
 * \brief  Get the number of CPUs on the system
 * \return The number of CPUs
**/
size_t CPUUsage::getNumCPUs() {
	if (mCPUUsage.size() == 0) {
		if (!filesystem::exists(path(PROC_STAT_PATH))) {
			cdbg << "Can not update CPU Usage Stats!" << endl;
			return -1;
		}

		// open the file
		ifstream StatFile(PROC_STAT_PATH);
		if (!StatFile.is_open()) {
			cdbg << "Error Updating CPU Usage Stats!" << endl;
			return -1;
		}

		// read the contents
		string Line;
		int cpus = 0;
		while (true) {
			// get the line and make sure it's related to cpu information
			getline(StatFile, Line);
			if (Line.find("cpu") != 0)
				break;
			cpus ++;
		}

		mCPUUsage.resize(cpus);
		for (int lp = 0; lp < cpus; lp ++)
			mCPUUsage[lp] = shared_ptr<CPUUsageInfo>(new CPUUsageInfo);
	}

	return mCPUUsage.size() - 1;
}

/**
 * \brief  Start the Usage watcher thread
**/
void CPUUsage::init() {
	if (getNumCPUs() < 0) {
		cdbg << "Cannot give CPU Usage Stats! -- Cannot access [" << PROC_STAT_PATH << "]" << endl;
		return;
	}

	// initialize the event handler thread
	thread thrd(mThreadProc);
}

/**
 * \brief  Event triggered when CPU Usage stats are updated
 * \param  Event A vector of CPU Usage info, where index 0 is ALL processors, 1 is proc 1, 2 is cpu 2, etc
**/
void CPUUsage::onCPUUsage(std::vector< boost::shared_ptr<CPUUsageInfo> > const & Event) {
	// override me
}

/**
 * \brief  Set the time between updates in seconds
 * \param  Seconds Number of seconds between updates
**/
void CPUUsage::setTimeBetweenUpdates(float Seconds) {
	mSecsBetweenUpdates = Seconds;
}

/**
 * \brief  Shutdown the CPUUsage watcher
**/
void CPUUsage::shutdown() {
	mWatching = false;
	while (mThreading) {
		cdbg5 << "Waiting on CPUUsage Thread to Finish..." << endl;
		UtilTime::sleep(0.1f);
	}
}

/**
 * \brief  The thread procedure loop
**/
void CPUUsage::threadProc() {
	// wait for events to occur
	mWatching = true;
	while (mWatching) {
		updateUsageStats();
		UtilTime::sleep(mSecsBetweenUpdates);
	}
}

/**
 * \brief  Force an update of the CPU Usage stats
**/
void CPUUsage::updateUsageStats() {
	// open the file
	FILE * StatFile;
	if ((StatFile = fopen(PROC_STAT_PATH, "r")) == NULL) {
		cdbg << "Failed get CPU Usage Information" << endl;
		return;
	}

	// read and close
	int ret;
	for (size_t cpu = 0; cpu < mCPUUsage.size(); cpu ++) {
		double Info[CPUUSAGE_MAX];
		int CpuIndex = 0;
		shared_ptr<CPUUsageInfo> pUsage = mCPUUsage[cpu];
		if (cpu == 0)
			ret = fscanf(StatFile, "cpu %lf %lf %lf %lf %lf %lf %lf %lf\n", Info, Info + 1, Info + 2, Info + 3, Info + 4, Info + 5, Info + 6, Info + 7);
		else {
			ret = fscanf(StatFile, "cpu%d %lf %lf %lf %lf %lf %lf %lf %lf\n", &CpuIndex, Info, Info + 1, Info + 2, Info + 3, Info + 4, Info + 5, Info + 6, Info + 7);
		}
		if (!ret)
			continue;

		// calculate the total
		double Total = 0.0;
		for (int lp = 0; lp < CPUUSAGE_MAX; lp ++) {
			//Total
			pUsage->Field[lp] = Info[lp] - pUsage->Stat[lp];
			Total += pUsage->Field[lp];
			pUsage->Stat[lp] = Info[lp];
		}
		pUsage->Usage = ((Total - pUsage->Field[CPUUSAGE_IDLE] - pUsage->Field[CPUUSAGE_IOWAIT]) / Total) * 100.0;
		pUsage->mAverager.push(pUsage->Usage);
		pUsage->Average = pUsage->mAverager.average();
	}
	fclose(StatFile);

	// fire the event
	onCPUUsage(mCPUUsage);
}

max_stars_repo_name: pauljeremyturner/gizmod

max_issues_repo_name: pauljeremyturner/gizmod

max_forks_repo_name: pauljeremyturner/gizmod


text:
#include "BBBoundingBox.h"
#include "Utils/BBUtils.h"
#include <cfloat>
#include "Render/BufferObject/BBVertexBufferObject.h"
#include "Render/BBMaterial.h"
#include "Render/BBDrawCall.h"
#include <Eigen/Eigen>
#include "Render/BBCamera.h"

using namespace Eigen;

/**
 * @brief BBBoundingBox::BBBoundingBox
 */
BBBoundingBox::BBBoundingBox()
    : BBBoundingBox(0, 0, 0, 0, 0, 0, 1, 1, 1)
{

}

BBBoundingBox::BBBoundingBox(float px, float py, float pz,
                             float rx, float ry, float rz,
                             float sx, float sy, float sz)
    : BBRenderableObject(px, py, pz, rx, ry, rz, sx, sy, sz)
{
    m_nBoxVertexCount = 0;
    m_pOriginalBoxVertexes = NULL;
    m_pTransformedBoxVertexes = NULL;
    m_DefaultColor = QVector3D(0.909804f, 0.337255f, 0.333333f);
}

BBBoundingBox::~BBBoundingBox()
{
    BB_SAFE_DELETE_ARRAY(m_pOriginalBoxVertexes);
    BB_SAFE_DELETE_ARRAY(m_pTransformedBoxVertexes);
}

bool BBBoundingBox::hit(const BBRay &ray, float &fDistance)
{
    Q_UNUSED(ray);
    Q_UNUSED(fDistance);
    return m_bActive;
}

QVector3D BBBoundingBox::getCenter()
{
    return QVector3D(m_Center[0], m_Center[1], m_Center[2]);
}

void BBBoundingBox::setModelMatrix(float px, float py, float pz,
                                   const QQuaternion &r,
                                   float sx, float sy, float sz)
{
    // When the corresponding model is transformed, invoke
    BBGameObject::setModelMatrix(px, py, pz, r, sx, sy, sz);
    for (int i = 0; i < m_nBoxVertexCount; i++)
    {
        m_pTransformedBoxVertexes[i] = m_ModelMatrix * m_pOriginalBoxVertexes[i];
    }
}

/**
 * @brief BBRectBoundingBox3D::BBRectBoundingBox3D
 * @param fCenterX
 * @param fCenterY
 * @param fCenterZ
 * @param fHalfLengthX
 * @param fHalfLengthY
 * @param fHalfLengthZ
 */
BBRectBoundingBox3D::BBRectBoundingBox3D(float fCenterX, float fCenterY, float fCenterZ,
                                         float fHalfLengthX, float fHalfLengthY, float fHalfLengthZ)
    : BBBoundingBox()
{
    m_nBoxVertexCount = 4;
    m_pOriginalBoxVertexes = new QVector3D[m_nBoxVertexCount];
    m_pTransformedBoxVertexes = new QVector3D[m_nBoxVertexCount];

    m_Center[0] = fCenterX;
    m_Center[1] = fCenterY;
    m_Center[2] = fCenterZ;
    if (fHalfLengthX == 0)
    {
        m_pOriginalBoxVertexes[0] = QVector3D(fCenterX, fCenterY + fHalfLengthY, fCenterZ + fHalfLengthZ);
        m_pOriginalBoxVertexes[1] = QVector3D(fCenterX, fCenterY - fHalfLengthY, fCenterZ + fHalfLengthZ);
        m_pOriginalBoxVertexes[2] = QVector3D(fCenterX, fCenterY - fHalfLengthY, fCenterZ - fHalfLengthZ);
        m_pOriginalBoxVertexes[3] = QVector3D(fCenterX, fCenterY + fHalfLengthY, fCenterZ - fHalfLengthZ);
    }
    else if (fHalfLengthY == 0)
    {
        m_pOriginalBoxVertexes[0] = QVector3D(fCenterX + fHalfLengthX, fCenterY, fCenterZ + fHalfLengthZ);
        m_pOriginalBoxVertexes[1] = QVector3D(fCenterX - fHalfLengthX, fCenterY, fCenterZ + fHalfLengthZ);
        m_pOriginalBoxVertexes[2] = QVector3D(fCenterX - fHalfLengthX, fCenterY, fCenterZ - fHalfLengthZ);
        m_pOriginalBoxVertexes[3] = QVector3D(fCenterX + fHalfLengthX, fCenterY, fCenterZ - fHalfLengthZ);
    }
    else if (fHalfLengthZ == 0)
    {
        m_pOriginalBoxVertexes[0] = QVector3D(fCenterX + fHalfLengthX, fCenterY + fHalfLengthY, fCenterZ);
        m_pOriginalBoxVertexes[1] = QVector3D(fCenterX - fHalfLengthX, fCenterY + fHalfLengthY, fCenterZ);
        m_pOriginalBoxVertexes[2] = QVector3D(fCenterX - fHalfLengthX, fCenterY - fHalfLengthY, fCenterZ);
        m_pOriginalBoxVertexes[3] = QVector3D(fCenterX + fHalfLengthX, fCenterY - fHalfLengthY, fCenterZ);
    }

    m_pTransformedBoxVertexes[0] = m_pOriginalBoxVertexes[0];
    m_pTransformedBoxVertexes[1] = m_pOriginalBoxVertexes[1];
    m_pTransformedBoxVertexes[2] = m_pOriginalBoxVertexes[2];
    m_pTransformedBoxVertexes[3] = m_pOriginalBoxVertexes[3];
}

BBRectBoundingBox3D::~BBRectBoundingBox3D()
{

}

void BBRectBoundingBox3D::init()
{
    m_pVBO = new BBVertexBufferObject(m_nBoxVertexCount);
    for (int i = 0; i < m_nBoxVertexCount; i++)
    {
        m_pVBO->setPosition(i, m_pOriginalBoxVertexes[i].x(),
                               m_pOriginalBoxVertexes[i].y(),
                               m_pOriginalBoxVertexes[i].z());
        m_pVBO->setColor(i, m_DefaultColor);
    }

    m_nIndexCount = 8;
    unsigned short indexes[] = {0, 1, 1, 2, 2, 3, 3, 0};
    m_pIndexes = new unsigned short[m_nIndexCount];
    for (int i = 0; i < m_nIndexCount; i++)
    {
        m_pIndexes[i] = indexes[i];
    }

    m_pCurrentMaterial->init("UI",
                             BB_PATH_RESOURCE_SHADER(UI.vert),
                             BB_PATH_RESOURCE_SHADER(UI.frag));
    m_pCurrentMaterial->setVector4(LOCATION_TEXTURE_SETTING0, 0.0f, 0.0f, 0.0f, 0.0f);
    m_pCurrentMaterial->setVector4(LOCATION_CAMERA_PARAMETERS0, 800.0f, 600.0f, 0.0f, 0.0f);

    BBRenderableObject::init();

    BBDrawCall *pDrawCall = new BBDrawCall;
    pDrawCall->setMaterial(m_pCurrentMaterial);
    pDrawCall->setVBO(m_pVBO);
    pDrawCall->setEBO(m_pEBO, GL_LINES, m_nIndexCount, 0);
    appendDrawCall(pDrawCall);
}

bool BBRectBoundingBox3D::hit(const BBRay &ray, float &fDistance)
{
    // If it is not activated, no collision occurs
    if (!BBBoundingBox::hit(ray, fDistance))
        return false;

    QVector3D intersection;
    bool result = false;
    fDistance = FLT_MAX;

    if (ray.computeIntersectWithRectangle(m_pTransformedBoxVertexes[0],
                                          m_pTransformedBoxVertexes[1],
                                          m_pTransformedBoxVertexes[2],
                                          m_pTransformedBoxVertexes[3], intersection))
    {
        float tmp = ray.computeIntersectDistance(intersection);
        if (tmp >= 0.0f)
        {
            result = true;
            fDistance = tmp;
        }
    }

    return result;
}

/**
 * @brief BBTriangleBoundingBox3D::BBTriangleBoundingBox3D
 * @param point1
 * @param point2
 * @param point3
 */
BBTriangleBoundingBox3D::BBTriangleBoundingBox3D(const QVector3D &point1,
                                                 const QVector3D &point2,
                                                 const QVector3D &point3)
    : BBBoundingBox()
{
    m_nBoxVertexCount = 3;
    m_pOriginalBoxVertexes = new QVector3D[m_nBoxVertexCount];
    m_pTransformedBoxVertexes = new QVector3D[m_nBoxVertexCount];

    m_pOriginalBoxVertexes[0] = point1;
    m_pOriginalBoxVertexes[1] = point2;
    m_pOriginalBoxVertexes[2] = point3;
}

bool BBTriangleBoundingBox3D::hit(const BBRay &ray, float &fDistance)
{
    // If it is not activated, no collision occurs
    if (!BBBoundingBox::hit(ray, fDistance))
        return false;

    QVector3D intersection;
    bool result = false;
    fDistance = FLT_MAX;

    if (ray.computeIntersectWithTriangle(m_pTransformedBoxVertexes[0],
                                         m_pTransformedBoxVertexes[1],
                                         m_pTransformedBoxVertexes[2], intersection))
    {
        float tmp = ray.computeIntersectDistance(intersection);
        if (tmp >= 0.0f)
        {
            result = true;
            fDistance = tmp;
        }
    }
    return result;
}

/**
 * @brief BBQuarterCircleBoundingBox3D::BBQuarterCircleBoundingBox3D
 * @param fCenterX
 * @param fCenterY
 * @param fCenterZ
 * @param fRadius
 * @param ePlaneName
 */
BBQuarterCircleBoundingBox3D::BBQuarterCircleBoundingBox3D(float fCenterX, float fCenterY, float fCenterZ,
                                                           float fRadius, const BBPlaneName &ePlaneName)
    : BBBoundingBox()
{
    m_nBoxVertexCount = 1;
    m_pOriginalBoxVertexes = new QVector3D[m_nBoxVertexCount];
    m_pTransformedBoxVertexes = new QVector3D[m_nBoxVertexCount];

    m_Center[0] = fCenterX;
    m_Center[1] = fCenterY;
    m_Center[2] = fCenterZ;

    m_eSelectedPlaneName = ePlaneName;

    m_QuadrantFlag = QVector3D(0, 0, 0);

    if (ePlaneName == BBPlaneName::YOZ)
    {
        m_pOriginalBoxVertexes[0] = QVector3D(m_Center[0], m_Center[1], m_Center[2]) + QVector3D(0, fRadius, 0);
    }
    else // XOZ or XOY
    {
        m_pOriginalBoxVertexes[0] = QVector3D(m_Center[0], m_Center[1], m_Center[2]) + QVector3D(fRadius, 0, 0);
    }
}

bool BBQuarterCircleBoundingBox3D::hit(const BBRay &ray, float &fDistance)
{
    // If it is not activated, no collision occurs
    if (!BBBoundingBox::hit(ray, fDistance))
        return false;

    QVector3D intersection;
    bool result = false;
    fDistance = FLT_MAX;

    if (ray.computeIntersectWithQuarterCircle(m_Position,
                                              (m_pTransformedBoxVertexes[0] - m_Position).length(),
                                              m_eSelectedPlaneName,
                                              intersection,
                                              m_QuadrantFlag))
    {
        float tmp = ray.computeIntersectDistance(intersection);
        if (tmp >= 0.0f)
        {
            result = true;
            fDistance = tmp;
        }
    }
    return result;
}

/**
 * @brief BBBoundingBox3D::BBBoundingBox3D
 * @param vertexes
 */
BBBoundingBox3D::BBBoundingBox3D(const QList<QVector4D> &vertexes)
    : BBBoundingBox3D(0, 0, 0, 0, 0, 0, 1, 1, 1, vertexes)
{

}

BBBoundingBox3D::BBBoundingBox3D(float px, float py, float pz,
                                 float rx, float ry, float rz,
                                 float sx, float sy, float sz,
                                 const QList<QVector4D> &vertexes)
    : BBBoundingBox(px, py, pz, rx, ry, rz, sx, sy, sz)
{
    m_nBoxVertexCount = 8;
    m_pOriginalBoxVertexes = new QVector3D[m_nBoxVertexCount];
    m_pTransformedBoxVertexes = new QVector3D[m_nBoxVertexCount];

    m_DefaultColor = QVector3D(0.909804f, 0.337255f, 0.333333f);
    m_Center[0] = 0;
    m_Center[1] = 0;
    m_Center[2] = 0;
    m_HalfLength[0] = 0.5f;
    m_HalfLength[1] = 0.5f;
    m_HalfLength[2] = 0.5f;
    m_Axis[0][0] = 1;
    m_Axis[0][1] = 0;
    m_Axis[0][2] = 0;
    m_Axis[1][0] = 0;
    m_Axis[1][1] = 1;
    m_Axis[1][2] = 0;
    m_Axis[2][0] = 0;
    m_Axis[2][1] = 0;
    m_Axis[2][2] = 1;

    computeBoxVertexes(vertexes);
}

BBBoundingBox3D::BBBoundingBox3D(const QVector3D &position, const QVector3D &rotation, const QVector3D &scale,
                                 const QVector3D &center, const QVector3D &halfLength)
    : BBBoundingBox3D(position.x(), position.y(), position.z(),
                      rotation.x(), rotation.y(), rotation.z(),
                      scale.x(), scale.y(), scale.z(),
                      center.x(), center.y(), center.z(),
                      halfLength.x(), halfLength.y(), halfLength.z())
{

}

BBBoundingBox3D::BBBoundingBox3D(float px, float py, float pz,
                                 float rx, float ry, float rz,
                                 float sx, float sy, float sz,
                                 float fCenterX, float fCenterY, float fCenterZ,
                                 float fHalfLengthX, float fHalfLengthY, float fHalfLengthZ)
    : BBBoundingBox(px, py, pz, rx, ry, rz, sx, sy, sz)
{
    m_nBoxVertexCount = 8;
    m_pOriginalBoxVertexes = new QVector3D[m_nBoxVertexCount];
    m_pTransformedBoxVertexes = new QVector3D[m_nBoxVertexCount];

    m_Center[0] = fCenterX;
    m_Center[1] = fCenterY;
    m_Center[2] = fCenterZ;
    m_HalfLength[0] = fHalfLengthX;
    m_HalfLength[1] = fHalfLengthY;
    m_HalfLength[2] = fHalfLengthZ;
    m_Axis[0][0] = 1;
    m_Axis[0][1] = 0;
    m_Axis[0][2] = 0;
    m_Axis[1][0] = 0;
    m_Axis[1][1] = 1;
    m_Axis[1][2] = 0;
    m_Axis[2][0] = 0;
    m_Axis[2][1] = 0;
    m_Axis[2][2] = 1;

    QList<QVector4D> vertexes;
    computeBoxVertexes(vertexes);
}

BBBoundingBox3D::~BBBoundingBox3D()
{

}

void BBBoundingBox3D::init()
{
    m_pVBO = new BBVertexBufferObject(8);
    for (int i = 0; i < 8; i++)
    {
        m_pVBO->setPosition(i, m_pOriginalBoxVertexes[i].x(),
                               m_pOriginalBoxVertexes[i].y(),
                               m_pOriginalBoxVertexes[i].z());
        m_pVBO->setColor(i, m_DefaultColor);
    }

    m_nIndexCount = 24;
    unsigned short indexes[] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7};
    m_pIndexes = new unsigned short[m_nIndexCount];
    for (int i = 0; i < m_nIndexCount; i++)
    {
        m_pIndexes[i] = indexes[i];
    }

    m_pCurrentMaterial->init("base",
                             BB_PATH_RESOURCE_SHADER(base.vert),
                             BB_PATH_RESOURCE_SHADER(base.frag));

    BBRenderableObject::init();

    BBDrawCall *pDrawCall = new BBDrawCall;
    pDrawCall->setMaterial(m_pCurrentMaterial);
    pDrawCall->setVBO(m_pVBO);
    pDrawCall->setEBO(m_pEBO, GL_LINES, m_nIndexCount, 0);
    appendDrawCall(pDrawCall);
}

bool BBBoundingBox3D::hit(const BBRay &ray, float &fDistance)
{
    // If it is not activated, no collision occurs
    if (!BBBoundingBox::hit(ray, fDistance))
        return false;

    QVector3D intersection;
    bool result = false;
    fDistance = FLT_MAX;
    // Calculate whether to hit the 6 faces of the bounding box
    static unsigned int indexes[] = {0, 1, 2, 3, 4, 5, 6, 7,
                                     1, 2, 6, 5, 0, 3, 7, 4,
                                     0, 1, 5, 4, 3, 2, 6, 7};
    for (int i = 0; i < 24; i += 4)
    {
        if (ray.computeIntersectWithRectangle(m_pTransformedBoxVertexes[indexes[i]],
                                              m_pTransformedBoxVertexes[indexes[i + 1]],
                                              m_pTransformedBoxVertexes[indexes[i + 2]],
                                              m_pTransformedBoxVertexes[indexes[i + 3]], intersection))
        {
            float temp = ray.computeIntersectDistance(intersection);
            if (temp >= 0.0f)
            {
                if (temp < fDistance)
                    fDistance = temp;
                result = true;
            }
        }
    }
    return result;
}

bool BBBoundingBox3D::belongToSelectionRegion(const BBFrustum &frustum)
{
    for (int i = 0; i < m_nBoxVertexCount; i++)
    {
        BB_PROCESS_ERROR_RETURN_FALSE(frustum.contain(m_pTransformedBoxVertexes[i]));
    }
    return true;
}

QVector3D BBBoundingBox3D::getHalfLength()
{
    return QVector3D(m_HalfLength[0], m_HalfLength[1], m_HalfLength[2]);
}

void BBBoundingBox3D::computeBoxVertexes(const QList<QVector4D> &vertexes)
{
    Q_UNUSED(vertexes);
    FloatData temp[8];
    int sign[8][3] = {{1, 1, 1},
                      {-1, 1, 1},
                      {-1, -1, 1},
                      {1, -1, 1},
                      {1, 1, -1},
                      {-1, 1, -1},
                      {-1, -1, -1},
                      {1, -1, -1}};
    for (int index = 0; index < 8; index++)
    {
        for (int i = 0; i < 3; i++)
        {
            temp[index].v[i] = m_Center[i];
            for (int j = 0; j < 3; j++)
            {
                temp[index].v[i] += m_Axis[j][i] * m_HalfLength[j] * sign[index][j];
            }
        }
        m_pOriginalBoxVertexes[index] = QVector3D(temp[index].v[0], temp[index].v[1], temp[index].v[2]);
        m_pTransformedBoxVertexes[index] = m_ModelMatrix * m_pOriginalBoxVertexes[index];
    }
}

/**
 * @brief BBAABBBoundingBox3D::BBAABBBoundingBox3D
 * @param vertexes
 */
BBAABBBoundingBox3D::BBAABBBoundingBox3D(const QList<QVector4D> &vertexes)
    : BBAABBBoundingBox3D(0, 0, 0, 0, 0, 0, 1, 1, 1, vertexes)
{

}

BBAABBBoundingBox3D::BBAABBBoundingBox3D(float px, float py, float pz,
                                         float rx, float ry, float rz,
                                         float sx, float sy, float sz,
                                         const QList<QVector4D> &vertexes)
    : BBBoundingBox3D(px, py, pz, rx, ry, rz, sx, sy, sz, vertexes)
{
    m_HalfLength[0] = 0;
    m_HalfLength[1] = 0;
    m_HalfLength[2] = 0;
    computeBoxVertexes(vertexes);
}

BBAABBBoundingBox3D::BBAABBBoundingBox3D(const QVector3D &position, const QVector3D &rotation, const QVector3D &scale,
                                         const QVector3D &center, const QVector3D &halfLength)
    : BBBoundingBox3D(position, rotation, scale, center, halfLength)
{

}

bool BBAABBBoundingBox3D::computeIntersectWithPlane(const QVector3D &point, const QVector3D &normal)
{
    // The vertex closest to the plane
    QVector3D p = getMin();
    if (normal.x() >= 0)
        p.setX(getMax().x());
    if (normal.y() >= 0)
        p.setY(getMax().y());
    if (normal.z() >= 0)
        p.setZ(getMax().z());
    // The vertex of the farthest diagonal
    QVector3D n = getMax();
    if (normal.x() >= 0)
        n.setX(getMin().x());
    if (normal.y() >= 0)
        n.setY(getMin().y());
    if (normal.z() >= 0)
        n.setZ(getMin().z());

    if (p.distanceToPlane(point, normal) < 0)
        return false;

    if (n.distanceToPlane(point, normal) < 0)
        return true;

    return false;
}

void BBAABBBoundingBox3D::computeBoxVertexes(const QList<QVector4D> &vertexes)
{
    int nVertexCount = vertexes.count();

    // init matrix
    MatrixXf m(3, nVertexCount);
    for (int i = 0; i < nVertexCount; i++)
    {
        m(0, i) = vertexes.at(i).x();
        m(1, i) = vertexes.at(i).y();
        m(2, i) = vertexes.at(i).z();
    }
    // Find the mean value of x y z, center
    VectorXf avg = m.rowwise().mean();
    // compute the distance from each point to the center
    m.colwise() -= avg;
    for (int i = 0; i < 3; i++)
    {
        m_Center[i] = avg[i];
        for (int j = 0; j < nVertexCount; j++)
        {
            m_HalfLength[i] = std::max(m_HalfLength[i], std::fabs(m(i, j)));
        }
    }

    BBBoundingBox3D::computeBoxVertexes(vertexes);
}

QVector3D BBAABBBoundingBox3D::getMax()
{
    return m_pTransformedBoxVertexes[0];
}

QVector3D BBAABBBoundingBox3D::getMin()
{
    return m_pTransformedBoxVertexes[6];
}

//void OBBBoundingBox3D::computeBoundingBox()
//{
//    int vertexCount = mVertexes.count();

//    //初始化矩阵
//    MatrixXf input(3, vertexCount);
//    MatrixXf m(3, vertexCount);
//    for (int i = 0; i < vertexCount; i++)
//    {
//        m(0, i) = mVertexes.at(i).x();
//        m(1, i) = mVertexes.at(i).y();
//        m(2, i) = mVertexes.at(i).z();
//    }
//    input = m;
//    //cout << input << endl << endl;
//    //求取x y z均值
//    VectorXf avg = m.rowwise().mean();
//    m.colwise() -= avg;
//    //计算协方差矩阵 adjoint转置
//    MatrixXf covMat = (m * m.adjoint()) / float(vertexCount - 1);
//    //cout << covMat << endl << endl;
//    //求特征向量和特征值
//    SelfAdjointEigenSolver<MatrixXf> eigen(covMat);
//    MatrixXf eigenvectors = eigen.eigenvectors();
//    //cout << eigenvectors << endl << endl;
//    //将各点的（X，Y，Z）坐标投影到计算出的坐标轴上 avg由累加所有点再求均值得到 求出center和半长度
//    VectorXf minExtents(3);
//    VectorXf maxExtents(3);
//    minExtents << FLT_MAX, FLT_MAX, FLT_MAX;
//    maxExtents << -FLT_MAX, -FLT_MAX, -FLT_MAX;
//    for (int i = 0; i < vertexCount; i++)
//    {
//        VectorXf vertex = input.col(i);
//        VectorXf displacement = vertex - avg;
//        for (int j = 0; j < 3; j++)
//        {
//            minExtents[j] = min(minExtents[j], displacement.dot(eigenvectors.col(j)));
//            maxExtents[j] = max(maxExtents[j], displacement.dot(eigenvectors.col(j)));
//        }
//    }
//    VectorXf offset = (maxExtents - minExtents) / 2.0f + minExtents;
//    for (int i = 0; i < 3; i++)
//    {
//        avg += eigenvectors.col(i) * offset[i];
//    }

//    for (int i = 0; i < 3; i++)
//    {
//        center[i] = avg[i];
//        radius[i] = (maxExtents[i] - minExtents[i]) / 2.0f;
//        for (int j = 0; j < 3; j++)
//            axis[i][j] = eigenvectors.col(i)[j];
//    }
//    /*qDebug() << center[0] << center[1] << center[2];
//    qDebug() << radius[0] << radius[1] << radius[2];
//    qDebug() << axis[0][0] << axis[0][1] << axis[0][2];
//    qDebug() << axis[1][0] << axis[1][1] << axis[1][2];
//    qDebug() << axis[2][0] << axis[2][1] << axis[2][2];
//    qDebug() << endl;*/
//    getBoundingBoxVertexes();
//}

max_stars_repo_name: xiaoxianrouzhiyou/BBearEditor


text:
#ifndef MOCHIMOCHI_ADAM_HPP_
#define MOCHIMOCHI_ADAM_HPP_

#include <Eigen/Dense>
#include <cassert>
#include "../../functions/enumerate.hpp"

class ADAM {
private :
  const std::size_t kDim;

private :
  std::size_t _timestep;
  Eigen::VectorXd _w;
  Eigen::VectorXd _m;
  Eigen::VectorXd _v;

public :
  ADAM(const std::size_t dim)
    : kDim(dim),
      _timestep(0),
      _w(Eigen::VectorXd::Zero(kDim)),
      _m(Eigen::VectorXd::Zero(kDim)),
      _v(Eigen::VectorXd::Zero(kDim)) {

    assert(dim > 0);
  }

  virtual ~ADAM() { }

private :

  double suffer_loss(const Eigen::VectorXd& x, const int y) const {
    return std::max(0.0, 1.0 - y * _w.dot(x));
  }

  double calculate_margin(const Eigen::VectorXd& x) const {
    return _w.dot(x);
  }

public :

  bool update(const Eigen::VectorXd& feature, const int label) {
    constexpr auto kAlpha = 0.001;
    constexpr auto kBeta1 = 0.9;
    constexpr auto kBeta2 = 0.999;
    constexpr auto  kEpsilon = 0.00000001;
    constexpr auto kLambda = 0.99999999;

    if (suffer_loss(feature, label) <= 0.0) { return false; }

    const Eigen::VectorXd gradiant = -label * feature;
    const auto beta1_t = std::pow(kLambda, _timestep) * kBeta1;

    _timestep++;
    functions::enumerate(gradiant.data(), gradiant.data() + gradiant.size(), 0,
                       [&](const std::size_t index, const double value) {
                         _m[index] = beta1_t * _m[index] + (1.0 - beta1_t) * value;
                         _v[index] = kBeta2 * _v[index] + (1.0 - kBeta2) * value * value;
                         const auto m_t = _m[index] / (1.0 - std::pow(kBeta1, _timestep));
                         const auto v_t = _v[index] / (1.0 - std::pow(kBeta2, _timestep));
                         _w[index] -= kAlpha * m_t / (std::sqrt(v_t) + kEpsilon);
                       });

    return true;
  }

  int predict(const Eigen::VectorXd& feature) const {
    return calculate_margin(feature) > 0.0 ? 1 : -1;
  }

};

#endif //MOCHIMOCHI_ADAM_HPP_

max_stars_repo_name: olanleed/MochiMochi

max_issues_repo_name: olanleed/MochiMochi

max_forks_repo_name: olanleed/MochiMochi


text:
#include "rosbaz/app/bag_printer.h"

#include "rosbaz/bag_statistics.h"
#include <boost/format.hpp>

namespace
{
std::string human_readable_size(size_t size)
{
  if (size > 1024 * 1024 * 1024)
  {
    return std::to_string(static_cast<float>(size) / 1024.f / 1024.f / 1024.f) + " GB";
  }
  else if (size > 1024 * 1024)
  {
    return std::to_string(static_cast<float>(size) / 1024.f / 1024.f) + " MB";
  }
  else
  {
    return std::to_string(static_cast<float>(size) / 1024.f) + " KB";
  }
}
}  // namespace

namespace rosbaz
{
namespace app
{
void write_bag_human_friendly(const rosbaz::Bag& bag, std::ostream& stream)
{
  const auto connection = bag.getConnections();
  write_bag_human_friendly(bag, connection, stream);
}

void write_bag_human_friendly(const rosbaz::Bag& bag,
                              const nonstd::span<const rosbag::ConnectionInfo* const> connections, std::ostream& stream)
{
  auto start_time = bag.getBeginTime();
  auto end_time = bag.getEndTime();
  auto duration = end_time - start_time;

  stream << "path:     " << bag.getFilePath() << "\n";
  stream << "version:  " << bag.getMajorVersion() << "." << bag.getMinorVersion() << "\n";
  stream << "duration: " << duration.toSec() << "s\n";
  std::ios_base::fmtflags f(stream.flags());
  stream << "start:    " << std::fixed << std::setprecision(6) << start_time.toSec() << "\n";
  stream << "end:      " << end_time.toSec() << "\n";
  stream.flags(f);

  stream << "size:     " << human_readable_size(bag.getSize()) << "\n";

  rosbaz::BagStatistics stats{ bag };

  stream << "messages: " << stats.getTotalMessageCount() << "\n";
  stream << "chunks:   " << bag.getChunkCount() << "\n";

  const auto msg_type_infos = stats.getMessageTypeInfos(connections);
  const auto max_datatype =
      std::max_element(msg_type_infos.begin(), msg_type_infos.end(),
                       [](const auto& a, const auto& b) { return a.datatype.size() < b.datatype.size(); });

  boost::format type_fmt("%s %-" + std::to_string(max_datatype->datatype.size()) + "s [%s]\n");

  std::string prefix = "types:   ";
  for (const auto& msg_type_info : msg_type_infos)
  {
    stream << boost::str(type_fmt % prefix % msg_type_info.datatype % msg_type_info.md5sum);
    prefix = "         ";
  }

  const auto topic_infos = stats.getMessageTopicInfos(connections);
  const auto max_topic_it = std::max_element(topic_infos.begin(), topic_infos.end(), [](const auto& a, const auto& b) {
    return a.topic.size() < b.topic.size();
  });
  const auto max_msgs_it = std::max_element(topic_infos.begin(), topic_infos.end(), [](const auto& a, const auto& b) {
    return a.num_messages < b.num_messages;
  });
  const auto max_freq_it = std::max_element(topic_infos.begin(), topic_infos.end(), [](const auto& a, const auto& b) {
    return a.frequency.value_or(-1.) < b.frequency.value_or(-1.);
  });

  const size_t max_topic = max_topic_it != topic_infos.end() ? max_topic_it->topic.size() : 0;
  const size_t max_msgs = max_msgs_it != topic_infos.end() ? max_msgs_it->num_messages : 0;
  const double max_freq = max_freq_it != topic_infos.end() ? max_freq_it->frequency.value_or(0.) : 0.;

  std::string topic_fmt_string = "%s %-" + std::to_string(max_topic) + "s  %" +
                                 std::to_string(std::to_string(max_msgs).size()) + "s msgs @ %" +
                                 std::to_string((boost::format("%.1f") % max_freq).size()) + ".1f %s : %s\n";
  std::string topic_fmt_no_freq_string = "%s %-" + std::to_string(max_topic) + "s  %" +
                                         std::to_string(std::to_string(max_msgs).size()) + "s msgs    : %s\n";

  boost::format topic_fmt(topic_fmt_string);
  boost::format topic_fmt_no_freq(topic_fmt_no_freq_string);

  prefix = "topics:  ";
  for (const auto& topic_info : topic_infos)
  {
    if (topic_info.frequency)
    {
      stream << boost::str(topic_fmt % prefix % topic_info.topic % topic_info.num_messages % *topic_info.frequency %
                           "hz" % topic_info.datatype);
    }
    else
    {
      stream << boost::str(topic_fmt_no_freq % prefix % topic_info.topic % topic_info.num_messages %
                           topic_info.datatype);
    }
    prefix = "         ";
  }
}

void write_bag_yaml(const rosbaz::Bag& bag, std::ostream& stream)
{
  const auto connection = bag.getConnections();
  write_bag_yaml(bag, connection, stream);
}

void write_bag_yaml(const rosbaz::Bag& bag, const nonstd::span<const rosbag::ConnectionInfo* const> connections,
                    std::ostream& stream)
{
  auto start_time = bag.getBeginTime();
  auto end_time = bag.getEndTime();
  auto duration = end_time - start_time;

  stream << "path: " << bag.getFilePath() << "\n";
  stream << "version: " << bag.getMajorVersion() << "." << bag.getMinorVersion() << "\n";
  stream << "duration: " << duration.toSec() << "\n";
  std::ios_base::fmtflags f(stream.flags());
  stream << "start: " << std::fixed << std::setprecision(6) << start_time.toSec() << "\n";
  stream << "end: " << end_time.toSec() << "\n";
  stream.flags(f);
  stream << "size: " << bag.getSize() << "\n";

  rosbaz::BagStatistics stats{ bag };

  stream << "messages: " << stats.getTotalMessageCount() << "\n";
  stream << "indexed: "
         << "True"
         << "\n";
  stream << "compression: "
         << "none"
         << "\n";

  stream << "types:\n";

  const auto msg_type_infos = stats.getMessageTypeInfos(connections);

  for (const auto& msg_type_info : msg_type_infos)
  {
    stream << "    - type: " << msg_type_info.datatype << "\n";
    stream << "      md5: " << msg_type_info.md5sum << "\n";
  }

  stream << "topics:\n";

  const auto topic_infos = stats.getMessageTopicInfos(connections);

  for (const auto& topic_info : topic_infos)
  {
    stream << "    - topic: " << topic_info.topic << "\n";
    stream << "      type: " << topic_info.datatype << "\n";
    stream << "      messages: " << topic_info.num_messages << "\n";

    if (topic_info.frequency)
    {
      stream << "      frequency: " << *topic_info.frequency << "\n";
    }
  }
}
}  // namespace app
}  // namespace rosbaz

max_stars_repo_name: janbernloehr/rosbaz

max_issues_repo_name: janbernloehr/rosbaz

max_forks_repo_name: janbernloehr/rosbaz


text:
#pragma once
#define BOOST_NO_CXX11_DECLTYPE_N3276
#include "glhead.hpp"
#include "glx_macro.hpp"
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/container.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <string>

#define TRANSFORM_STRUCT_MEMBER(ign, name, member) (decltype(name::member), member)
#define FUSION_ADAPT_STRUCT_AUTO(name, members) \
	BOOST_FUSION_ADAPT_STRUCT(name, BOOST_PP_SEQ_FOR_EACH(TRANSFORM_STRUCT_MEMBER, name, members))

#define DEF_TYPE(typ, name, seq) struct typ##_ : x3::symbols<unsigned> { \
			enum TYPE { BOOST_PP_SEQ_FOR_EACH(PPFUNC_ENUM, T, seq) }; \
			const static char* cs_typeStr[BOOST_PP_SEQ_SIZE(seq)]; \
			typ##_(): x3::symbols<unsigned>(std::string(name)) { \
				add \
				BOOST_PP_SEQ_FOR_EACH(PPFUNC_ADD, T, seq); } }; \
		extern const typ##_ typ;
namespace rs {
	enum class VSem : unsigned int {
		BOOST_PP_SEQ_ENUM(SEQ_VSEM),
		NUM_SEMANTIC
	};
}
using namespace boost::spirit;
namespace rs {
	// ---------------- GLXシンボルリスト ----------------
	//! GLSL変数型
	DEF_TYPE(GLType, "GLSL-ValueType", SEQ_GLTYPE)
	//! GLSL変数入出力フラグ
	DEF_TYPE(GLInout, "InOut-Flag", SEQ_INOUT)
	//! GLSL頂点セマンティクス
	DEF_TYPE(GLSem, "VertexSemantics", SEQ_VSEM)
	//! GLSL浮動小数点数精度
	DEF_TYPE(GLPrecision, "PrecisionFlag", SEQ_PRECISION)
	//! boolでフラグを切り替える項目
	struct GLBoolsetting_ : x3::symbols<unsigned> {
		GLBoolsetting_(): x3::symbols<unsigned>(std::string("BooleanSettingName")) {
			add("cullface", GL_CULL_FACE)
				("polyoffsetfill", GL_POLYGON_OFFSET_FILL)
				("scissortest", GL_SCISSOR_TEST)
				("samplealphatocoverage", GL_SAMPLE_ALPHA_TO_COVERAGE)
				("samplecoverage", GL_SAMPLE_COVERAGE)
				("stenciltest", GL_STENCIL_TEST)
				("depthtest", GL_DEPTH_TEST)
				("blend", GL_BLEND)
				("dither", GL_DITHER);
		}
	};
	struct GLFillMode_ : x3::symbols<unsigned> {
		GLFillMode_(): x3::symbols<unsigned>(std::string("FillMode")) {
			add("point", GL_POINT)
				("line", GL_LINE)
				("fill", GL_FILL);
		}
	};
	//! 数値指定するタイプの設定項目フラグ
	struct GLSetting_ : x3::symbols<unsigned> {
		enum TYPE : unsigned { BOOST_PP_SEQ_FOR_EACH(PPFUNC_GLSET_ENUM, T, SEQ_GLSETTING) };
		const static char* cs_typeStr[BOOST_PP_SEQ_SIZE(SEQ_GLSETTING)];
		GLSetting_(): x3::symbols<unsigned>(std::string("SettingName")) {
				add
				BOOST_PP_SEQ_FOR_EACH(PPFUNC_GLSET_ADD, T, SEQ_GLSETTING);
		}
	};
	//! 設定項目毎に用意したほうがいい？
	struct GLStencilop_ : x3::symbols<unsigned> {
		GLStencilop_(): x3::symbols<unsigned>(std::string("StencilOperator")) {
			add("keep", GL_KEEP)
				("zero", GL_ZERO)
				("replace", GL_REPLACE)
				("increment", GL_INCR)
				("decrement", GL_DECR)
				("invert", GL_INVERT)
				("incrementwrap", GL_INCR_WRAP)
				("decrementwrap", GL_DECR_WRAP);
		}
	};
	struct GLFunc_ : x3::symbols<unsigned> {
		GLFunc_(): x3::symbols<unsigned>(std::string("CompareFunction")) {
			add("never", GL_NEVER)
				("always", GL_ALWAYS)
				("less", GL_LESS)
				("lessequal", GL_LEQUAL)
				("equal", GL_EQUAL)
				("greater", GL_GREATER)
				("greaterequal", GL_GEQUAL)
				("notequal", GL_NOTEQUAL);
		}
	};
	struct GLEq_ : x3::symbols<unsigned> {
		GLEq_(): x3::symbols<unsigned>(std::string("BlendEquation")) {
			add("add", GL_FUNC_ADD)
				("subtract", GL_FUNC_SUBTRACT)
				("invsubtract", GL_FUNC_REVERSE_SUBTRACT);
		}
	};
	struct GLBlend_ : x3::symbols<unsigned> {
		GLBlend_(): x3::symbols<unsigned>(std::string("BlendOperator")) {
			add("zero", GL_ZERO)
				("one", GL_ONE)
				("invsrccolor", GL_ONE_MINUS_SRC_COLOR)
				("invdstcolor", GL_ONE_MINUS_DST_COLOR)
				("srccolor", GL_SRC_COLOR)
				("dstcolor", GL_DST_COLOR)
				("invsrcalpha", GL_ONE_MINUS_SRC_ALPHA)
				("invdstalpha", GL_ONE_MINUS_DST_ALPHA)
				("srcalpha", GL_SRC_ALPHA)
				("dstalpha", GL_DST_ALPHA)
				("invconstantalpha", GL_ONE_MINUS_CONSTANT_ALPHA)
				("constantalpha", GL_CONSTANT_ALPHA)
				("srcalphasaturate", GL_SRC_ALPHA_SATURATE);
		}
	};
	struct GLFace_ : x3::symbols<unsigned> {
		GLFace_(): x3::symbols<unsigned>(std::string("Face(Front or Back)")) {
			add("front", GL_FRONT)
				("back", GL_BACK)
				("frontandback", GL_FRONT_AND_BACK);
		}
	};
	struct GLFacedir_ : x3::symbols<unsigned> {
		GLFacedir_(): x3::symbols<unsigned>(std::string("FaceDir")) {
			add("ccw", GL_CCW)
				("cw", GL_CW);
		}
	};
	struct GLColormask_ : x3::symbols<unsigned> {
		GLColormask_(): x3::symbols<unsigned>(std::string("ColorMask")) {
			add("r", 0x08)
				("g", 0x04)
				("b", 0x02)
				("a", 0x01);
		}
	};
	struct GLShadertype_ : x3::symbols<unsigned> {
		GLShadertype_(): x3::symbols<unsigned>(std::string("ShaderType")) {
			add("vertexshader", (unsigned)rs::ShType::VERTEX)
				("fragmentshader", (unsigned)rs::ShType::FRAGMENT)
				("geometryshader", (unsigned)rs::ShType::GEOMETRY);
		}
	};
	//! 変数ブロックタイプ
	DEF_TYPE(GLBlocktype, "BlockType", SEQ_BLOCK)

	extern const GLSetting_ GLSetting;
	extern const GLBoolsetting_ GLBoolsetting;
	extern const GLFillMode_ GLFillMode;
	extern const GLStencilop_ GLStencilop;
	extern const GLFunc_ GLFunc;
	extern const GLEq_ GLEq;
	extern const GLBlend_ GLBlend;
	extern const GLFace_ GLFace;
	extern const GLFacedir_ GLFacedir;
	extern const GLColormask_ GLColormask;
	extern const GLShadertype_ GLShadertype;

	// ---------------- GLX構文解析データ ----------------
	struct EntryBase {
		boost::optional<unsigned>	prec;
		int							type;
		std::string					name;
	};
	std::ostream& operator << (std::ostream& os, const EntryBase& e);
	//! Attribute宣言エントリ
	struct AttrEntry : EntryBase {
		unsigned					sem;
	};
	std::ostream& operator << (std::ostream& os, const AttrEntry& e);
	//! Varying宣言エントリ
	struct VaryEntry : EntryBase {
		boost::optional<int>	arraySize;
	};
	std::ostream& operator << (std::ostream& os, const VaryEntry& e);
	//! Uniform宣言エントリ
	struct UnifEntry : EntryBase {
		boost::optional<int>	arraySize;
		boost::optional<boost::variant<std::vector<float>, float, bool>>	defStr;
	};
	std::ostream& operator << (std::ostream& os, const UnifEntry& e);
	//! Const宣言エントリ
	struct ConstEntry : EntryBase {
		boost::variant<bool, float, std::vector<float>>		defVal;
	};
	std::ostream& operator << (std::ostream& os, const ConstEntry& e);
	//! Bool設定項目エントリ
	struct BoolSetting {
		GLuint				type;		//!< 設定項目ID
		bool				value;		//!< 設定値ID or 数値
	};
	std::ostream& operator << (std::ostream& os, const BoolSetting& s);
	//! 数値設定エントリ
	struct ValueSetting {
		using ValueT = boost::variant<boost::blank, unsigned int,float,bool>;

		unsigned				type;
		std::vector<ValueT>		value;
	};
	std::ostream& operator << (std::ostream& os, const ValueSetting& s);

	//! 変数ブロック使用宣言
	struct BlockUse {
		unsigned					type;	// Attr,Vary,Unif,Const
		bool						bAdd;
		std::vector<std::string>	name;
	};
	std::ostream& operator << (std::ostream& os, const BlockUse& b);
	//! シェーダー設定エントリ
	struct ShSetting {
		int							type;
		std::string					shName;
		// 引数指定
		std::vector<boost::variant<std::vector<float>, float, bool>>	args;
	};
	std::ostream& operator << (std::ostream& os, const ShSetting& s);
	//! マクロ宣言エントリ
	struct MacroEntry {
		std::string						fromStr;
		boost::optional<std::string>	toStr;
	};
	std::ostream& operator << (std::ostream& os, const MacroEntry& e);

	template <class Ent>
	struct Struct {
		std::string					name;
		std::vector<std::string>	derive;
		std::vector<Ent>			entry;

		Struct() = default;
		Struct(const Struct& a) = default;
		Struct(Struct&& a): Struct() { swap(a); }
		Struct& operator = (const Struct& a) {
			this->~Struct();
			new(this) Struct(a);
			return *this;
		}
		void swap(Struct& a) noexcept {
			std::swap(name, a.name);
			std::swap(derive, a.derive);
			std::swap(entry, a.entry);
		}
		void iterate(std::function<void (const Ent&)> cb) const {
			for(const auto& e : entry)
				cb(e);
		}
		void output(std::ostream& os) const {
			using std::endl;

			// print name
			os << '"' << name << '"' << endl;

			// print derives
			os << "derives: ";
			for(auto& d : derive)
				os << d << ", ";
			os << endl;

			// print entries
			for(auto& e : entry) {
				os << e << endl;
			}
		}
	};
	using AttrStruct = Struct<AttrEntry>;
	using VaryStruct = Struct<VaryEntry>;
	using UnifStruct = Struct<UnifEntry>;
	using ConstStruct = Struct<ConstEntry>;
	template <class T>
	std::ostream& operator << (std::ostream& os, const Struct<T>& s) {
		s.output(os);
		return os;
	}

	struct ArgItem {
		int			type;
		std::string	name;
	};
	using StrV = std::vector<std::string>;
	struct ShStruct {
		//! シェーダータイプ
		uint32_t				type;
		//! バージョン文字列
		std::string				version_str;
		//! 組み込みコードブロック名
		StrV					code;
		//! シェーダー名
		std::string				name;
		//! 引数群(型ID + 名前)
		std::vector<ArgItem>	args;
		//! シェーダーの中身(文字列)
		std::string				info;
		mutable std::string		info_str;	//!< シェーダー文字列を1つに纏めた物

		const std::string& getShaderString() const;
	};
	struct CodeStruct {
		//! コードブロック名
		std::string				name;
		//! シェーダーコード文字列
		std::string				info;
	};
	std::ostream& operator << (std::ostream& os, const CodeStruct& t);

	template <typename T>
	using NameMap = std::map<std::string, T>;
	//! Tech,Pass
	struct TPStruct;
	struct TPStruct {
		std::string					name;

		std::vector<BlockUse>		blkL;
		std::vector<BoolSetting> 	bsL;
		std::vector<MacroEntry>		mcL;
		std::vector<ShSetting>		shL;
		std::vector<boost::recursive_wrapper<TPStruct>>		tpL;
		std::vector<ValueSetting> 	vsL;

		std::vector<std::string>	derive;
	};
	std::ostream& operator << (std::ostream& os, const TPStruct& t);

	//! エフェクト全般
	struct GLXStruct {
		NameMap<AttrStruct>		atM;
		NameMap<ConstStruct>	csM;
		NameMap<ShStruct>		shM;
		std::vector<TPStruct>	tpL;
		NameMap<UnifStruct>		uniM;
		NameMap<VaryStruct>		varM;
		NameMap<CodeStruct>		codeM;
		std::vector<std::string>	incl;
	};
	std::ostream& operator << (std::ostream& os, const GLXStruct& glx);

	GLXStruct ParseGlx(std::string str);
}
FUSION_ADAPT_STRUCT_AUTO(rs::AttrEntry, (prec)(type)(name)(sem))
FUSION_ADAPT_STRUCT_AUTO(rs::VaryEntry, (prec)(type)(name)(arraySize))
FUSION_ADAPT_STRUCT_AUTO(rs::UnifEntry, (prec)(type)(name)(arraySize)(defStr))
FUSION_ADAPT_STRUCT_AUTO(rs::ConstEntry, (prec)(type)(name)(defVal))
FUSION_ADAPT_STRUCT_AUTO(rs::BoolSetting, (type)(value))
FUSION_ADAPT_STRUCT_AUTO(rs::ValueSetting, (type)(value))
FUSION_ADAPT_STRUCT_AUTO(rs::ShSetting, (type)(shName)(args))
FUSION_ADAPT_STRUCT_AUTO(rs::MacroEntry, (fromStr)(toStr))
FUSION_ADAPT_STRUCT_AUTO(rs::AttrStruct, (name)(derive)(entry))
FUSION_ADAPT_STRUCT_AUTO(rs::VaryStruct, (name)(derive)(entry))
FUSION_ADAPT_STRUCT_AUTO(rs::UnifStruct, (name)(derive)(entry))
FUSION_ADAPT_STRUCT_AUTO(rs::ConstStruct, (name)(derive)(entry))
FUSION_ADAPT_STRUCT_AUTO(rs::ShStruct, (type)(version_str)(name)(args)(info))
FUSION_ADAPT_STRUCT_AUTO(rs::TPStruct, (name)(blkL)(bsL)(mcL)(shL)(tpL)(vsL)(derive))
FUSION_ADAPT_STRUCT_AUTO(rs::GLXStruct, (atM)(csM)(shM)(tpL)(uniM)(varM)(incl))
FUSION_ADAPT_STRUCT_AUTO(rs::ArgItem, (type)(name))
FUSION_ADAPT_STRUCT_AUTO(rs::BlockUse, (type)(bAdd)(name))

max_stars_repo_name: degarashi/resonant

max_issues_repo_name: degarashi/resonant

max_forks_repo_name: degarashi/resonant