text:
// Copyright 2010-2015 RethinkDB, all rights reserved.
#ifndef RDB_PROTOCOL_PROTOCOL_HPP_
#define RDB_PROTOCOL_PROTOCOL_HPP_

#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "errors.hpp"
#include <boost/variant.hpp>

#include "btree/secondary_operations.hpp"
#include "clustering/administration/auth/user_context.hpp"
#include "concurrency/cond_var.hpp"
#include "containers/optional.hpp"
#include "perfmon/perfmon.hpp"
#include "protocol_api.hpp"
#include "rdb_protocol/changefeed.hpp"
#include "rdb_protocol/configured_limits.hpp"
#include "rdb_protocol/context.hpp"
#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/datumspec.hpp"
#include "rdb_protocol/erase_range.hpp"
#include "rdb_protocol/geo/ellipsoid.hpp"
#include "rdb_protocol/geo/lon_lat_types.hpp"
#include "rdb_protocol/optargs.hpp"
#include "rdb_protocol/shards.hpp"
#include "region/region.hpp"
#include "repli_timestamp.hpp"
#include "rpc/mailbox/typed.hpp"

class store_t;
class buf_lock_t;
template <class> class clone_ptr_t;
template <class> class cross_thread_watchable_variable_t;
class cross_thread_signal_t;
struct secondary_index_t;
class traversal_progress_combiner_t;
template <class> class watchable_t;

enum class profile_bool_t {
    PROFILE,
    DONT_PROFILE
};
ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(
        profile_bool_t, int8_t,
        profile_bool_t::PROFILE, profile_bool_t::DONT_PROFILE);

enum class point_write_result_t {
    STORED,
    DUPLICATE
};
ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(
        point_write_result_t, int8_t,
        point_write_result_t::STORED, point_write_result_t::DUPLICATE);

enum class point_delete_result_t {
    DELETED,
    MISSING
};
ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(
        point_delete_result_t, int8_t,
        point_delete_result_t::DELETED, point_delete_result_t::MISSING);

class key_le_t {
public:
    explicit key_le_t(sorting_t _sorting) : sorting(_sorting) { }
    bool is_le(const store_key_t &key1, const store_key_t &key2) const {
        return (!reversed(sorting) && key1 <= key2)
            || (reversed(sorting) && key2 <= key1);
    }
private:
    sorting_t sorting;
};

namespace ql {
class datum_t;
class primary_readgen_t;
class readgen_t;
class sindex_readgen_t;
class intersecting_readgen_t;
} // namespace ql

namespace rdb_protocol {

void resume_construct_sindex(
        const uuid_u &sindex_to_construct,
        const key_range_t &construct_range,
        store_t *store,
        auto_drainer_t::lock_t store_keepalive)
    THROWS_NOTHING;

} // namespace rdb_protocol

struct point_read_response_t {
    ql::datum_t data;
    point_read_response_t() { }
    explicit point_read_response_t(ql::datum_t _data)
        : data(_data) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(point_read_response_t);

struct shard_stamp_info_t {
    uint64_t stamp;
    region_t shard_region;
    // The starting points of the reads (assuming left to right traversal)
    store_key_t last_read_start;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(shard_stamp_info_t);

struct changefeed_stamp_response_t {
    changefeed_stamp_response_t() { }
    // The `uuid_u` below is the uuid of the changefeed `server_t`.  (We have
    // different timestamps for each `server_t` because they're on different
    // servers and don't synchronize with each other.)  If this is empty it
    // means the feed was aborted.
    optional<std::map<uuid_u, shard_stamp_info_t> > stamp_infos;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(changefeed_stamp_response_t);

struct rget_read_response_t {
    optional<changefeed_stamp_response_t> stamp_response;
    ql::result_t result;
    reql_version_t reql_version;

    rget_read_response_t()
        : reql_version(reql_version_t::EARLIEST) { }
    explicit rget_read_response_t(const ql::exc_t &ex)
        : result(ex), reql_version(reql_version_t::EARLIEST) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(rget_read_response_t);

struct nearest_geo_read_response_t {
    typedef std::pair<double, ql::datum_t> dist_pair_t;
    typedef std::vector<dist_pair_t> result_t;
    boost::variant<result_t, ql::exc_t> results_or_error;

    nearest_geo_read_response_t() { }
    explicit nearest_geo_read_response_t(result_t &&_results) {
        // Implement "move" on _results through std::vector<...>::swap to avoid
        // problems with boost::variant not supporting move assignment.
        results_or_error = result_t();
        boost::get<result_t>(&results_or_error)->swap(_results);
    }
    explicit nearest_geo_read_response_t(const ql::exc_t &_error)
        : results_or_error(_error) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(nearest_geo_read_response_t);

void scale_down_distribution(size_t result_limit, std::map<store_key_t, int64_t> *key_counts);

struct distribution_read_response_t {
    // Supposing the map has keys:
    // k1, k2 ... kn
    // with k1 < k2 < .. < kn
    // Then k1 == left_key
    // and key_counts[ki] = the number of keys in [ki, ki+1) if i < n
    // key_counts[kn] = the number of keys in [kn, right_key)
    region_t region;
    std::map<store_key_t, int64_t> key_counts;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(distribution_read_response_t);

struct changefeed_subscribe_response_t {
    changefeed_subscribe_response_t() { }
    std::set<uuid_u> server_uuids;
    std::set<ql::changefeed::server_t::addr_t> addrs;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(changefeed_subscribe_response_t);

struct changefeed_limit_subscribe_response_t {
    int64_t shards;
    std::vector<ql::changefeed::server_t::limit_addr_t> limit_addrs;

    changefeed_limit_subscribe_response_t() { }
    changefeed_limit_subscribe_response_t(
        int64_t _shards, decltype(limit_addrs) _limit_addrs)
        : shards(_shards), limit_addrs(std::move(_limit_addrs)) { }
};
RDB_DECLARE_SERIALIZABLE(changefeed_limit_subscribe_response_t);

struct changefeed_point_stamp_response_t {
    changefeed_point_stamp_response_t() { }
    // The `uuid_u` below is the uuid of the changefeed `server_t`.  (We have
    // different timestamps for each `server_t` because they're on different
    // servers and don't synchronize with each other.)
    struct valid_response_t {
        std::pair<uuid_u, uint64_t> stamp;
        ql::datum_t initial_val;
    };
    // If this is empty it means the feed was aborted.
    optional<valid_response_t> resp;
};
RDB_DECLARE_SERIALIZABLE(changefeed_point_stamp_response_t::valid_response_t);
RDB_DECLARE_SERIALIZABLE(changefeed_point_stamp_response_t);

struct dummy_read_response_t {
    // dummy read always succeeds
};

RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(dummy_read_response_t);

struct serializable_env_t {
    // The global optargs values passed to .run(...) in the Python, Ruby, and JS
    // drivers.
    ql::global_optargs_t global_optargs;

    // The user that's evaluating this query
    auth::user_context_t user_context;

    // The time that the most recent request started processing, set in fill_response
    // in query_cache.cc
    // Used to evaluate r.now in a deterministic way.
    ql::datum_t deterministic_time;
};

RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(serializable_env_t);

struct read_response_t {
    typedef boost::variant<point_read_response_t,
                           rget_read_response_t,
                           nearest_geo_read_response_t,
                           changefeed_subscribe_response_t,
                           changefeed_limit_subscribe_response_t,
                           changefeed_stamp_response_t,
                           changefeed_point_stamp_response_t,
                           distribution_read_response_t,
                           dummy_read_response_t> variant_t;
    variant_t response;
    profile::event_log_t event_log;
    size_t n_shards;

    read_response_t() { }
    explicit read_response_t(const variant_t &r)
        : response(r) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(read_response_t);

class point_read_t {
public:
    point_read_t() { }
    explicit point_read_t(const store_key_t& _key) : key(_key) { }

    store_key_t key;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(point_read_t);

// `dummy_read_t` can be used to poll for table readiness - it will go through all
// the clustering layers, but is a no-op in the protocol layer.
class dummy_read_t {
public:
    dummy_read_t() : region(region_t::universe()) { }
    region_t region;
};

RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(dummy_read_t);

struct sindex_rangespec_t {
    sindex_rangespec_t() { }
    sindex_rangespec_t(const std::string &_id,
                       // This is the region in the sindex keyspace.  It's
                       // sometimes smaller than the datum range below when
                       // dealing with truncated keys.
                       optional<region_t> _region,
                       ql::datumspec_t _datumspec,
                       require_sindexes_t _require_sindex_val = require_sindexes_t::NO)
        : id(_id),
          region(std::move(_region)),
          datumspec(std::move(_datumspec)),
          require_sindex_val(_require_sindex_val){ }
    std::string id; // What sindex we're using.
    // What keyspace we're currently operating on.  If empty, assume the
    // original range and create the readgen on the shards.
    optional<region_t> region;
    // For dealing with truncation and `get_all`.
    ql::datumspec_t datumspec;
    // For forcing sindex values to be returned with sorting::UNORDERED, used in eq_join.
    require_sindexes_t require_sindex_val;
};

RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(sindex_rangespec_t);

struct changefeed_stamp_t {
    changefeed_stamp_t() : region(region_t::universe()) { }
    explicit changefeed_stamp_t(ql::changefeed::client_t::addr_t _addr)
        : addr(std::move(_addr)), region(region_t::universe()) { }
    ql::changefeed::client_t::addr_t addr;
    region_t region;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(changefeed_stamp_t);

class rget_read_t {
public:
    rget_read_t() : batchspec(ql::batchspec_t::empty()) { }

    rget_read_t(optional<changefeed_stamp_t> &&_stamp,
                region_t _region,
                optional<std::map<region_t, store_key_t> > _hints,
                optional<std::map<store_key_t, uint64_t> > _primary_keys,
                serializable_env_t s_env,
                std::string _table_name,
                ql::batchspec_t _batchspec,
                std::vector<ql::transform_variant_t> _transforms,
                optional<ql::terminal_variant_t> &&_terminal,
                optional<sindex_rangespec_t> &&_sindex,
                sorting_t _sorting)
    : stamp(std::move(_stamp)),
      region(std::move(_region)),
      hints(std::move(_hints)),
      primary_keys(std::move(_primary_keys)),
      serializable_env(std::move(s_env)),
      table_name(std::move(_table_name)),
      batchspec(std::move(_batchspec)),
      transforms(std::move(_transforms)),
      terminal(std::move(_terminal)),
      sindex(std::move(_sindex)),
      sorting(std::move(_sorting)) { }

    optional<changefeed_stamp_t> stamp;

    region_t region; // We need this even for sindex reads due to sharding.
    optional<region_t> current_shard;
    optional<std::map<region_t, store_key_t> > hints;

    // The `uint64_t`s here are counts.  This map is used to make `get_all` more
    // efficient, and it's legal to pass duplicate keys to `get_all`.
    optional<std::map<store_key_t, uint64_t> > primary_keys;

    serializable_env_t serializable_env;
    std::string table_name;
    ql::batchspec_t batchspec; // used to size batches

    // We use these two for lazy maps, reductions, etc.
    std::vector<ql::transform_variant_t> transforms;
    optional<ql::terminal_variant_t> terminal;

    // This is non-empty if we're doing an sindex read.
    // TODO: `read_t` should maybe be multiple types.  Determining the type
    // of read by branching on whether an optional is full sucks.
    optional<sindex_rangespec_t> sindex;

    sorting_t sorting; // Optional sorting info (UNORDERED means no sorting).
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(rget_read_t);

class intersecting_geo_read_t {
public:
    intersecting_geo_read_t() : batchspec(ql::batchspec_t::empty()) { }

    intersecting_geo_read_t(
        optional<changefeed_stamp_t> &&_stamp,
        region_t _region,
        serializable_env_t s_env,
        std::string _table_name,
        ql::batchspec_t _batchspec,
        std::vector<ql::transform_variant_t> _transforms,
        optional<ql::terminal_variant_t> &&_terminal,
        sindex_rangespec_t &&_sindex,
        ql::datum_t _query_geometry)
        : stamp(std::move(_stamp)),
          region(std::move(_region)),
          serializable_env(s_env),
          table_name(std::move(_table_name)),
          batchspec(std::move(_batchspec)),
          transforms(std::move(_transforms)),
          terminal(std::move(_terminal)),
          sindex(std::move(_sindex)),
          query_geometry(std::move(_query_geometry)) { }

    optional<changefeed_stamp_t> stamp;

    region_t region; // Primary key range. We need this because of sharding.
    serializable_env_t serializable_env;
    std::string table_name;
    ql::batchspec_t batchspec; // used to size batches

    // We use these two for lazy maps, reductions, etc.
    std::vector<ql::transform_variant_t> transforms;
    optional<ql::terminal_variant_t> terminal;

    sindex_rangespec_t sindex;

    ql::datum_t query_geometry; // Tested for intersection
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(intersecting_geo_read_t);

class nearest_geo_read_t {
public:
    nearest_geo_read_t() { }

    nearest_geo_read_t(
            const region_t &_region,
            lon_lat_point_t _center,
            double _max_dist,
            uint64_t _max_results,
            const ellipsoid_spec_t &_geo_system,
            const std::string &_table_name,
            const std::string &_sindex_id,
            serializable_env_t s_env)
        : serializable_env(std::move(s_env)),
          center(_center),
          max_dist(_max_dist),
          max_results(_max_results),
          geo_system(_geo_system),
          region(_region),
          table_name(_table_name),
          sindex_id(_sindex_id) { }

    serializable_env_t serializable_env;

    lon_lat_point_t center;
    double max_dist;
    uint64_t max_results;
    ellipsoid_spec_t geo_system;

    region_t region; // We need this even for sindex reads due to sharding.
    std::string table_name;

    std::string sindex_id;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(nearest_geo_read_t);

class distribution_read_t {
public:
    distribution_read_t()
        : max_depth(0), result_limit(0), region(region_t::universe())
    { }
    distribution_read_t(int _max_depth, size_t _result_limit)
        : max_depth(_max_depth), result_limit(_result_limit),
          region(region_t::universe())
    { }

    int max_depth;
    size_t result_limit;
    region_t region;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(distribution_read_t);

struct changefeed_subscribe_t {
    changefeed_subscribe_t() { }
    explicit changefeed_subscribe_t(ql::changefeed::client_t::addr_t _addr)
        : addr(_addr), shard_region(region_t::universe()) { }
    ql::changefeed::client_t::addr_t addr;
    region_t shard_region;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(changefeed_subscribe_t);

struct changefeed_limit_subscribe_t {
    changefeed_limit_subscribe_t() { }
    explicit changefeed_limit_subscribe_t(
        ql::changefeed::client_t::addr_t _addr,
        uuid_u _uuid,
        ql::changefeed::keyspec_t::limit_t _spec,
        std::string _table,
        serializable_env_t s_env,
        region_t pkey_region)
        : addr(std::move(_addr)),
          uuid(std::move(_uuid)),
          spec(std::move(_spec)),
          table(std::move(_table)),
          serializable_env(std::move(s_env)),
          region(std::move(pkey_region)) { }
    ql::changefeed::client_t::addr_t addr;
    uuid_u uuid;
    ql::changefeed::keyspec_t::limit_t spec;
    std::string table;
    serializable_env_t serializable_env;
    region_t region;
    optional<region_t> current_shard;
};
RDB_DECLARE_SERIALIZABLE(changefeed_limit_subscribe_t);

// This is a separate class because it needs to shard and unshard differently.
struct changefeed_point_stamp_t {
    ql::changefeed::client_t::addr_t addr;
    store_key_t key;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(changefeed_point_stamp_t);

struct read_t {
    typedef boost::variant<point_read_t,
                           rget_read_t,
                           intersecting_geo_read_t,
                           nearest_geo_read_t,
                           changefeed_subscribe_t,
                           changefeed_stamp_t,
                           changefeed_limit_subscribe_t,
                           changefeed_point_stamp_t,
                           distribution_read_t,
                           dummy_read_t> variant_t;

    variant_t read;
    profile_bool_t profile;
    read_mode_t read_mode;

    region_t get_region() const THROWS_NOTHING;
    // Returns true if the read has any operation for this region.  Returns
    // false if read_out has not been touched.
    bool shard(const region_t &region,
               read_t *read_out) const THROWS_NOTHING;

    void unshard(read_response_t *responses, size_t count,
                 read_response_t *response, rdb_context_t *ctx,
                 signal_t *interruptor) const
        THROWS_ONLY(interrupted_exc_t);

    read_t() : profile(profile_bool_t::DONT_PROFILE), read_mode(read_mode_t::SINGLE) { }
    template<class T>
    read_t(T &&_read, profile_bool_t _profile, read_mode_t _read_mode)
        : read(std::forward<T>(_read)), profile(_profile), read_mode(_read_mode) { }

    // We use snapshotting for queries that acquire-and-hold large portions of the
    // table, so that they don't block writes.
    bool use_snapshot() const THROWS_NOTHING;

    // At the moment changefeed reads must be routed to the primary replica.
    bool route_to_primary() const THROWS_NOTHING;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(read_t);

struct point_write_response_t {
    point_write_result_t result;

    point_write_response_t() { }
    explicit point_write_response_t(point_write_result_t _result)
        : result(_result)
    { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(point_write_response_t);

struct point_delete_response_t {
    point_delete_result_t result;
    point_delete_response_t() {}
    explicit point_delete_response_t(point_delete_result_t _result)
        : result(_result)
    { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(point_delete_response_t);

struct sync_response_t {
    // sync always succeeds
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(sync_response_t);

struct dummy_write_response_t {
    // dummy write always succeeds
};

RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(dummy_write_response_t);

typedef ql::datum_t batched_replace_response_t;

struct write_response_t {
    boost::variant<batched_replace_response_t,
                   // batched_replace_response_t is also for batched_insert
                   point_write_response_t,
                   point_delete_response_t,
                   sync_response_t,
                   dummy_write_response_t> response;

    profile::event_log_t event_log;
    size_t n_shards;

    write_response_t() { }
    template<class T>
    explicit write_response_t(const T &t) : response(t) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(write_response_t);

struct batched_replace_t {
    batched_replace_t() { }
    batched_replace_t(
            std::vector<store_key_t> &&_keys,
            const std::string &_pkey,
            const counted_t<const ql::func_t> &func,
            const optional<counted_t<const ql::func_t> > &wh,
            serializable_env_t s_env,
            return_changes_t _return_changes)
        : keys(std::move(_keys)),
          pkey(_pkey),
          f(func),
          serializable_env(std::move(s_env)),
          return_changes(_return_changes) {
        r_sanity_check(keys.size() != 0);

        if (wh.has_value()) {
            write_hook.set(ql::wire_func_t(*wh));
        }

    }
    std::vector<store_key_t> keys;
    std::string pkey;
    ql::wire_func_t f;
    optional<ql::wire_func_t> write_hook;
    serializable_env_t serializable_env;
    return_changes_t return_changes;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(batched_replace_t);

struct batched_insert_t {
    batched_insert_t() { }
    batched_insert_t(
        std::vector<ql::datum_t> &&_inserts,
        const std::string &_pkey,
        const optional<counted_t<const ql::func_t> > &_write_hook,
        conflict_behavior_t _conflict_behavior,
        const optional<counted_t<const ql::func_t> > &_conflict_func,
        const ql::configured_limits_t &_limits,
        serializable_env_t s_env,
        return_changes_t _return_changes);

    std::vector<ql::datum_t> inserts;
    std::string pkey;
    optional<ql::wire_func_t> write_hook;
    conflict_behavior_t conflict_behavior;
    optional<ql::wire_func_t> conflict_func;
    ql::configured_limits_t limits;
    serializable_env_t serializable_env;
    return_changes_t return_changes;
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(batched_insert_t);

class point_write_t {
public:
    point_write_t() { }
    point_write_t(const store_key_t& _key,
                  ql::datum_t _data,
                  bool _overwrite = true)
        : key(_key), data(_data), overwrite(_overwrite) { }

    store_key_t key;
    ql::datum_t data;
    bool overwrite;
};
RDB_DECLARE_SERIALIZABLE(point_write_t);

class point_delete_t {
public:
    point_delete_t() { }
    explicit point_delete_t(const store_key_t& _key)
        : key(_key) { }

    store_key_t key;
};
RDB_DECLARE_SERIALIZABLE(point_delete_t);

class sync_t {
public:
    sync_t()
        : region(region_t::universe())
    { }

    region_t region;
};
RDB_DECLARE_SERIALIZABLE(sync_t);

// `dummy_write_t` can be used to poll for table readiness - it will go through all
// the clustering layers, but is a no-op in the protocol layer.
class dummy_write_t {
public:
    dummy_write_t() : region(region_t::universe()) { }
    region_t region;
};
RDB_DECLARE_SERIALIZABLE(dummy_write_t);

struct write_t {
    typedef boost::variant<batched_replace_t,
                           batched_insert_t,
                           point_write_t,
                           point_delete_t,
                           sync_t,
                           dummy_write_t> variant_t;
    variant_t write;

    durability_requirement_t durability_requirement;
    profile_bool_t profile;
    ql::configured_limits_t limits;

    region_t get_region() const THROWS_NOTHING;
    // Returns true if the write had any side effects applicable to the
    // region, and a non-empty write was written to write_out.
    bool shard(const region_t &region,
               write_t *write_out) const THROWS_NOTHING;
    void unshard(write_response_t *responses, size_t count,
                 write_response_t *response, rdb_context_t *cache, signal_t *)
        const THROWS_NOTHING;

    // This is currently used to improve the cache's write transaction throttling.
    int expected_document_changes() const;

    durability_requirement_t durability() const { return durability_requirement; }

    /* The clustering layer calls this. */
    static write_t make_sync(const region_t &region, profile_bool_t profile) {
        sync_t sync;
        sync.region = region;
        return write_t(
            sync,
            DURABILITY_REQUIREMENT_HARD,
            profile,
            ql::configured_limits_t());
    }

    write_t() :
        durability_requirement(DURABILITY_REQUIREMENT_DEFAULT),
        profile(profile_bool_t::DONT_PROFILE),
        limits() {}
    /*  Note that for durability != DURABILITY_REQUIREMENT_HARD, sync might
     *  not have the desired effect (of writing unsaved data to disk).
     *  However there are cases where we use sync internally (such as when
     *  splitting up batched replaces/inserts) and want it to only have an
     *  effect if DURABILITY_REQUIREMENT_DEFAULT resolves to hard
     *  durability. */
    template<class T>
    write_t(T &&t,
            durability_requirement_t _durability,
            profile_bool_t _profile,
            const ql::configured_limits_t &_limits)
        : write(std::forward<T>(t)),
          durability_requirement(_durability), profile(_profile),
          limits(_limits) { }
    template<class T>
    write_t(T &&t, profile_bool_t _profile,
            const ql::configured_limits_t &_limits)
        : write(std::forward<T>(t)),
          durability_requirement(DURABILITY_REQUIREMENT_DEFAULT),
          profile(_profile),
          limits(_limits) { }
};
RDB_DECLARE_SERIALIZABLE_FOR_CLUSTER(write_t);

class store_t;

namespace rdb_protocol {
const size_t MAX_PRIMARY_KEY_SIZE = 128;

// Construct a region containing only the specified key
region_t monokey_region(const store_key_t &k);

// Constructs a region which will query an sindex for matches to a specific key
// TODO consider relocating this
key_range_t sindex_key_range(const store_key_t &start,
                             const store_key_t &end,
                             key_range_t::bound_t end_type);
}  // namespace rdb_protocol

namespace rdb_protocol {
/* TODO: This might be redundant. I thought that `key_tester_t` was only
originally necessary because in v1.1.x the hashing scheme might be different
between the source and destination servers. */
struct range_key_tester_t : public key_tester_t {
    explicit range_key_tester_t(const region_t *_delete_range) : delete_range(_delete_range) { }
    virtual ~range_key_tester_t() { }
    bool key_should_be_erased(const btree_key_t *key);

    const region_t *delete_range;
};
} // namespace rdb_protocol

#endif  // RDB_PROTOCOL_PROTOCOL_HPP_

max_stars_repo_name: zadcha/rethinkdb

max_issues_repo_name: zadcha/rethinkdb

max_forks_repo_name: zadcha/rethinkdb


text:
// (c) Copyright Jeremy Siek 2002.

// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Sample output:
// <This> <is> <,> <a> <test>

// char_sep_example_3.cpp
#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>

int main()
{
   std::string str = "This is,  a test";
   typedef boost::tokenizer<boost::char_separator<char> > Tok;
   boost::char_separator<char> sep; // default constructed
   Tok tok(str, sep);
   for(Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter)
     std::cout << "<" << *tok_iter << "> ";
   std::cout << "\n";
   return EXIT_SUCCESS;
}

ext: cpp

max_stars_repo_name: randolphwong/mcsema

max_issues_repo_name: randolphwong/mcsema

max_forks_repo_name: randolphwong/mcsema


text:
#include "util/packed_vector.hpp"
#include "util/typedefs.hpp"

#include <boost/test/test_case_template.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(packed_vector_test)

using namespace osrm;
using namespace osrm::util;

// Verify that the packed vector behaves as expected
BOOST_AUTO_TEST_CASE(insert_and_retrieve_packed_test)
{
    PackedVector<OSMNodeID, false> packed_ids;
    std::vector<OSMNodeID> original_ids;

    const constexpr std::size_t num_test_cases = 399;

    for (std::size_t i = 0; i < num_test_cases; i++)
    {
        OSMNodeID r {static_cast<std::uint64_t>(rand() % 2147483647)}; // max 33-bit uint

        packed_ids.push_back(r);
        original_ids.push_back(r);
    }

    for (std::size_t i = 0; i < num_test_cases; i++)
    {
        BOOST_CHECK_EQUAL(original_ids.at(i), packed_ids.at(i));
    }
}

BOOST_AUTO_TEST_CASE(packed_vector_capacity_test)
{
    PackedVector<OSMNodeID, false> packed_vec;
    const std::size_t original_size = packed_vec.capacity();
    std::vector<OSMNodeID> dummy_vec;

    BOOST_CHECK_EQUAL(original_size, dummy_vec.capacity());

    packed_vec.reserve(100);

    BOOST_CHECK(packed_vec.capacity() >= 100);
}

BOOST_AUTO_TEST_SUITE_END()


text:
#ifndef BOOST_PP_IS_ITERATING
    ///////////////////////////////////////////////////////////////////////////////
    /// \file matches.hpp
    /// Contains definition of matches\<\> metafunction for determining if
    /// a given expression matches a given pattern.
    //
    //  Copyright 2007 Eric Niebler. Distributed under the Boost
    //  Software License, Version 1.0. (See accompanying file
    //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

    #ifndef BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006
    #define BOOST_PROTO_MATCHES_HPP_EAN_11_03_2006

    #include <boost/xpressive/proto/detail/prefix.hpp> // must be first include
    #include <boost/preprocessor/cat.hpp>
    #include <boost/preprocessor/arithmetic/dec.hpp>
    #include <boost/preprocessor/arithmetic/sub.hpp>
    #include <boost/preprocessor/repetition/enum.hpp>
    #include <boost/preprocessor/iteration/iterate.hpp>
    #include <boost/preprocessor/facilities/intercept.hpp>
    #include <boost/preprocessor/punctuation/comma_if.hpp>
    #include <boost/preprocessor/repetition/enum_params.hpp>
    #include <boost/preprocessor/repetition/enum_shifted.hpp>
    #include <boost/preprocessor/repetition/enum_shifted_params.hpp>
    #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
    #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
    #include <boost/config.hpp>
    #include <boost/mpl/logical.hpp>
    #include <boost/mpl/apply.hpp>
    #include <boost/mpl/aux_/template_arity.hpp>
    #include <boost/mpl/aux_/lambda_arity_param.hpp>
    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits/is_convertible.hpp>
    #include <boost/type_traits/is_reference.hpp>
    #include <boost/type_traits/is_pointer.hpp>
    #include <boost/xpressive/proto/proto_fwd.hpp>
    #include <boost/xpressive/proto/traits.hpp>
    #include <boost/xpressive/proto/detail/suffix.hpp> // must be last include

    // Some compilers (like GCC) need extra help figuring out a template's arity.
    // I use MPL's BOOST_MPL_AUX_LAMBDA_ARITY_PARAM() macro to disambiguate, which
    // which is controlled by the BOOST_MPL_LIMIT_METAFUNCTION_ARITY macro. If
    // You define BOOST_PROTO_MAX_ARITY to be greater than
    // BOOST_MPL_LIMIT_METAFUNCTION_ARITY on these compilers, things don't work.
    // You must define BOOST_MPL_LIMIT_METAFUNCTION_ARITY to be greater.
    #ifdef BOOST_MPL_CFG_EXTENDED_TEMPLATE_PARAMETERS_MATCHING
    # if BOOST_PROTO_MAX_ARITY > BOOST_MPL_LIMIT_METAFUNCTION_ARITY
    #  error BOOST_MPL_LIMIT_METAFUNCTION_ARITY must be at least as large as BOOST_PROTO_MAX_ARITY
    # endif
    #endif

    #if defined(_MSC_VER) && (_MSC_VER >= 1020)
    # pragma warning(push)
    # pragma warning(disable:4305) // 'specialization' : truncation from 'const int' to 'bool'
    #endif

    namespace boost { namespace proto
    {

        namespace detail
        {
            struct _;

            template<typename Expr, typename Grammar>
            struct matches_impl;

            // and_ and or_ implementation
            template<bool B, typename Expr, typename G0>
            struct or1
              : mpl::bool_<B>
            {
                typedef G0 which;
            };

            template<bool B>
            struct and1
              : mpl::bool_<B>
            {};

            template<bool B, typename Pred>
            struct and2;

            template<typename And>
            struct last;

            template<typename T, typename U
                BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(long Arity = mpl::aux::template_arity<U>::value)
            >
            struct lambda_matches
              : mpl::false_
            {};

            template<typename T>
            struct lambda_matches<T, proto::_ BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(-1)>
              : mpl::true_
            {};

            template<typename T>
            struct lambda_matches<T, T BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(-1)>
              : mpl::true_
            {};

            template<template<typename> class T, typename Expr0, typename Grammar0>
            struct lambda_matches<T<Expr0>, T<Grammar0> BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(1) >
              : lambda_matches<Expr0, Grammar0>
            {};

            // vararg_matches_impl
            template<typename Args1, typename Back, long From, long To>
            struct vararg_matches_impl;

            // vararg_matches
            template<typename Args1, typename Args2, typename Back, bool Can, bool Zero, typename EnableIf = void>
            struct vararg_matches
              : mpl::false_
            {};

            template<typename Args1, typename Args2, typename Back>
            struct vararg_matches<Args1, Args2, Back, true, true, typename Back::proto_is_vararg_>
              : matches_impl<expr<_, Args1, Args1::size>, expr<_, Args2, Args1::size> >
            {};

            template<typename Args1, typename Args2, typename Back>
            struct vararg_matches<Args1, Args2, Back, true, false, typename Back::proto_is_vararg_>
              : and2<
                    matches_impl<expr<_, Args1, Args2::size>, expr<_, Args2, Args2::size> >::value
                  , vararg_matches_impl<Args1, typename Back::proto_base_expr, Args2::size + 1, Args1::size>
                >
            {};

            // How terminal_matches<> handles references and cv-qualifiers.
            // The cv and ref_ matter *only* if the grammar has a top-level ref_.
            //
            // Expr     |   Grammar  |  Match
            // ------------------------------
            // T            T           yes
            // T &          T           yes
            // T const &    T           yes
            // T            T &         no
            // T &          T &         yes
            // T const &    T &         no
            // T            T const &   no
            // T &          T const &   no
            // T const &    T const &   yes

            template<typename T, typename U>
            struct is_cv_ref_compatible
              : mpl::true_
            {};

            template<typename T, typename U>
            struct is_cv_ref_compatible<T, U &>
              : mpl::false_
            {};

            template<typename T, typename U>
            struct is_cv_ref_compatible<T &, U &>
              : mpl::bool_<is_const<T>::value == is_const<U>::value>
            {};

        #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
            // MSVC-7.1 has lots of problems with array types that have been
            // deduced. Partially specializing terminal_matches<> on array types
            // doesn't seem to work.
            template<
                typename T
              , typename U
              , bool B = is_array<typename remove_cv_ref<T>::type>::value
            >
            struct terminal_array_matches
              : mpl::false_
            {};

            template<typename T, typename U, std::size_t M>
            struct terminal_array_matches<T, U(&)[M], true>
              : is_convertible<T, U(&)[M]>
            {};

            template<typename T, typename U>
            struct terminal_array_matches<T, U(&)[proto::N], true>
              : is_convertible<T, U *>
            {};

            template<typename T, typename U>
            struct terminal_array_matches<T, U *, true>
              : is_convertible<T, U *>
            {};

            // terminal_matches
            template<typename T, typename U>
            struct terminal_matches
              : mpl::or_<
                    mpl::and_<
                        is_cv_ref_compatible<T, U>
                      , lambda_matches<
                            typename remove_cv_ref<T>::type
                          , typename remove_cv_ref<U>::type
                        >
                    >
                  , terminal_array_matches<T, U>
                >
            {};
        #else
            // terminal_matches
            template<typename T, typename U>
            struct terminal_matches
              : mpl::and_<
                    is_cv_ref_compatible<T, U>
                  , lambda_matches<
                        typename remove_cv_ref<T>::type
                      , typename remove_cv_ref<U>::type
                    >
                >
            {};

            template<typename T, std::size_t M>
            struct terminal_matches<T(&)[M], T(&)[proto::N]>
              : mpl::true_
            {};

            template<typename T, std::size_t M>
            struct terminal_matches<T(&)[M], T *>
              : mpl::true_
            {};
        #endif

            template<typename T>
            struct terminal_matches<T, T>
              : mpl::true_
            {};

            template<typename T>
            struct terminal_matches<T &, T>
              : mpl::true_
            {};

            template<typename T>
            struct terminal_matches<T const &, T>
              : mpl::true_
            {};

            template<typename T>
            struct terminal_matches<T, proto::_>
              : mpl::true_
            {};

            template<typename T>
            struct terminal_matches<T, exact<T> >
              : mpl::true_
            {};

            template<typename T, typename U>
            struct terminal_matches<T, proto::convertible_to<U> >
              : is_convertible<T, U>
            {};

            // matches_impl
            template<typename Expr, typename Grammar>
            struct matches_impl
              : mpl::false_
            {};

            template<typename Expr>
            struct matches_impl< Expr, proto::_ >
              : mpl::true_
            {};

            template<typename Tag, typename Args1, long N1, typename Args2, long N2>
            struct matches_impl< expr<Tag, Args1, N1>, expr<Tag, Args2, N2> >
              : vararg_matches< Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) >
            {};

            template<typename Tag, typename Args1, long N1, typename Args2, long N2>
            struct matches_impl< expr<Tag, Args1, N1>, expr<proto::_, Args2, N2> >
              : vararg_matches< Args1, Args2, typename Args2::back_, (N1+2 > N2), (N2 > N1) >
            {};

            template<typename Args1, typename Args2, long N2>
            struct matches_impl< expr<tag::terminal, Args1, 0>, expr<proto::_, Args2, N2> >
              : mpl::false_
            {};

            template<typename Tag, typename Args1, typename Args2>
            struct matches_impl< expr<Tag, Args1, 1>, expr<Tag, Args2, 1> >
              : matches_impl<typename Args1::arg0::proto_base_expr, typename Args2::arg0::proto_base_expr>
            {};

            template<typename Tag, typename Args1, typename Args2>
            struct matches_impl< expr<Tag, Args1, 1>, expr<proto::_, Args2, 1> >
              : matches_impl<typename Args1::arg0::proto_base_expr, typename Args2::arg0::proto_base_expr>
            {};

            template<typename Args1, typename Args2>
            struct matches_impl< expr<tag::terminal, Args1, 0>, expr<tag::terminal, Args2, 0> >
              : terminal_matches<typename Args1::arg0, typename Args2::arg0>
            {};

        #define BOOST_PROTO_MATCHES_N_FUN(z, n, data)\
            matches_impl<\
                typename Args1::BOOST_PP_CAT(arg, n)::proto_base_expr\
              , typename Args2::BOOST_PP_CAT(arg, n)::proto_base_expr\
            >

        #define BOOST_PROTO_DEFINE_MATCHES(z, n, data)\
            matches_impl<\
                typename Expr::proto_base_expr\
              , typename BOOST_PP_CAT(G, n)::proto_base_expr\
            >

        #define BOOST_PROTO_DEFINE_LAMBDA_MATCHES(z, n, data)\
            lambda_matches<\
                BOOST_PP_CAT(Expr, n)\
              , BOOST_PP_CAT(Grammar, n)\
            >

        #if BOOST_PROTO_MAX_LOGICAL_ARITY > BOOST_PROTO_MAX_ARITY
            #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, BOOST_PROTO_MAX_LOGICAL_ARITY, <boost/xpressive/proto/matches.hpp>, 1))
        #else
            #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, BOOST_PROTO_MAX_ARITY, <boost/xpressive/proto/matches.hpp>, 1))
        #endif
        #include BOOST_PP_ITERATE()

        #define BOOST_PP_ITERATION_PARAMS_1 (4, (2, BOOST_PROTO_MAX_ARITY, <boost/xpressive/proto/matches.hpp>, 2))
        #include BOOST_PP_ITERATE()

        #undef BOOST_PROTO_MATCHES_N_FUN
        #undef BOOST_PROTO_DEFINE_MATCHES
        #undef BOOST_PROTO_DEFINE_LAMBDA_MATCHES

            // handle proto::if_
            template<typename Expr, typename Condition>
            struct matches_impl<Expr, if_<Condition> >
              : mpl::apply1<Condition, Expr>::type
            {};

            // handle proto::not_
            template<typename Expr, typename Grammar>
            struct matches_impl<Expr, not_<Grammar> >
              : mpl::not_<matches_impl<Expr, typename Grammar::proto_base_expr> >
            {};

            // handle proto::switch_
            template<typename Expr, typename Cases>
            struct matches_impl<Expr, switch_<Cases> >
              : matches_impl<
                    Expr
                  , typename Cases::template case_<typename Expr::proto_tag>::proto_base_expr
                >
            {};
        }

        namespace result_of
        {
            template<typename Expr, typename Grammar>
            struct matches
              : detail::matches_impl<typename Expr::proto_base_expr, typename Grammar::proto_base_expr>
            {};
        }

        namespace wildcardns_
        {
            struct _
              : has_identity_transform
            {
                typedef _ proto_base_expr;
                typedef void proto_is_wildcard_;
            };

            template<typename T>
            transform::detail::yes_type is_wildcard_expression_fun(T const *);
        }

        namespace control
        {
            // not_
            template<typename Grammar>
            struct not_
              : has_identity_transform
            {
                typedef not_ proto_base_expr;
            };

            // if_
            template<typename Condition, typename Then, typename Else>
            struct if_
              : or_<
                    and_<if_<Condition>, Then>
                  , and_<not_<if_<Condition> >, Else>
                >
            {};

            template<typename Condition, typename Then>
            struct if_<Condition, Then, void>
              : and_<if_<Condition>, Then>
            {};

            template<typename Condition>
            struct if_<Condition, void, void>
              : has_identity_transform
            {
                typedef if_ proto_base_expr;
            };

            // or_
            template<BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, typename G)>
            struct or_
            {
                typedef or_ proto_base_expr;

                template<typename Expr, typename State, typename Visitor>
                struct apply
                {
                    typedef typename detail::matches_impl<Expr, or_>::which which;
                    typedef typename which::template apply<Expr, State, Visitor>::type type;
                };

                template<typename Expr, typename State, typename Visitor>
                static typename apply<Expr, State, Visitor>::type
                call(Expr const &expr, State const &state, Visitor &visitor)
                {
                    typedef typename detail::matches_impl<Expr, or_>::which which;
                    return which::call(expr, state, visitor);
                }
            };

            // and_
            template<BOOST_PP_ENUM_PARAMS(BOOST_PROTO_MAX_LOGICAL_ARITY, typename G)>
            struct and_
            {
                typedef and_ proto_base_expr;

                template<typename Expr, typename State, typename Visitor>
                struct apply
                {
                    typedef typename detail::last<and_>::type which;
                    typedef typename which::template apply<Expr, State, Visitor>::type type;
                };

                template<typename Expr, typename State, typename Visitor>
                static typename apply<Expr, State, Visitor>::type
                call(Expr const &expr, State const &state, Visitor &visitor)
                {
                    typedef typename detail::last<and_>::type which;
                    return which::call(expr, state, visitor);
                }
            };

            // switch_
            template<typename Cases>
            struct switch_
            {
                typedef switch_ proto_base_expr;

                template<typename Expr, typename State, typename Visitor>
                struct apply
                  : Cases::template case_<typename Expr::proto_tag>::template apply<Expr, State, Visitor>
                {};

                template<typename Expr, typename State, typename Visitor>
                static typename apply<Expr, State, Visitor>::type
                call(Expr const &expr, State const &state, Visitor &visitor)
                {
                    return Cases::template case_<typename Expr::proto_tag>::call(expr, state, visitor);
                }
            };

            template<typename T>
            struct exact
            {};

            template<typename T>
            struct convertible_to
            {};

            template<typename Grammar>
            struct vararg
              : Grammar
            {
                typedef void proto_is_vararg_;
            };
        }
    }}

    #if defined(_MSC_VER) && (_MSC_VER >= 1020)
    # pragma warning(pop)
    #endif

    #endif

#elif BOOST_PP_ITERATION_FLAGS() == 1

    #define N BOOST_PP_ITERATION()

            template<bool B, BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(N), typename P)>
            struct BOOST_PP_CAT(and, N)
              : BOOST_PP_CAT(and, BOOST_PP_DEC(N))<
                    P0::value BOOST_PP_COMMA_IF(BOOST_PP_SUB(N,2))
                    BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_DEC(N), P)
                >
            {};

            template<BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(N), typename P)>
            struct BOOST_PP_CAT(and, N)<false, BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(N), P)>
              : mpl::false_
            {};

        #if N <= BOOST_PROTO_MAX_LOGICAL_ARITY
            template<BOOST_PP_ENUM_PARAMS(N, typename G)>
            struct last<proto::and_<BOOST_PP_ENUM_PARAMS(N, G)> >
            {
                typedef BOOST_PP_CAT(G, BOOST_PP_DEC(N)) type;
            };

            template<bool B, typename Expr, BOOST_PP_ENUM_PARAMS(N, typename G)>
            struct BOOST_PP_CAT(or, N)
              : BOOST_PP_CAT(or, BOOST_PP_DEC(N))<
                    matches_impl<Expr, typename G1::proto_base_expr>::value
                  , Expr, BOOST_PP_ENUM_SHIFTED_PARAMS(N, G)
                >
            {};

            template<typename Expr BOOST_PP_ENUM_TRAILING_PARAMS(N, typename G)>
            struct BOOST_PP_CAT(or, N)<true, Expr, BOOST_PP_ENUM_PARAMS(N, G)>
              : mpl::true_
            {
                typedef G0 which;
            };

            // handle proto::or_
            template<typename Expr, BOOST_PP_ENUM_PARAMS(N, typename G)>
            struct matches_impl<Expr, proto::or_<BOOST_PP_ENUM_PARAMS(N, G)> >
              : BOOST_PP_CAT(or, N)<
                    matches_impl<typename Expr::proto_base_expr, typename G0::proto_base_expr>::value,
                    typename Expr::proto_base_expr, BOOST_PP_ENUM_PARAMS(N, G)
                >
            {};

            // handle proto::and_
            template<typename Expr, BOOST_PP_ENUM_PARAMS(N, typename G)>
            struct matches_impl<Expr, proto::and_<BOOST_PP_ENUM_PARAMS(N, G)> >
              : detail::BOOST_PP_CAT(and, N)<
                    BOOST_PROTO_DEFINE_MATCHES(~, 0, ~)::value,
                    BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_DEFINE_MATCHES, ~)
                >
            {};
        #endif

    #undef N

#elif BOOST_PP_ITERATION_FLAGS() == 2

    #define N BOOST_PP_ITERATION()

            template<typename Args, typename Back, long To>
            struct vararg_matches_impl<Args, Back, N, To>
              : and2<
                    matches_impl<typename Args::BOOST_PP_CAT(arg, BOOST_PP_DEC(N))::proto_base_expr, Back>::value
                  , vararg_matches_impl<Args, Back, N + 1, To>
                >
            {};

            template<typename Args, typename Back>
            struct vararg_matches_impl<Args, Back, N, N>
              : matches_impl<typename Args::BOOST_PP_CAT(arg, BOOST_PP_DEC(N))::proto_base_expr, Back>
            {};

            template<
                template<BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT)> class T
                BOOST_PP_ENUM_TRAILING_PARAMS(N, typename Expr)
                BOOST_PP_ENUM_TRAILING_PARAMS(N, typename Grammar)
            >
            struct lambda_matches<T<BOOST_PP_ENUM_PARAMS(N, Expr)>, T<BOOST_PP_ENUM_PARAMS(N, Grammar)> BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(N) >
              : BOOST_PP_CAT(and, N)<
                    BOOST_PROTO_DEFINE_LAMBDA_MATCHES(~, 0, ~)::value,
                    BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_DEFINE_LAMBDA_MATCHES, ~)
                >
            {};

            template<typename Tag, typename Args1, typename Args2>
            struct matches_impl< expr<Tag, Args1, N>, expr<Tag, Args2, N> >
              : BOOST_PP_CAT(and, N)<
                    BOOST_PROTO_MATCHES_N_FUN(~, 0, ~)::value,
                    BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_MATCHES_N_FUN, ~)
                >
            {};

            template<typename Tag, typename Args1, typename Args2>
            struct matches_impl< expr<Tag, Args1, N>, expr<proto::_, Args2, N> >
              : BOOST_PP_CAT(and, N)<
                    BOOST_PROTO_MATCHES_N_FUN(~, 0, ~)::value,
                    BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_MATCHES_N_FUN, ~)
                >
            {};

    #undef N

#endif

ext: hpp


text:
#include <net/if.h>
#include <boost/scoped_array.hpp>

#include "TLV.hh"
#include "endian.hh"

// Most Significant Bit in the type field indicates the type is optional.
#define OPTIONAL_MASK (1 << 7)

/**
 * Makes a deep copy of the given TLV.
 */
TLV::TLV(const TLV& other) {
    this->init(other.getType(), other.getLength(), other.getValue());
}

/**
 * Constructs a new TLV object by storing the given shared_array.
 */
TLV::TLV(uint8_t type, size_t len, boost::shared_array<uint8_t> value) {
    this->init(type, len, value);
}

/**
 * Constructs a new TLV object by copying the value from the given pointer.
 */
TLV::TLV(uint8_t type, size_t len, const uint8_t* value) {
    this->init(type, len, value);
}

TLV::TLV(uint8_t type, size_t len, uint8_t value) {
    this->init(type, len, reinterpret_cast<uint8_t*>(&value));
}

TLV::TLV(uint8_t type, size_t len, uint16_t value) {
    this->init(type, len, reinterpret_cast<uint8_t*>(&value));
}

TLV::TLV(uint8_t type, size_t len, uint32_t value) {
    this->init(type, len, reinterpret_cast<uint8_t*>(&value));
}

TLV::TLV(uint8_t type, size_t len, uint64_t value) {
    this->init(type, len, reinterpret_cast<uint8_t*>(&value));
}

TLV::TLV(uint8_t type, const MACAddress& addr) {
    boost::shared_array<uint8_t> buf(new uint8_t[IFHWADDRLEN]);
    addr.toArray(buf.get());
    init(type, IFHWADDRLEN, buf);
}

TLV::TLV(uint8_t type, const IPAddress& addr, const IPAddress& mask) {
    boost::shared_array<uint8_t> buf;
    uint8_t *buf_mask = NULL;
    size_t length;

    if (addr.getVersion() == IPV6) {
        length = sizeof(ip6_match);
        buf.reset(new uint8_t[length]);
        buf_mask = buf.get() + (length / 2);
    } else if (addr.getVersion() == IPV4) {
        length = sizeof(ip_match);
        buf.reset(new uint8_t[length]);
        buf_mask = buf.get() + (length / 2);
    } else {
        throw "Invalid IP version";
    }

    addr.toArray(buf.get());
    mask.toArray(buf_mask);

    init(type, length, buf);
}

TLV& TLV::operator=(const TLV& other) {
    if (this != &other) {
        this->init(other.getType(), other.getLength(), other.getValue());
    }
    return *this;
}

bool TLV::operator==(const TLV& other) {
    return (this->getType() == other.getType() and
            (memcmp(other.getValue(), this->getValue(), this->length) == 0));
}

uint8_t TLV::getType() const {
    return this->type;
}

uint8_t TLV::getUint8() const {
    if (this->getLength() < sizeof(uint8_t)) {
        return 0;
    }
    return *reinterpret_cast<const uint8_t*>(this->getValue());
}

uint16_t TLV::getUint16() const {
    if (this->getLength() < sizeof(uint16_t)) {
        return 0;
    }
    return *reinterpret_cast<const uint16_t*>(this->getValue());
}

uint32_t TLV::getUint32() const {
    if (this->getLength() < sizeof(uint32_t)) {
        return 0;
    }
    return *reinterpret_cast<const uint32_t*>(this->getValue());
}

uint64_t TLV::getUint64() const {
    if (this->getLength() < sizeof(uint64_t)) {
        return 0;
    }
    return *reinterpret_cast<const uint64_t*>(this->getValue());
}

size_t TLV::getLength() const {
    return this->length;
}

const uint8_t* TLV::getValue() const {
    return this->value.get();
}

/**
 * Returns the IP address held internally, in network byte-order.
 */
const void* TLV::getIPAddress() const {
    return this->getValue();
}

/**
 * Returns the IP mask held internally, in network byte-order.
 */
const void* TLV::getIPMask() const {
    if (this->length == sizeof(ip_match)) {
        return &reinterpret_cast<const ip_match*>(this->getValue())->mask;
    } else if (this->length == sizeof(ip6_match)) {
        return &reinterpret_cast<const ip6_match*>(this->getValue())->mask;
    }
    return NULL;
}

mongo::BSONObj TLV::to_BSON() const {
    return TLV_to_BSON(this, ORDER_HOST);
}

/**
 * Serialises the TLV object to BSON in the following format:
 * {
 *   "type": (int),
 *   "value": (binary)
 * }
 *
 * Where "value" is converted from "byte_order" to network byte-order.
 */
mongo::BSONObj TLV::TLV_to_BSON(const TLV* tlv, byte_order order) {
    const uint8_t* value = tlv->getValue();

    boost::scoped_array<uint8_t> arr(new uint8_t[tlv->length]);
    if (order == ORDER_HOST) {
        switch (tlv->length) {
            case sizeof(uint16_t): {
                uint16_t new_val = htons(tlv->getUint16());
                memcpy(arr.get(), &new_val, tlv->length);
                value = arr.get();
                break;
            }
            case sizeof(uint32_t): {
                uint32_t new_val = htonl(tlv->getUint32());
                memcpy(arr.get(), &new_val, tlv->length);
                value = arr.get();
                break;
            }
            case sizeof(uint64_t): {
                uint64_t new_val = htonll(tlv->getUint64());
                memcpy(arr.get(), &new_val, tlv->length);
                value = arr.get();
                break;
            }
            default:
                break;
        }
    }

    mongo::BSONObjBuilder builder;
    builder.append("type", tlv->type);
    builder.appendBinData("value", tlv->length, mongo::BinDataGeneral, value);

    return builder.obj();
}

uint8_t TLV::type_from_BSON(mongo::BSONObj bson) {
    const mongo::BSONElement& btype = bson["type"];

    if (btype.type() != mongo::NumberInt)
        return 0;

    return static_cast<uint8_t>(btype.Int());
}

boost::shared_array<uint8_t> TLV::value_from_BSON(mongo::BSONObj bson,
                                                  byte_order order) {
    boost::shared_array<uint8_t> arr;

    const mongo::BSONElement& bvalue = bson["value"];
    if (bvalue.type() != mongo::BinData)
        return arr;

    int len = bvalue.valuesize();
    const uint8_t* value = reinterpret_cast<const uint8_t*>
                           (bvalue.binData(len));

    arr.reset(new uint8_t[len]);
    if (order == ORDER_HOST) {
        switch (len) {
            case sizeof(uint16_t): {
                uint16_t new_val = ntohs(*reinterpret_cast<const uint16_t*>
                                        (value));
                memcpy(arr.get(), &new_val, len);
                break;
            }
            case sizeof(uint32_t): {
                uint32_t new_val = ntohl(*reinterpret_cast<const uint32_t*>
                                        (value));
                memcpy(arr.get(), &new_val, len);
                break;
            }
            case sizeof(uint64_t): {
                uint64_t new_val = ntohll(*reinterpret_cast<const uint64_t*>
                                         (value));
                memcpy(arr.get(), &new_val, len);
                break;
            }
            default:
                memcpy(arr.get(), value, len);
                break;
        }
    } else {
        memcpy(arr.get(), value, len);
    }

    return arr;
}

std::string TLV::toString() const {
    boost::scoped_array<char> buf(new char[this->length]);
    snprintf(buf.get(), this->length, "%*s", static_cast<int>(this->length),
             this->value.get());

    std::stringstream ss;
    ss << "{\"type\": " << this->type_to_string() << ", \"value\":\"";
    ss.write(buf.get(), this->length);
    ss << "\"}";

    return ss.str();
}

std::string TLV::type_to_string() const {
    std::stringstream ss;
    ss << this->type;
    return ss.str();
}

bool TLV::optional() const {
    if (this->type & OPTIONAL_MASK) {
        return true;
    }
    return false;
}

void TLV::init(uint8_t type, size_t len, const uint8_t* value) {
    boost::shared_array<uint8_t> arr(new uint8_t[len]);
    memcpy(arr.get(), value, len);
    this->init(type, len, arr);
}

void TLV::init(uint8_t type, size_t len, boost::shared_array<uint8_t> value) {
    this->type = type;
    this->length = 0;

    if (len == 0 || value.get() == NULL) {
        return;
    }

    this->value = value;
    this->length = len;
}

ext: cc


text:
// TODO
// Timeout message to indicate not found.

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <pthread.h>
#include <std_msgs/String.h>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "KaimiMidField.h"

boost::asio::io_service KaimiMidFieldIoService_;
boost::asio::deadline_timer KaimiMidFieldDeadlineTimer_(KaimiMidFieldIoService_, boost::posix_time::milliseconds(500));

static void * KaimiMidFieldFindObjectTimerRoutine(const boost::system::error_code& /*e*/) {
	ptime now = microsec_clock::local_time();
	time_duration timeSinceLastFound = now - KaimiMidField::Singleton().lastTimeFound();
	long millisecondsSinceLastReport = (long) timeSinceLastFound.total_milliseconds();
	if (millisecondsSinceLastReport > 100) {
		//ROS_INFO("[KaimiMidFieldFindObjectTimerRoutine] no object found in last 500 ms");
		KaimiMidField::Singleton().setNotFound();
	}

	KaimiMidFieldDeadlineTimer_.expires_at(KaimiMidFieldDeadlineTimer_.expires_at() + milliseconds(100));
	KaimiMidFieldDeadlineTimer_.async_wait(KaimiMidFieldFindObjectTimerRoutine);
}

void* kaimiMidFieldHeartBeatFunction(void* singleton) {
    KaimiMidFieldDeadlineTimer_.async_wait(KaimiMidFieldFindObjectTimerRoutine);
    KaimiMidFieldIoService_.run();
}

// void FindObject::configurationCallback(kaimi_mid_camera::kaimi_mid_camera_paramsConfig &config, uint32_t level) {
// 	ROS_INFO("Reconfigure Request hue_low: %d, hue_high: %d, saturation_low: %d, saturation high: %d, value_low: %d, value_high: %d, contourSizeThreshold: %d",
// 	         config.hue_low, config.hue_low,
// 	         config.saturation_low, config.saturation_high,
// 	         config.value_low, config.value_high,
// 	         config.contourSizeThreshold);
// 	//setTrackbarPos("LowV", "Control", 13/*config.value_low*/);
// 	if (findObject) {
// 		findObject->iLowH = config.hue_low;
// 		findObject->iHighH = config.hue_high;
// 		findObject->iLowS = config.saturation_low;
// 		findObject->iHighS = config.saturation_high;
// 		findObject->iLowV = config.value_low;
// 		findObject->iHighV = config.value_high;
// 		findObject->contourSizeThreshold = config.contourSizeThreshold;
// 	}
// }

void KaimiMidField::topicCb(const std_msgs::String& msg) {
	// MidCamera:found;X:313.49;Y:408.196;AREA:3201;I:0;ROWS:480;COLS:640
	//ROS_INFO("[KaimiMidField::topicCb] Message: %s", msg.data.c_str());

	char localStr[strlen(msg.data.c_str()) + 1];
	strcpy(localStr, msg.data.c_str());

	char* keyValPtr = strtok(localStr, ";");
	while (keyValPtr != NULL) {
		// Found key/value pair.
		char keyValue[strlen(keyValPtr) + 1];
		strcpy(keyValue, keyValPtr);

		char* keyPtr = keyValue;
		while ((*keyPtr) && (*keyPtr != ':')) keyPtr++;
		if (*keyPtr) {
			*keyPtr = '\0';
			char key[keyPtr - keyValue];
			keyPtr++;
			strcpy(key, keyValue);
			char* value = keyPtr;
			if (strcmp(key, "Found") == 0) {
				if (strcmp(value, "Found")) {
					setFound();
				} else {
					setNotFound();
				}
			} else if (strcmp(key, "MidCamera") == 0) {
				if (strcmp(value, "Found") == 0) {
					found_ = true;
					lastFieldReport_ = microsec_clock::local_time();
				} else {
					found_ = false;
				}
			} else if (strcmp(key, "AREA") == 0) {
				area_ = atof(value);
			} else if (strcmp(key, "X") == 0) {
				x_ = atof(value);
			} else if (strcmp(key, "Y") == 0) {
				y_ = atof(value);
			} else if (strcmp(key, "COLS") == 0) {
				cols_ = atol(value);
			} else if (strcmp(key, "ROWS") == 0) {
				rows_ = atol(value);
			}
		} else {
			ROS_INFO("[KaimiMidField::topicCb] !!! missing value");
		}

		keyValPtr = strtok(NULL, ";");
	}
}

KaimiMidField::KaimiMidField() {
	ros::param::param<std::string>("midfield_topic_name", midfieldTopicName_, "/midSampleFound");
	ROS_INFO("PARAM midield_topic_name: %s", midfieldTopicName_.c_str());
	midfield_sub_ = nh_.subscribe(midfieldTopicName_.c_str(), 1, &KaimiMidField::topicCb, this);

	pthread_t thread;
	int rc = pthread_create(&thread, NULL, kaimiMidFieldHeartBeatFunction, this);

	area_ = 0.0;
	cols_ = 0;
	found_ = false;
	rows_ = 0;
	x_ = 0.0;
	y_ = 0.0;
}

KaimiMidField& KaimiMidField::Singleton() {
	static KaimiMidField singleton_;
	return singleton_;
}

max_stars_repo_name: mwimble/kaimiPi

max_issues_repo_name: mwimble/kaimiPi

max_forks_repo_name: mwimble/kaimiPi